<commit_before><!--

TODO
* Make page available without login
* Get a way to capture people's emails
*
-->



<script type="text/javascript" src="/static/dropfile.js"></script>

<div class="container-fluid" id="bulk" style="display:none;">
  <div class="row">
    <div class="col-md-8 col-md-offset-2">

<!-- Headline & 1 liner -->

      <div>

<h1 style="text-align:center;">DeliverOA</h1>
<h3 style="text-align:center;">Give us a spreadsheet of articles, we'll email you which can be found Open Access</h3>

      </div>

      <!-- End of intro -->

<!-- This is where you login or sign up-->

<div id="cloginEmailArea">
  <p style="text-align:center;">
    Just enter your email address to get started. We'll email you your results.<br>
  </p>
  <input type="email" class="form-control" id="cloginEmail" name="email" placeholder="Enter your email address">
  <button id="cloginSubmit" type="submit" class="btn btn-action btn-block" style="margin-top:10px;">Submit</button>
</div>

<!-- end of login -->

<!-- Start of upload button & instructions. This should be shown only when logged in. -->

      <div id="upload">
        <p class="jobupload">Upload a csv file, which must have column names including at least one of "url", "doi", "pmid", "pmcid", "title".</p>
        <form>
          <input type="file" name="jobupload" id="jobupload" class="form-control" style="padding-bottom:30px;margin-bottom:5px;">
  				<div style="display:none;" id="jobinfo">Uploading, for large files this can take a minute</div>
        </form>
      </div>

<!-- end of upload button & instructions -->

<!-- Start of places to read more. This should always be shown.  -->

  <div class="row">
    <div class="col-md-4" style="text-align:center;">
      <a href="#" class="show" what="examples" style="text-decoration:underline;">Help</a>
    </div>
    <div class="col-md-4" style="text-align:center;">
      <a href="#" class="show" what="examples" style="text-decoration:underline;">Example</a>
    </div>
    <div class="col-md-4" style="text-align:center;">
      <a href="#" class="show" what="howitworks" style="text-decoration:underline;">FAQ</a>
    </div>
  </div>
<!-- End of places to read more -->

    </div>
  </div>
</div>




<script>
  jQuery(document).ready(function() {
    if (!clogin.loggedin()) {
      window.location = '/account?next=/bulk';
    }

    var api = 'https://api.openaccessbutton.org';
    if (window.location.host.indexOf('openaccessbutton.org') === -1 || window.location.host.indexOf('dev.openaccessbutton.org') !== -1) {
      api = 'https://dev.api.cottagelabs.com/service/oab';
      clogin.api = 'https://dev.api.cottagelabs.com/accounts';
    }

    var createrequests = function(e) {
      e.preventDefault();
      $('#jobinfo').html('<p>Checking job status...</p>').show();
      var uid = $(this).attr('href');
      $.ajax({
        url: api + '/job/' + uid + '/results',
        success: function(data) {
          $('#jobinfo').html('');
          var count = 0;
          for ( var r in data ) {
            if (data[r].availability.length === 0 && data[r].requests.length === 0 && ( ( data[r].match.indexOf('TITLE:') === -1 && data[r].match.indexOf('CITATION:') === -1 ) || ( data[r].meta && data[r].meta.article && data[r].meta.article.doi ) ) ) count += 1;
          }
          var confirmed = confirm('Are you sure you want to try to create ' + count + ' requests from this job? Requests will only be created for records that are unavailable and for which there are not already requests, and where at least a url or doi was provided or found during checking - title alone is not enough. This count estimate is based on how many it seems at least a url or doi is available for, and for which there was not already a request at the time the job was run (if a request has since been created, it should be matched and not duplicated, but will still be counted). The actual created number will be confirmed after you submit.)');
          if (confirmed) {
            $('html,body').scrollTop(0);
            $('#jobinfo').html('Creating requests from job ' + uid + '...');
            $.ajax({
              url: api + '/job/' + uid + '/request?apikey=' + clogin.apikey,
              success: function(res) {
                $('#jobinfo').html('<p>' + res.length + ' requests created</p>');
                for ( var rid in res ) $('#jobinfo').append('<p><a target="_blank" href="/request/' + res[rid]._id + '">' + res[rid]._id + '</a></p>');
              }
            });
          }
        }
      });
    }

    var checkprogress = function(e) {
      e.preventDefault();
      var uid = $(this).attr('href');
      var u = api + '/job/' + uid + '/progress';
		  $('.checkprogress[href="' + uid + '"]').html('Checking...');
   		$.ajax({
  			url: u,
  			method: 'GET',
  			success: function(data) {
  			  $('.checkprogress[href="' + uid + '"]').html(data.progress.toFixed(2) + '%');
  			}
			});
    }

    var removejob = function(e) {
      e.preventDefault();
      var confirmed = confirm('Are you sure you want to delete this job?');
      if (confirmed) {
        var uid = $(this).attr('href');
        var u = api + '/job/' + uid + '/remove?apikey=' + clogin.apikey;
     		$.ajax({
    			url: u,
    			method: 'GET',
    			success: function(data) {
    			  $('.job'+uid).remove();
    			}
  			});
			}
    }

		var getJobs = function(e) {
			$.ajax({
				url: api + '/job?apikey='+clogin.apikey,
				method: 'GET',
				contentType: "application/json; charset=utf-8",
				success: function(data) {
					var jh = '';
					for ( var j in data ) {
						var job = data[j];
		        jh += '<p class="job' + job._id + '">' + job.created_date + ': ' + job.name + ' (ID #' + job._id + ') ' + job.processes + ' rows. ';
		        jh += job.done ? '<span style="color:orange;">Complete</span>' : '<a class="checkprogress" href="' + job._id + '">Check progress</a>';
		        jh += ' - get <a target="_blank" href="' + api + '/job/' + job._id + '/results.json">JSON</a> or <a href="' + api + '/job/' + job._id + '/results.csv">CSV</a> ';
						jh += '- or <a class="createrequests" href="' + job._id + '">Request</a> ';
						jh += '- <a class="removejob" href="' + job._id + '" style="color:red;">x</a></p>';
					}
					$('#jobinfo').hide();
					$('#jobhistory').html(jh);
					$('.checkprogress').bind('click',checkprogress);
					$('.removejob').bind('click',removejob);
					$('.createrequests').bind('click',createrequests);
				}
			});
		}

    var start = moment().startOf('isoWeek');
    var today = moment().endOf('day');
    $('#batchfrom').val(moment(start,"x").format("DDMMYYYY"));
    $('#batchto').val(moment(today,"x").format("DDMMYYYY"));
    var generatebatch = function(e) {
      e.preventDefault();
      var from = $('#batchfrom').val();
      var to = $('#batchto').val();
			$.ajax({
				url: api + '/job/generate/' + from + '/' + to + '?apikey='+clogin.apikey,
				method: 'POST',
				success: function(data) {
				  if (data.count) {
				    $('#jobinfo').show().html('<p>Job added, with ' + data.count + ' rows. Refresh the page to update job list.</p>');
				  } else {
				    $('#jobinfo').show().html('<p>There are no open requests between these dates. No job created.</p>');
				  }
				},
				error: function() { $('#jobinfo').show().html('<p>Sorry, there was an error creating this job.</p>'); }
			});
    }
    $('#generatebatch').bind('click',generatebatch);

		var identifiers = [];
		var file, filename;

		var submitJob = function(e) {
			identifiers = [];
			var split = ',';
			var wrap = '"';
			var wrapreplace = new RegExp(wrap,"g");

			file = file.replace(/\r\n/g,'\n'); // switch MS line breaks to unix
			file = file.replace(/\n{2,}/g,'\n'); // get rid of any blank lines
			file = file.replace(/\n*$/g,''); // remove newlines at end of file

			var lines = [];
			var fls = file.split('\n');
			var il = '';
			for ( var f in fls ) {
				il += fls[f];
				if ( il.split(wrap).length % 2 !== 0 ) {
					lines.push(il);
					il = '';
				}
			}
			var headers = [];
			var hline = lines.shift();
			var hlines = hline.split(split);
			var hl = '';
			for ( var h in hlines ) {
				if (hl.length > 0) hl += ',';
				hl += hlines[h];
				if ( hl.split(wrap).length % 2 !== 0 ) {
					hl = hl.replace(wrapreplace,'').replace(/(^\s*)|(\s*$)/g,'');
					headers.push(hl.toLowerCase());
					hl = '';
				}
			}

			for (var i = 0; i < lines.length; i++) {
				var obj = {};
				var currentline = lines[i].split(split);
				var cl = '';
				var counter = 0;
				var lengths = 0;
				for ( var col in currentline ) {
					if (cl.length > 0) cl += ',';
					cl += currentline[col];
					if ( cl.split(wrap).length % 2 !== 0 ) {
						cl = cl.replace(wrapreplace,'');
						if (headers[counter] && headers[counter].length > 0) obj[headers[counter]] = cl;
						if (lengths === 0) lengths = cl.length;
						cl = '';
						counter += 1;
					}
				}
				if (lengths) identifiers.push(obj);
			}

			var payload = {processes:identifiers,name:filename};
			if ( $('.bulklibraries:checked').length ) {
			  payload.libraries = [];
			  $('.bulklibraries:checked').each(function() {
			    payload.libraries.push($(this).val());
			  });
			}
			$.ajax({
				url: api + '/job?apikey='+clogin.apikey,
				method: 'POST',
				data: JSON.stringify(payload),
				dataType: 'JSON', // TODO sort issue here, the POST invalidates preflight without jsonp but with jsonp we don't get back a jsonp object
				contentType: "application/json; charset=utf-8",
				success: function() { $('#jobinfo').html('<p>Job accepted! We will email you the results when they are ready. </p>'); },
				error: function() { $('#jobinfo').html('<p>Sorry, this job could not be uploaded. Contact <EMAIL></p>'); }
			});
		}

		var uploadJob = function(e) {
			$('#jobinfo').html('Uploading...').show();
			var f;
			if( window.FormData === undefined ) {
				f = (e.files || e.dataTransfer.files);
			} else {
				f = e.target.files[0];
			}
			filename = f.name;
			var reader = new FileReader();
			reader.onload = (function(theFile) {
				return function(e) {
					file = e.target.result;
					submitJob();
				};
			})(f);
			reader.readAsBinaryString(f);
		}

		$('input[type=file]').on('change', uploadJob);

    clogin.afterLogin = function() {
      if (clogin.hasRole('openaccessbutton.admin')) {
				getJobs();
        $('#bulk').show();
      } else {
        window.location = '/';
      }
    }
		clogin.afterFailure = function() { window.location = '/account?next=/bulk'; };
    clogin.login();
  });
</script>
<commit_msg>trying out quick tabs<commit_after><!--

TODO
* Make page available without login
* Get a way to capture people's emails
*
-->
<style>
    div:not(:target) {
      display: none;
    }

    div:target {
      display: block;
    }

    /* Make the div big, so we would jump, if the JS was still broken */
    div {
      height: 100vh;
    }
  </style>


<script type="text/javascript" src="/static/dropfile.js"></script>

<div class="container-fluid" id="bulk" style="display:none;">
  <div class="row">
    <div class="col-md-8 col-md-offset-2">

<!-- Headline & 1 liner -->

      <div>

<h1 style="text-align:center;">DeliverOA</h1>
<h3 style="text-align:center;">Give us a spreadsheet of articles, we'll email you which can be found Open Access</h3>

      </div>

      <!-- End of intro -->

<!-- This is where you login or sign up-->

<div id="cloginEmailArea">
  <p style="text-align:center;">
    Just enter your email address to get started. We'll email you your results.<br>
  </p>
  <input type="email" class="form-control" id="cloginEmail" name="email" placeholder="Enter your email address">
  <button id="cloginSubmit" type="submit" class="btn btn-action btn-block" style="margin-top:10px;">Submit</button>
</div>

<!-- end of login -->

<!-- Start of upload button & instructions. This should be shown only when logged in. -->

      <div id="upload">
        <p class="jobupload">Upload a csv file, which must have column names including at least one of "url", "doi", "pmid", "pmcid", "title".</p>
        <form>
          <input type="file" name="jobupload" id="jobupload" class="form-control" style="padding-bottom:30px;margin-bottom:5px;">
  				<div style="display:none;" id="jobinfo">Uploading, for large files this can take a minute</div>
        </form>
      </div>

<!-- end of upload button & instructions -->

<!-- Start of places to read more. This should always be shown.  -->

  <div class="row">
    <div class="col-md-4" style="text-align:center;">
      <a href="#tab-1" style="text-decoration:underline;">Help</a>
    </div>
    <div class="col-md-4" style="text-align:center;">
      <a href="#tab-2" style="text-decoration:underline;">Example</a>
    </div>
    <div class="col-md-4" style="text-align:center;">
      <a href="#" class="show" what="howitworks" style="text-decoration:underline;">FAQ</a>
    </div>
  </div>
<!-- End of places to read more -->

    </div>
  </div>


  <div id="tab-1">
    <div class="container-fluid">
      <div class="row">
        <div class="col-md-8 col-md-offset-2" style="text-align:justify;">

    <h1 style="text-align:left;margin-top:25px;margin-bottom:25px;font-size:4em;">Firefox Install Instructions</h1>

    <ol>
    <li> Make sure your bookmarks toolbar is showing. If not, you can <a href="https://support.mozilla.org/en-US/kb/bookmarklets-perform-common-web-page-tasks#w_how-do-i-install-a-bookmarklet">right-click on an empty space in the tabs bar</a>, and select "Bookmarks Toolbar."</li>
    <li> Drag the Button to your bookmarks toolbar.</li>
    <img src = "/static/bookmarklet_install_ff.gif" style = "width: 100%;border:1px solid #212f3f;margin:10px;" >
    <li> If there is a pop-up, click yes.</li>
    <li> You're done! The Button is ready to click when you next need it.</li>
    </ol>

    <h3>If that doesn't work:</h3>
    <ol>
    <li> Right click on the Button.</li>
    <li> Click "Bookmark this link."</li>
    <li> Choose "Bookmarks Toolbar" as the folder.</li>
    <img src = "/static/bookmarklet_install_ff_right-click.gif" style = "width: 100%;border:1px solid #212f3f;margin:10px;">
    <li> Click "Save."</li>
    <li> You're done! The Button is ready to click when you next need it.</li>
    </ol>
        </div>
      </div>
    </div>
  </div>

  <div id="tab-2">
    Tab two contents
  </div>

  <script>
  // Stop href="#hashtarget" links jumping around the page
  var hashLinks = document.querySelectorAll("a[href^='#']");
  [].forEach.call(hashLinks, function (link) {
    link.addEventListener("click", function (event) {
      event.preventDefault();
      history.pushState({}, "", link.href);
      history.pushState({}, "", link.href);
      history.back();
    });
  });
  </script>
  </body>


</div>




<script>
  jQuery(document).ready(function() {
    if (!clogin.loggedin()) {
      window.location = '/account?next=/bulk';
    }

    var api = 'https://api.openaccessbutton.org';
    if (window.location.host.indexOf('openaccessbutton.org') === -1 || window.location.host.indexOf('dev.openaccessbutton.org') !== -1) {
      api = 'https://dev.api.cottagelabs.com/service/oab';
      clogin.api = 'https://dev.api.cottagelabs.com/accounts';
    }

    var createrequests = function(e) {
      e.preventDefault();
      $('#jobinfo').html('<p>Checking job status...</p>').show();
      var uid = $(this).attr('href');
      $.ajax({
        url: api + '/job/' + uid + '/results',
        success: function(data) {
          $('#jobinfo').html('');
          var count = 0;
          for ( var r in data ) {
            if (data[r].availability.length === 0 && data[r].requests.length === 0 && ( ( data[r].match.indexOf('TITLE:') === -1 && data[r].match.indexOf('CITATION:') === -1 ) || ( data[r].meta && data[r].meta.article && data[r].meta.article.doi ) ) ) count += 1;
          }
          var confirmed = confirm('Are you sure you want to try to create ' + count + ' requests from this job? Requests will only be created for records that are unavailable and for which there are not already requests, and where at least a url or doi was provided or found during checking - title alone is not enough. This count estimate is based on how many it seems at least a url or doi is available for, and for which there was not already a request at the time the job was run (if a request has since been created, it should be matched and not duplicated, but will still be counted). The actual created number will be confirmed after you submit.)');
          if (confirmed) {
            $('html,body').scrollTop(0);
            $('#jobinfo').html('Creating requests from job ' + uid + '...');
            $.ajax({
              url: api + '/job/' + uid + '/request?apikey=' + clogin.apikey,
              success: function(res) {
                $('#jobinfo').html('<p>' + res.length + ' requests created</p>');
                for ( var rid in res ) $('#jobinfo').append('<p><a target="_blank" href="/request/' + res[rid]._id + '">' + res[rid]._id + '</a></p>');
              }
            });
          }
        }
      });
    }

    var checkprogress = function(e) {
      e.preventDefault();
      var uid = $(this).attr('href');
      var u = api + '/job/' + uid + '/progress';
		  $('.checkprogress[href="' + uid + '"]').html('Checking...');
   		$.ajax({
  			url: u,
  			method: 'GET',
  			success: function(data) {
  			  $('.checkprogress[href="' + uid + '"]').html(data.progress.toFixed(2) + '%');
  			}
			});
    }

    var removejob = function(e) {
      e.preventDefault();
      var confirmed = confirm('Are you sure you want to delete this job?');
      if (confirmed) {
        var uid = $(this).attr('href');
        var u = api + '/job/' + uid + '/remove?apikey=' + clogin.apikey;
     		$.ajax({
    			url: u,
    			method: 'GET',
    			success: function(data) {
    			  $('.job'+uid).remove();
    			}
  			});
			}
    }

		var getJobs = function(e) {
			$.ajax({
				url: api + '/job?apikey='+clogin.apikey,
				method: 'GET',
				contentType: "application/json; charset=utf-8",
				success: function(data) {
					var jh = '';
					for ( var j in data ) {
						var job = data[j];
		        jh += '<p class="job' + job._id + '">' + job.created_date + ': ' + job.name + ' (ID #' + job._id + ') ' + job.processes + ' rows. ';
		        jh += job.done ? '<span style="color:orange;">Complete</span>' : '<a class="checkprogress" href="' + job._id + '">Check progress</a>';
		        jh += ' - get <a target="_blank" href="' + api + '/job/' + job._id + '/results.json">JSON</a> or <a href="' + api + '/job/' + job._id + '/results.csv">CSV</a> ';
						jh += '- or <a class="createrequests" href="' + job._id + '">Request</a> ';
						jh += '- <a class="removejob" href="' + job._id + '" style="color:red;">x</a></p>';
					}
					$('#jobinfo').hide();
					$('#jobhistory').html(jh);
					$('.checkprogress').bind('click',checkprogress);
					$('.removejob').bind('click',removejob);
					$('.createrequests').bind('click',createrequests);
				}
			});
		}

    var start = moment().startOf('isoWeek');
    var today = moment().endOf('day');
    $('#batchfrom').val(moment(start,"x").format("DDMMYYYY"));
    $('#batchto').val(moment(today,"x").format("DDMMYYYY"));
    var generatebatch = function(e) {
      e.preventDefault();
      var from = $('#batchfrom').val();
      var to = $('#batchto').val();
			$.ajax({
				url: api + '/job/generate/' + from + '/' + to + '?apikey='+clogin.apikey,
				method: 'POST',
				success: function(data) {
				  if (data.count) {
				    $('#jobinfo').show().html('<p>Job added, with ' + data.count + ' rows. Refresh the page to update job list.</p>');
				  } else {
				    $('#jobinfo').show().html('<p>There are no open requests between these dates. No job created.</p>');
				  }
				},
				error: function() { $('#jobinfo').show().html('<p>Sorry, there was an error creating this job.</p>'); }
			});
    }
    $('#generatebatch').bind('click',generatebatch);

		var identifiers = [];
		var file, filename;

		var submitJob = function(e) {
			identifiers = [];
			var split = ',';
			var wrap = '"';
			var wrapreplace = new RegExp(wrap,"g");

			file = file.replace(/\r\n/g,'\n'); // switch MS line breaks to unix
			file = file.replace(/\n{2,}/g,'\n'); // get rid of any blank lines
			file = file.replace(/\n*$/g,''); // remove newlines at end of file

			var lines = [];
			var fls = file.split('\n');
			var il = '';
			for ( var f in fls ) {
				il += fls[f];
				if ( il.split(wrap).length % 2 !== 0 ) {
					lines.push(il);
					il = '';
				}
			}
			var headers = [];
			var hline = lines.shift();
			var hlines = hline.split(split);
			var hl = '';
			for ( var h in hlines ) {
				if (hl.length > 0) hl += ',';
				hl += hlines[h];
				if ( hl.split(wrap).length % 2 !== 0 ) {
					hl = hl.replace(wrapreplace,'').replace(/(^\s*)|(\s*$)/g,'');
					headers.push(hl.toLowerCase());
					hl = '';
				}
			}

			for (var i = 0; i < lines.length; i++) {
				var obj = {};
				var currentline = lines[i].split(split);
				var cl = '';
				var counter = 0;
				var lengths = 0;
				for ( var col in currentline ) {
					if (cl.length > 0) cl += ',';
					cl += currentline[col];
					if ( cl.split(wrap).length % 2 !== 0 ) {
						cl = cl.replace(wrapreplace,'');
						if (headers[counter] && headers[counter].length > 0) obj[headers[counter]] = cl;
						if (lengths === 0) lengths = cl.length;
						cl = '';
						counter += 1;
					}
				}
				if (lengths) identifiers.push(obj);
			}

			var payload = {processes:identifiers,name:filename};
			if ( $('.bulklibraries:checked').length ) {
			  payload.libraries = [];
			  $('.bulklibraries:checked').each(function() {
			    payload.libraries.push($(this).val());
			  });
			}
			$.ajax({
				url: api + '/job?apikey='+clogin.apikey,
				method: 'POST',
				data: JSON.stringify(payload),
				dataType: 'JSON', // TODO sort issue here, the POST invalidates preflight without jsonp but with jsonp we don't get back a jsonp object
				contentType: "application/json; charset=utf-8",
				success: function() { $('#jobinfo').html('<p>Job accepted! We will email you the results when they are ready. </p>'); },
				error: function() { $('#jobinfo').html('<p>Sorry, this job could not be uploaded. Contact <EMAIL></p>'); }
			});
		}

		var uploadJob = function(e) {
			$('#jobinfo').html('Uploading...').show();
			var f;
			if( window.FormData === undefined ) {
				f = (e.files || e.dataTransfer.files);
			} else {
				f = e.target.files[0];
			}
			filename = f.name;
			var reader = new FileReader();
			reader.onload = (function(theFile) {
				return function(e) {
					file = e.target.result;
					submitJob();
				};
			})(f);
			reader.readAsBinaryString(f);
		}

		$('input[type=file]').on('change', uploadJob);

    clogin.afterLogin = function() {
      if (clogin.hasRole('openaccessbutton.admin')) {
				getJobs();
        $('#bulk').show();
      } else {
        window.location = '/';
      }
    }
		clogin.afterFailure = function() { window.location = '/account?next=/bulk'; };
    clogin.login();
  });
</script>

{'fraction_non_alphanumeric': 0.19748243307324223, 'fraction_numerical': 0.0053455188170884165, 'mean_word_length': 2.709306044131756, 'pattern_counts': {'":': 0, '<': 228, '<?xml version=': 0, '>': 232, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7420053', 'n_tokens_mistral': 8516, 'n_tokens_neox': 7526, 'n_words': 1944}