<commit_before>let sentiment = require('sentiment'),
		stats = require("stats-lite");
function sentimentAnalyzer(){
	let analyzeReddit = function(reddits){
		let rankingHolder = [];
		for(var key in reddits){
			let sentimentObj = sentiment(reddits[key].comment);
			reddits[key].sentiment = sentimentObj;

			reddits[key].sentiment.w_rank = reddit_rank(reddits[key]);
					// if(isNaN(content[j])) console.log("--------------------"+JSON.stringify(content[j]))
			rankingHolder.push(reddits[key].sentiment.w_rank);

		}

		let normalData = normal_dist_data_filter(rankingHolder)
		let reddit_with_graphical = {data:reddits}
		for(var i in normalData){
			reddit_with_graphical[i] = normalData[i]
		}

		return reddit_with_graphical;

	};
	let reddit_rank = function(redditComment) {
		let tweetText = redditComment.comment.replace(/\W+/g, " "),
			voteResults = redditComment.score,
			score = redditComment.sentiment.score,
			comparative = redditComment.sentiment.comparative;
		let results = 0;
		results += score+ (score*Math.abs(comparative));
	    //results += (retweets!=0?score/Math.abs(score)*(Math.log(retweets)/Math.log(2)):0);
	    //results += (favorites!=0?score/Math.abs(score)*(Math.log(favorites)/Math.log(2)):0);
	    //results = results / tweetText.length;
	    //tweetIndividual.sentiment.w_score = results*100;
	  	return results;
	};
		let twitter_rank = function(tweetIndividual) {
		let tweetText = tweetIndividual.text.replace(/\W+/g, " "),
			retweets = tweetIndividual.share_count,
			favorites = tweetIndividual.vote_count,
			score = tweetIndividual.sentiment.score,
			mentions = tweetIndividual.mentions_to.length,
			comparative = tweetIndividual.sentiment.comparative;
		let results = 0;
		results += score+ (score*Math.abs(comparative));
	    //results += (retweets!=0?score/Math.abs(score)*(Math.log(retweets)/Math.log(2)):0);
	    //results += (favorites!=0?score/Math.abs(score)*(Math.log(favorites)/Math.log(2)):0);
	    //results = results / tweetText.length;
	    //tweetIndividual.sentiment.w_score = results*100;
	  	return results;
	};
	let normal_dist_data_filter = function(content){
		//console.log("-----"+content);
		let normalized = content;
		normalized.sort();
		let mean = stats.mean(normalized);
		let median = stats.median(normalized);
		let standardDeviation = stats.stdev(normalized);
		let mode = stats.mode(normalized);
		let variance = stats.variance(normalized);
		return {set: normalized,
				mean: mean,
				median:median,
				standardDeviation:standardDeviation,
				mode:mode,
				variance:variance};
	};

	let analyzeTwit = function(textObject,callback){
		let analyzedResults = {};
		let tweet_sentiment = [];
		//console.log(textObject);
		let rankingHolder = [];
		for(var i in textObject){
			let curr = textObject[i];
			let content = curr.content;
			for(var j in content){

				if(sentiment(content[j].text)!=0){
					content[j].sentiment = sentiment(content[j].text);
					content[j].sentiment.w_rank = twitter_rank(content[j]);
					//if(isNaN(content[j])) console.log("--------------------"+JSON.stringify(content[j]))
					rankingHolder.push(twitter_rank(content[j]));}
			}
		}
		//let sentimentCalc= sentiment(textObject.text);
		//for (let attrname in sentimentCalc) { textObject.sentiment[attrname] = sentimentCalc[attrname]; }

		let normalData = normal_dist_data_filter(rankingHolder)
		let tweet_with_graphical = {data:textObject}
		for(var i in normalData){
			tweet_with_graphical[i] = normalData[i]
		}

		return tweet_with_graphical;
	};

	return {
		twitter: analyzeTwit,
		reddit: analyzeReddit
	};
}

module.exports = sentimentAnalyzer();

<commit_msg>(feature) sentiment analysis coordinates<commit_after>let sentiment = require('sentiment'),
		stats = require("stats-lite");
function sentimentAnalyzer(){
	let analyzeReddit = function(reddits){
		let rankingHolder = [];
		for(var key in reddits){
			let sentimentObj = sentiment(reddits[key].comment);
			reddits[key].sentiment = sentimentObj;

			reddits[key].sentiment.w_rank = reddit_rank(reddits[key]);
					// if(isNaN(content[j])) console.log("--------------------"+JSON.stringify(content[j]))
			rankingHolder.push(reddits[key].sentiment.w_rank);

		}

		let normalData = normal_dist_data_filter(rankingHolder)
		let reddit_with_graphical = {data:reddits}
		for(var i in normalData){
			reddit_with_graphical[i] = normalData[i]
		}

		return reddit_with_graphical;

	};
	let reddit_rank = function(redditComment) {
		let tweetText = redditComment.comment.replace(/\W+/g, " "),
			voteResults = redditComment.score,
			score = redditComment.sentiment.score,
			comparative = redditComment.sentiment.comparative;
		let results = 0;
		results += score+ (score*Math.abs(comparative));
	    //results += (retweets!=0?score/Math.abs(score)*(Math.log(retweets)/Math.log(2)):0);
	    //results += (favorites!=0?score/Math.abs(score)*(Math.log(favorites)/Math.log(2)):0);
	    //results = results / tweetText.length;
	    //tweetIndividual.sentiment.w_score = results*100;

	  	return [redditComment.score, results];
	}
		let twitter_rank = function(tweetIndividual) {
		let tweetText = tweetIndividual.text.replace(/\W+/g, " "),
			retweets = tweetIndividual.share_count,
			favorites = tweetIndividual.vote_count,
			score = tweetIndividual.sentiment.score,
			mentions = tweetIndividual.mentions_to.length,
			comparative = tweetIndividual.sentiment.comparative;
		let results = 0;
		results += score+ (score*Math.abs(comparative));
	    //results += (retweets!=0?score/Math.abs(score)*(Math.log(retweets)/Math.log(2)):0);
	    //results += (favorites!=0?score/Math.abs(score)*(Math.log(favorites)/Math.log(2)):0);
	    //results = results / tweetText.length;
	    //tweetIndividual.sentiment.w_score = results*100;
	  	return results;
	};
	let normal_dist_data_filter = function(content){
		//console.log("-----"+content);
		let normalized = content;
		normalized.sort();
		let mean = stats.mean(normalized);
		let median = stats.median(normalized);
		let standardDeviation = stats.stdev(normalized);
		let mode = stats.mode(normalized);
		let variance = stats.variance(normalized);
		return {set: normalized,
				mean: mean,
				median:median,
				standardDeviation:standardDeviation,
				mode:mode,
				variance:variance};
	};

	let analyzeTwit = function(textObject,callback){
		let analyzedResults = {};
		let tweet_sentiment = [];
		//console.log(textObject);
		let rankingHolder = [];
		for(var i in textObject){
			let curr = textObject[i];
			let content = curr.content;
			for(var j in content){

				if(sentiment(content[j].text)!=0){
					content[j].sentiment = sentiment(content[j].text);
					content[j].sentiment.w_rank = twitter_rank(content[j]);
					//if(isNaN(content[j])) console.log("--------------------"+JSON.stringify(content[j]))
					rankingHolder.push(twitter_rank(content[j]));}
			}
		}
		//let sentimentCalc= sentiment(textObject.text);
		//for (let attrname in sentimentCalc) { textObject.sentiment[attrname] = sentimentCalc[attrname]; }

		let normalData = normal_dist_data_filter(rankingHolder)
		let tweet_with_graphical = {data:textObject}
		for(var i in normalData){
			tweet_with_graphical[i] = normalData[i]
		}

		return tweet_with_graphical;
	};

	return {
		twitter: analyzeTwit,
		reddit: analyzeReddit
	};
}

module.exports = sentimentAnalyzer();

<|endoftext|>


<commit_before>Tickets = function(self){
  this.calendar = function(month, year, data) {
    if ( typeof(month) === 'object' ) {
      data = month;
      month = null;
    }
    this.current_date = new Date();
    this.day_labels = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    this.month_labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    this.month = (isNaN(month) || month === null) ? this.current_date.getMonth() : month;
    this.year = (isNaN(year) || year === null) ? this.current_date.getFullYear() : year;
    this.draw = function(ele){
        // get dates
        var startingDay = new Date(this.year, this.month, 1).getDay(),
        endingDate = new Date(this.year, this.month + 1, 0),
        monthLength = endingDate.getDate(),
        inLastRow = 6 - endingDate.getDay();
        if (this.month > 11) {
          this.month -= 12;
          this.year += 1;
        } else if (this.month < 0) {
          this.month += 12;
          this.year -= 1;
        }

        // generate header
        this.table = document.createElement('table');
        this.head = document.createElement('thead');
        this.prev = document.createElement('th');
        this.next = document.createElement('th');
        this.title = document.createElement('th');
        this.days = document.createElement('tr');
        this.body = document.createElement('tbody');
        this.cells = '';
        this.table.setAttribute('class', 'calendar');
        this.table.appendChild(this.head);
        this.head.appendChild(this.prev);
        this.prev.innerHTML = "«";
        this.prev.id = 'prev';
        this.head.appendChild(this.title);
        this.head.appendChild(this.next);
        this.next.innerHTML = "»";
        this.next.id = 'next';
        this.table.appendChild(this.days);
        this.title.innerHTML = this.month_labels[this.month] + " " + this.year;
        this.title.setAttribute('colspan', '5');
        this.days.setAttribute('class', 'header');
        for (var i = 0; i <= 6; i++ ) this.cells += '' + this.day_labels[i] + '	';
        this.days.innerHTML = this.cells;

        //generate calendar
        var html = '
';
        if ( startingDay ) html += '	';
        for (var day = 1; day <= monthLength; day++) {
        html += '
' + day + '
';
        //if data argument present, append key value for current day
        if (data) {
          var today = (this.month+1)+'/'+day+'/'+this.year;
          if (data[today]) {
            html += '
'+Object.keys(data[today]).length+' '+data.type+'
';
            html += '
<button class="btn btn-primary" onclick="db.Tickets.showTickets(db.Tickets.sortTickets()[\''+today+'\']);">Show Tickets</button>
';
          }
        }
        html += '	';
        if ( (day + startingDay) % 7 === 0 && day != monthLength ) html += '

';
        }
        if ( inLastRow ) html += '	';
        html += '
';
        this.table.innerHTML += html;
        if (ele) {
          ele.innerHTML = this.table.outerHTML;
        } else {
          return this.table.outerHTML;
        }
        // save reference to dom node in object
        this.node = ele;
        // save reference to calendar object for enclosure scope
        var cal = this;
            (function(){
          // save calendar object reference for listeners
          var self = this;
          self.prev.addEventListener('click', function(){
            cal.month--;
            cal.draw(cal.node);
          });
          self.next.addEventListener('click', function(){
            cal.month++;
            cal.draw(cal.node);
          });
          document.onkeydown = function(e) {
            e = e || window.event;
              if (e.keyCode == '37') {
                // left arrow
                cal.month--;
                cal.draw(cal.node);
              } else if (e.keyCode == '39') {
                // right arrow
                cal.month++;
                cal.draw(cal.node);
              }
          };
        })();
      };
  };
  this.getTickets = (){
    var response = self.Tools.httpRequest({
      method: 'POST',
      url:'https://launchpad.boostability.com/TicketApi/Ticket_SelectRange',
      headers: {
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'en-US,en;q=0.8',
        'Cookie': document.cookie,
        'Referer': 'https://launchpad.boostability.com/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36',
        'X-Requested-With': 'XMLHttpRequest',
        'Content-Type': 'application/json',
        'Connection': 'keep-alive',
      },
      body: '{"statusId":"1,2","teamIds":1055,"page":1,"pageSize":1000,"startDate":"05/06/2014 06:00:00","endDate":"05/06/2017 06:00:00","ownership":"Mine"}'
    });
    tickets = JSON.parse(response).Data;
    for (var i=0;i<tickets.length;i++){
      tickets[i].DueDate = new Date(tickets[i].DueDate);
      tickets[i].StartDate = new Date(tickets[i].StartDate);
      tickets[i].ScheduledEndDate = new Date(tickets[i].ScheduledEndDate);
      tickets[i].StatusDate = new Date(tickets[i].StatusDate);
    }
    return tickets;
  };
  this.getCritical = function() {
    var tickets = this.getTickets(),
    critical = [];
    for (var i = 0; i < tickets.length; i++) {
      if (tickets[i].ScheduledEndDate < new Date()) {
        critical.push(tickets[i]);
      }
    }
    if (tickets.length > 0){
      return critical;
    } else {
      return false;
    }
  };
  this.countCritical = function() {
    var criticals = self.Tickets.getCritical();
    if (criticals) {
      return 'Critical Tickets: ' + criticals.length + '';
    } else {
      return 'Error loading tickets!';
    }
  };
  this.sortTickets = function(tickets){
    if (! tickets){
      tickets = this.getTickets();
    }
    var data = {type: 'Tickets'};
    for (var i=0;i<tickets.length;i++){
      var ticket = tickets[i],
      date = new Date(ticket.ScheduledEndDate),
      day = (date.getMonth()+1)+'/'+date.getDate()+'/'+date.getFullYear();
      if (! data[day]){ data[day] = [];}
      data[day].push(ticket);
    }
    return data;
  };
  this.listTickets = function(tickets){
    var list = document.createElement('table'),
    head = list.appendChild(document.createElement('thead')),
    body = list.appendChild(document.createElement('tbody'));
    head.innerHTML = '
Business Name	Ticket Type	Due Date
';
    for (var i=0;i<tickets.length;i++){
      var ticket = tickets[i],
      listItem = document.createElement('tr'),
      content = ''+ticket.CompanyName+'	'+ticket.TicketTypeName+'	';
      content += ''+(ticket.ScheduledEndDate.getMonth()+1);
      content += '/'+ticket.ScheduledEndDate.getDate()+'/';
      content += ticket.ScheduledEndDate.getFullYear()+'	';
      listItem.innerHTML = content;
      listItem.setAttribute('data-client', ticket.CustomerId);
      listItem.onclick = function(){
        self.Tools.openClient(this.dataset.client);
        var modals = document.getElementsByClassName('bootbox-close-button');
        for (var i=0;i<modals.length;i++){modals[i].click();}
      };
      body.appendChild(listItem);
    }
    sorttable.makeSortable(list);
    return list;
  };
  this.showTickets = function(tickets){
    bootbox.dialog({
      message: self.Tickets.listTickets(tickets),
      title: "Tickets (click row to open client)",
      className: "ticket-list",
      buttons: {},
    });
  };
  this.tryCache = function(){
    try {
      if (self.Tickets.ticketArray) {
        localStorage.setItem('ticketCache', JSON.stringify(self.Tickets.ticketArray));
      }
    } catch(err) {
      setTimeout(function(){self.Tickets.tryCache();}, 1000);
    }
  };
};
<commit_msg>Update tickets.js<commit_after>Tickets = function(self){
  this.calendar = function(month, year, data) {
    if ( typeof(month) === 'object' ) {
      data = month;
      month = null;
    }
    this.current_date = new Date();
    this.day_labels = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    this.month_labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    this.month = (isNaN(month) || month === null) ? this.current_date.getMonth() : month;
    this.year = (isNaN(year) || year === null) ? this.current_date.getFullYear() : year;
    this.draw = function(ele){
        // get dates
        var startingDay = new Date(this.year, this.month, 1).getDay(),
        endingDate = new Date(this.year, this.month + 1, 0),
        monthLength = endingDate.getDate(),
        inLastRow = 6 - endingDate.getDay();
        if (this.month > 11) {
          this.month -= 12;
          this.year += 1;
        } else if (this.month < 0) {
          this.month += 12;
          this.year -= 1;
        }

        // generate header
        this.table = document.createElement('table');
        this.head = document.createElement('thead');
        this.prev = document.createElement('th');
        this.next = document.createElement('th');
        this.title = document.createElement('th');
        this.days = document.createElement('tr');
        this.body = document.createElement('tbody');
        this.cells = '';
        this.table.setAttribute('class', 'calendar');
        this.table.appendChild(this.head);
        this.head.appendChild(this.prev);
        this.prev.innerHTML = "«";
        this.prev.id = 'prev';
        this.head.appendChild(this.title);
        this.head.appendChild(this.next);
        this.next.innerHTML = "»";
        this.next.id = 'next';
        this.table.appendChild(this.days);
        this.title.innerHTML = this.month_labels[this.month] + " " + this.year;
        this.title.setAttribute('colspan', '5');
        this.days.setAttribute('class', 'header');
        for (var i = 0; i <= 6; i++ ) this.cells += '' + this.day_labels[i] + '	';
        this.days.innerHTML = this.cells;

        //generate calendar
        var html = '
';
        if ( startingDay ) html += '	';
        for (var day = 1; day <= monthLength; day++) {
        html += '
' + day + '
';
        //if data argument present, append key value for current day
        if (data) {
          var today = (this.month+1)+'/'+day+'/'+this.year;
          if (data[today]) {
            html += '
'+Object.keys(data[today]).length+' '+data.type+'
';
            html += '
<button class="btn btn-primary" onclick="db.Tickets.showTickets(db.Tickets.sortTickets()[\''+today+'\']);">Show Tickets</button>
';
          }
        }
        html += '	';
        if ( (day + startingDay) % 7 === 0 && day != monthLength ) html += '

';
        }
        if ( inLastRow ) html += '	';
        html += '
';
        this.table.innerHTML += html;
        if (ele) {
          ele.innerHTML = this.table.outerHTML;
        } else {
          return this.table.outerHTML;
        }
        // save reference to dom node in object
        this.node = ele;
        // save reference to calendar object for enclosure scope
        var cal = this;
            (function(){
          // save calendar object reference for listeners
          var self = this;
          self.prev.addEventListener('click', function(){
            cal.month--;
            cal.draw(cal.node);
          });
          self.next.addEventListener('click', function(){
            cal.month++;
            cal.draw(cal.node);
          });
          document.onkeydown = function(e) {
            e = e || window.event;
              if (e.keyCode == '37') {
                // left arrow
                cal.month--;
                cal.draw(cal.node);
              } else if (e.keyCode == '39') {
                // right arrow
                cal.month++;
                cal.draw(cal.node);
              }
          };
        })();
      };
  };
  this.getTickets = function(){
    var response = self.Tools.httpRequest({
      method: 'POST',
      url:'https://launchpad.boostability.com/TicketApi/Ticket_SelectRange',
      headers: {
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'en-US,en;q=0.8',
        'Cookie': document.cookie,
        'Referer': 'https://launchpad.boostability.com/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36',
        'X-Requested-With': 'XMLHttpRequest',
        'Content-Type': 'application/json',
        'Connection': 'keep-alive',
      },
      body: '{"statusId":"1,2","teamIds":1055,"page":1,"pageSize":1000,"startDate":"05/06/2014 06:00:00","endDate":"05/06/2017 06:00:00","ownership":"Mine"}'
    });
    tickets = JSON.parse(response).Data;
    for (var i=0;i<tickets.length;i++){
      tickets[i].DueDate = new Date(tickets[i].DueDate);
      tickets[i].StartDate = new Date(tickets[i].StartDate);
      tickets[i].ScheduledEndDate = new Date(tickets[i].ScheduledEndDate);
      tickets[i].StatusDate = new Date(tickets[i].StatusDate);
    }
    return tickets;
  };
  this.getCritical = function() {
    var tickets = this.getTickets(),
    critical = [];
    for (var i = 0; i < tickets.length; i++) {
      if (tickets[i].ScheduledEndDate < new Date()) {
        critical.push(tickets[i]);
      }
    }
    if (tickets.length > 0){
      return critical;
    } else {
      return false;
    }
  };
  this.countCritical = function() {
    var criticals = self.Tickets.getCritical();
    if (criticals) {
      return 'Critical Tickets: ' + criticals.length + '';
    } else {
      return 'Error loading tickets!';
    }
  };
  this.sortTickets = function(tickets){
    if (! tickets){
      tickets = this.getTickets();
    }
    var data = {type: 'Tickets'};
    for (var i=0;i<tickets.length;i++){
      var ticket = tickets[i],
      date = new Date(ticket.ScheduledEndDate),
      day = (date.getMonth()+1)+'/'+date.getDate()+'/'+date.getFullYear();
      if (! data[day]){ data[day] = [];}
      data[day].push(ticket);
    }
    return data;
  };
  this.listTickets = function(tickets){
    var list = document.createElement('table'),
    head = list.appendChild(document.createElement('thead')),
    body = list.appendChild(document.createElement('tbody'));
    head.innerHTML = '
Business Name	Ticket Type	Due Date
';
    for (var i=0;i<tickets.length;i++){
      var ticket = tickets[i],
      listItem = document.createElement('tr'),
      content = ''+ticket.CompanyName+'	'+ticket.TicketTypeName+'	';
      content += ''+(ticket.ScheduledEndDate.getMonth()+1);
      content += '/'+ticket.ScheduledEndDate.getDate()+'/';
      content += ticket.ScheduledEndDate.getFullYear()+'	';
      listItem.innerHTML = content;
      listItem.setAttribute('data-client', ticket.CustomerId);
      listItem.onclick = function(){
        self.Tools.openClient(this.dataset.client);
        var modals = document.getElementsByClassName('bootbox-close-button');
        for (var i=0;i<modals.length;i++){modals[i].click();}
      };
      body.appendChild(listItem);
    }
    sorttable.makeSortable(list);
    return list;
  };
  this.showTickets = function(tickets){
    bootbox.dialog({
      message: self.Tickets.listTickets(tickets),
      title: "Tickets (click row to open client)",
      className: "ticket-list",
      buttons: {},
    });
  };
  this.tryCache = function(){
    try {
      if (self.Tickets.ticketArray) {
        localStorage.setItem('ticketCache', JSON.stringify(self.Tickets.ticketArray));
      }
    } catch(err) {
      setTimeout(function(){self.Tickets.tryCache();}, 1000);
    }
  };
};
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const BPromise = require('bluebird');
const xml2js = require('xml2js');
BPromise.promisifyAll(xml2js);
const log = require('app/server/util/logapp.js');
const dates = require('app/server/util/dates.js');
const datamerge = require('app/server/util/datamerge.js');
// const datatransform = require('app/server/util/datatransform.js');

const metaField = {
  START_DATE: 'start',
  END_DATE: 'end',
  DEVICE_ID: 'deviceid',
  SIM_SERIAL: 'simserial',
  PERSON: 'person',
  REGION: 'region',
  FACILITY: 'facility'
};

const formType = {
  SAMPLE_DEPARTURE: 'sdepart',
  SAMPLE_ARRIVAL: 'sarrive',
  RESULTS_DEPATURE: 'redepart',
  RESULTS_ARRIVAL: 'rarrive'
};

const REPEAT = 'srepeat';
const LAB_ID = 'labid';
const ST_ID = 'stid';
const ARTIFACT = 'stype';
const STATUS = 'condition';

const formElement = BPromise.method(parsed => {
  log.debug('Pulling collect for element for parsed form', parsed);
  const form = _.values(formType).filter(type => !!parsed[type]);
  if (!(form || form[0])) {
    throw new Error(`Cannot identify form type among top elements:
                    ${Object.keys(parsed)}`);
  }
  log.debug('form from parsed', form);
  return form[0];
});

const collectSubmission = xml => {
  log.debug('Transorming Lab Status XML', xml);
  const parse = xml2js.parseStringAsync(xml);
  const form = parse.then(formElement);
  return BPromise.join(parse, form, (parsed, formResult) => parsed[formResult]);
};

const repeats = form => BPromise.resolve(_.get(form, [REPEAT]));

const ST_ID_REPEAT_PATH = [ST_ID, 0];
const LAB_ID_REPEAT_PATH = [LAB_ID, 0];

const sampleIds = form => (
  repeats(form)
  .map(repeat => ({
    stId: _.get(repeat, ST_ID_REPEAT_PATH) || null,
    labId: _.get(repeat, LAB_ID_REPEAT_PATH) || null
  }))
  .then(results => _.uniqBy(results, ids => ids.stId))
);

const FACILITY_PATH = [metaField.FACILITY, '0'];
const PERSON_PATH = [metaField.PERSON, '0'];
const REGION_PATH = [metaField.REGION, '0'];
const STATUS_REPEAT_PATH = [STATUS, '0'];
const ARTIFACT_REPEAT_PATH = [ARTIFACT, '0'];

const upperCaseKey = key => key ? key.toUpperCase() : key;

const artifacts = form => {
  return repeats(form)
  .tap(form => {
    log.debug('collecttransform artifacts parser form', form);
  })
  .map(repeat => ({
    stId: _.get(repeat, ST_ID_REPEAT_PATH) || null,
    labId: _.get(repeat, LAB_ID_REPEAT_PATH) || null,
    artifactType: upperCaseKey(_.get(repeat, ARTIFACT_REPEAT_PATH))
  }))
  .tap(results => {
    console.log('artifacts pre-filtered results');
    console.dir(results, {depth: 3});
  })
  .then(results => _.uniqBy(results, item => item.artifactType + item.stId)
  )
  .tap(results => {
    console.log('artifacts post-filtered results');
    console.dir(results, {depth: 3});
  });
};

const FORM_TYPE_PATH = ['$', 'id'];
const END_DATE_PATH = ['end', 0];
const DEFAULT_STATUS = 'ok';

const changes = form => {
  log.debug('form for changes', form);
  const commonProps = BPromise.props({
    statusDate: dates.parseXMLDate(_.get(form, END_DATE_PATH)),
    stage: _.get(form, FORM_TYPE_PATH),
    person: upperCaseKey(_.get(form, PERSON_PATH)),
    region: upperCaseKey(_.get(form, REGION_PATH)),
    facility: upperCaseKey(_.get(form, FACILITY_PATH))
  });

  return BPromise.join(commonProps, repeats(form), (common, repeatEls) =>
    BPromise.map(repeatEls, repeat => ({
      stId: _.get(repeat, ST_ID_REPEAT_PATH),
      labId: _.get(repeat, LAB_ID_REPEAT_PATH) || null,
      statusDate: common.statusDate,
      stage: common.stage,
      artifactType: upperCaseKey(_.get(repeat, ARTIFACT_REPEAT_PATH)),
      region: common.region,
      facility: common.facility,
      person: common.person,
      status: upperCaseKey(_.get(repeat, STATUS_REPEAT_PATH, DEFAULT_STATUS))
    }))
  );
};

/**
 * Replaces the stId/labId value pair with the corresponding sampleId reference
 * (uuid).
 *
 * @method [fillSampleIdRefs]
 * @param {Array.<Object>} artifacts [description]
 * @param {Array.<Object>} sampleIds [description]
 * @return {Array.<Object>}          Array of artifacts with sampleId uuids
 */
const fillSampleIdRefs = BPromise.method((artifacts, sampleIds) => {
  if (!sampleIds) {
    throw new Error('Missing required parameter sampleIds');
  }
  if (!_.every(sampleIds, sampleId => !!sampleId.uuid)) {
    throw new Error('Missing required sampleIds uuid');
  }
  return datamerge.propKeyReduce(sampleIds, ['stId'])
  .then(idMap => {
    return BPromise.map(artifacts, artifact => {
      const sampleMatch = idMap[artifact.stId];
      return Object.assign({},
        _.omit(artifact, ['stId', 'labId']),
        {sampleId: sampleMatch.uuid}
      );
    });
  });
});

/**
 * Replaces the stId/labId value pair with the corresponding sampleId reference
 * (uuid). Using this sample reference, this function replaces the artifactType
 * value with the correct artifact reference (uuid).
 *
 * @param  {Array.<Object>} changes   [description]
 * @param  {Array.<Object>} sampleIds [description]
 * @param  {Array.<Object>} artifacts [description]
 * @return {Array.<Object>}           Array of changes with artifact uuids
 */
const fillArtifactRefs = (changes, sampleIds, artifacts) => {
  // Lookup samples by the STT IDs
  const mapSamples = datamerge.propKeyReduce(sampleIds, ['stId']);

  // Lookup artifacts by sampleId (uuid) and artifactType (metadata key)
  const mapArtifacts = datamerge.propKeyReduce(
    artifacts, ['sampleId', 'artifactType']
  );

  return BPromise.join(mapSamples, mapArtifacts)
  .spread((smapper, amapper) => {
    log.debug('sampleId mapper', smapper);
    log.debug('artifacts mapper', amapper);
    return BPromise.map(changes, change => {
      log.debug('Filling refs for change', change);
      log.debug(`Pulling sampleId for stId=${change.stId}`);
      const sampleIdRef = smapper[change.stId];
      log.debug('Matched sampleId', sampleIdRef);
      log.debug('Artifacts for sampleId', amapper[sampleIdRef.uuid]);
      const artifactRef = amapper[sampleIdRef.uuid][change.artifactType];
      return Object.assign({},
        // Change objects do include stId, labId, and artifactType values
        // directly. Instead, it holds references artifacts (which themselves
        // reference a sample).
        _.omit(change, ['stId', 'labId', 'artifactType']),
        {artifact: artifactRef.uuid}
      );
    });
  });
};

module.exports = {
  collectSubmission,
  sampleIds,
  artifacts,
  changes,
  fillSampleIdRefs,
  fillArtifactRefs
};
<commit_msg>logging cleanup<commit_after>'use strict';

const _ = require('lodash');
const BPromise = require('bluebird');
const xml2js = require('xml2js');
BPromise.promisifyAll(xml2js);
const log = require('app/server/util/logapp.js');
const dates = require('app/server/util/dates.js');
const datamerge = require('app/server/util/datamerge.js');
// const datatransform = require('app/server/util/datatransform.js');

const metaField = {
  START_DATE: 'start',
  END_DATE: 'end',
  DEVICE_ID: 'deviceid',
  SIM_SERIAL: 'simserial',
  PERSON: 'person',
  REGION: 'region',
  FACILITY: 'facility'
};

const formType = {
  SAMPLE_DEPARTURE: 'sdepart',
  SAMPLE_ARRIVAL: 'sarrive',
  RESULTS_DEPATURE: 'redepart',
  RESULTS_ARRIVAL: 'rarrive'
};

const REPEAT = 'srepeat';
const LAB_ID = 'labid';
const ST_ID = 'stid';
const ARTIFACT = 'stype';
const STATUS = 'condition';

const formElement = BPromise.method(parsed => {
  log.debug('Pulling collect for element for parsed form', parsed);
  const form = _.values(formType).filter(type => !!parsed[type]);
  if (!(form || form[0])) {
    throw new Error(`Cannot identify form type among top elements:
                    ${Object.keys(parsed)}`);
  }
  log.debug('form from parsed', form);
  return form[0];
});

const collectSubmission = xml => {
  log.debug('Transorming Lab Status XML', xml);
  const parse = xml2js.parseStringAsync(xml);
  const form = parse.then(formElement);
  return BPromise.join(parse, form, (parsed, formResult) => parsed[formResult]);
};

const repeats = form => BPromise.resolve(_.get(form, [REPEAT]));

const ST_ID_REPEAT_PATH = [ST_ID, 0];
const LAB_ID_REPEAT_PATH = [LAB_ID, 0];

const sampleIds = form => (
  repeats(form)
  .map(repeat => ({
    stId: _.get(repeat, ST_ID_REPEAT_PATH) || null,
    labId: _.get(repeat, LAB_ID_REPEAT_PATH) || null
  }))
  .then(results => _.uniqBy(results, ids => ids.stId))
);

const FACILITY_PATH = [metaField.FACILITY, '0'];
const PERSON_PATH = [metaField.PERSON, '0'];
const REGION_PATH = [metaField.REGION, '0'];
const STATUS_REPEAT_PATH = [STATUS, '0'];
const ARTIFACT_REPEAT_PATH = [ARTIFACT, '0'];

const upperCaseKey = key => key ? key.toUpperCase() : key;

const artifacts = form => {
  return repeats(form)
  .tap(form => {
    log.debug('collecttransform artifacts parser form', form);
  })
  .map(repeat => ({
    stId: _.get(repeat, ST_ID_REPEAT_PATH) || null,
    labId: _.get(repeat, LAB_ID_REPEAT_PATH) || null,
    artifactType: upperCaseKey(_.get(repeat, ARTIFACT_REPEAT_PATH))
  }))
  .then(results => _.uniqBy(results, item => item.artifactType + item.stId));
};

const FORM_TYPE_PATH = ['$', 'id'];
const END_DATE_PATH = ['end', 0];
const DEFAULT_STATUS = 'ok';

const changes = form => {
  log.debug('form for changes', form);
  const commonProps = BPromise.props({
    statusDate: dates.parseXMLDate(_.get(form, END_DATE_PATH)),
    stage: _.get(form, FORM_TYPE_PATH),
    person: upperCaseKey(_.get(form, PERSON_PATH)),
    region: upperCaseKey(_.get(form, REGION_PATH)),
    facility: upperCaseKey(_.get(form, FACILITY_PATH))
  });

  return BPromise.join(commonProps, repeats(form), (common, repeatEls) =>
    BPromise.map(repeatEls, repeat => ({
      stId: _.get(repeat, ST_ID_REPEAT_PATH),
      labId: _.get(repeat, LAB_ID_REPEAT_PATH) || null,
      statusDate: common.statusDate,
      stage: common.stage,
      artifactType: upperCaseKey(_.get(repeat, ARTIFACT_REPEAT_PATH)),
      region: common.region,
      facility: common.facility,
      person: common.person,
      status: upperCaseKey(_.get(repeat, STATUS_REPEAT_PATH, DEFAULT_STATUS))
    }))
  );
};

/**
 * Replaces the stId/labId value pair with the corresponding sampleId reference
 * (uuid).
 *
 * @method [fillSampleIdRefs]
 * @param {Array.<Object>} artifacts [description]
 * @param {Array.<Object>} sampleIds [description]
 * @return {Array.<Object>}          Array of artifacts with sampleId uuids
 */
const fillSampleIdRefs = BPromise.method((artifacts, sampleIds) => {
  if (!sampleIds) {
    throw new Error('Missing required parameter sampleIds');
  }
  if (!_.every(sampleIds, sampleId => !!sampleId.uuid)) {
    throw new Error('Missing required sampleIds uuid');
  }
  return datamerge.propKeyReduce(sampleIds, ['stId'])
  .then(idMap => {
    return BPromise.map(artifacts, artifact => {
      const sampleMatch = idMap[artifact.stId];
      return Object.assign({},
        _.omit(artifact, ['stId', 'labId']),
        {sampleId: sampleMatch.uuid}
      );
    });
  });
});

/**
 * Replaces the stId/labId value pair with the corresponding sampleId reference
 * (uuid). Using this sample reference, this function replaces the artifactType
 * value with the correct artifact reference (uuid).
 *
 * @param  {Array.<Object>} changes   [description]
 * @param  {Array.<Object>} sampleIds [description]
 * @param  {Array.<Object>} artifacts [description]
 * @return {Array.<Object>}           Array of changes with artifact uuids
 */
const fillArtifactRefs = (changes, sampleIds, artifacts) => {
  // Lookup samples by the STT IDs
  const mapSamples = datamerge.propKeyReduce(sampleIds, ['stId']);

  // Lookup artifacts by sampleId (uuid) and artifactType (metadata key)
  const mapArtifacts = datamerge.propKeyReduce(
    artifacts, ['sampleId', 'artifactType']
  );

  return BPromise.join(mapSamples, mapArtifacts)
  .spread((smapper, amapper) => {
    return BPromise.map(changes, change => {
      const sampleIdRef = smapper[change.stId];
      const artifactRef = amapper[sampleIdRef.uuid][change.artifactType];
      return Object.assign({},
        // Change objects do include stId, labId, and artifactType values
        // directly. Instead, it holds references artifacts (which themselves
        // reference a sample).
        _.omit(change, ['stId', 'labId', 'artifactType']),
        {artifact: artifactRef.uuid}
      );
    });
  });
};

module.exports = {
  collectSubmission,
  sampleIds,
  artifacts,
  changes,
  fillSampleIdRefs,
  fillArtifactRefs
};
<|endoftext|>


<commit_before>{
	"translatorID":"d0b1914a-11f1-4dd7-8557-b32fe8a3dd47",
	"translatorType":4,
	"label":"EBSCOhost",
	"creator":"Simon Kornblith and Michael Berkowitz",
	"target":"https?://[^/]+/(?:bsi|ehost)/(?:results|detail|folder)",
	"minVersion":"1.0.0b3.r1",
	"maxVersion":"",
	"priority":100,
	"inRepository":true,
	"lastUpdated":"2010-09-12 20:35:00"
}

function detectWeb(doc, url) {
	var namespace = doc.documentElement.namespaceURI;
	var nsResolver = namespace ? function(prefix) {
		if (prefix == 'x') return namespace; else return null;
	} : null;
		// The Scientific American Archive breaks this translator, disabling
		try {
			var databases = doc.evaluate("//span[@class = 'selected-databases']", doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext().textContent;
			if(databases.indexOf("Scientific American Archive Online") != -1) {
				return false;
			}
		} catch(e) {
		}

	// See if this is a search results or folder results page
	var searchResult = doc.evaluate('//ul[@class="result-list" or @class="folder-list"]/li/div[@class="result-list-record" or @class="folder-item"]', doc, nsResolver,
	                                XPathResult.ANY_TYPE, null).iterateNext();
	if(searchResult) {
		return "multiple";
	}
/*
	var xpath = '//div[@class="citation-wrapping-div"]/dl[@class="citation-fields"]/dt[starts-with(text(), "Persistent link to this record")'
		+' or starts-with(text(), "Vínculo persistente a este informe")'
		+' or starts-with(text(), "Lien permanent à cette donnée")'
		+' or starts-with(text(), "Permanenter Link zu diesem Datensatz")'
		+' or starts-with(text(), "Link permanente al record")'
		+' or starts-with(text(), "Link permanente para este registro")'
		+' or starts-with(text(), "本記錄固定連結")'
		+' or starts-with(text(), "此记录的永久链接")'
		+' or starts-with(text(), "このレコードへのパーシスタント リンク")'
		+' or starts-with(text(), "레코드 링크 URL")'
		+' or starts-with(text(), "Постоянная ссылка на эту запись")'
		+' or starts-with(text(), "Bu kayda sürekli bağlantı")'
		+' or starts-with(text(), "Μόνιμος σύνδεσμος σε αυτό το αρχείο")]';
*/
	var xpath = '//input[@id="ctl00_ctl00_Column2_Column2_topDeliveryControl_deliveryButtonControl_lnkExport"]';
	var persistentLink = doc.evaluate(xpath, doc, nsResolver, XPathResult.ANY_TYPE, null);
	if(persistentLink) {
		return "journalArticle";
	}
}

var customViewStateMatch = /<input type="hidden" name="__CUSTOMVIEWSTATE" id="__CUSTOMVIEWSTATE" value="([^"]+)" \/>/
var host;

function fullEscape(text) {
	return escape(text).replace(/\//g, "%2F").replace(/\+/g, "%2B");
}

function generateDeliverString(nsResolver, doc){
	var hiddenInputs = doc.evaluate('//input[@type="hidden" and not(contains(@name, "folderHas")) and not(@name ="ajax")]', doc, nsResolver, XPathResult.ANY_TYPE, null);
	var hiddenInput;
	var deliverString ="";
	while(hiddenInput = hiddenInputs.iterateNext()) {
		if (hiddenInput.name !== "__EVENTTARGET" && hiddenInput.name !== "") {
			deliverString = deliverString+hiddenInput.name.replace(/\$/g, "%24")+"="+encodeURIComponent(hiddenInput.value) + "&";
		}
	}
	var otherHiddenInputs = doc.evaluate('//input[@type="hidden" and contains(@name, "folderHas")]', doc, nsResolver, XPathResult.ANY_TYPE, null);
	while(hiddenInput = otherHiddenInputs.iterateNext()) {
		deliverString = deliverString+hiddenInput.name.replace(/\$/g, "%24")+"="+escape(hiddenInput.value).replace(/\//g, "%2F").replace(/%20/g, "+") + "&";
	}

	deliverString = "__EVENTTARGET=ctl00%24ctl00%24Column2%24Column2%24topDeliveryControl%24deliveryButtonControl%24lnkExport&" + deliverString;

	return deliverString;
}

/*
 * given the text of the delivery page, downloads an item
 */
function downloadFunction(text) {

	//Zotero.debug("POSTTEXT="+text);
	var postLocation = /<form (?:autocomplete="o(?:ff|n)" )?name="aspnetForm" method="post" action="([^"]+)"/
	var postMatch = postLocation.exec(text);
	var deliveryURL = postMatch[1].replace(/&/g, "&");
	postMatch = customViewStateMatch.exec(text);
	var downloadString = "__EVENTTARGET=&__EVENTARGUMENT=&__CUSTOMVIEWSTATE="+fullEscape(postMatch[1])+"&__VIEWSTATE=&ctl00%24ctl00%24MainContentArea%24MainContentArea%24ctl00%24btnSubmit=Save&ctl00%24ctl00%24MainContentArea%24MainContentArea%24ctl00%24BibFormat=1&ajax=enabled";

	Zotero.Utilities.HTTP.doPost(host+"/ehost/"+deliveryURL,
								 downloadString, function(text) {	// get marked records as RIS
		Zotero.debug(text);
		// load translator for RIS
		var test = text.match(/UR\s+\-(.*)/g);
		if (text.match(/AB\s\s\-/)) text = text.replace(/AB\s\s\-/, "N2  -");
		if (!text.match(/TY\s\s-/)) text = text+"\nTY  - JOUR\n";
		// load translator for RIS
		var translator = Zotero.loadTranslator("import");
		translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
		translator.setString(text);
		translator.setHandler("itemDone", function(obj, item) {
			if (text.match(/^L3\s+-\s*(.*)/m)) {
				item.DOI = text.match(/^L3\s+\-\s*(.*)/m)[1];
			}
			if (text.match(/^DO\s+-\s*(.*)/m)) {
				item.DOI = text.match(/^DO\s+-\s*(.*)/m)[1];
			}
			if (text.match(/^T1\s+-/m)) {
				item.title = text.match(/^T1\s+-\s*(.*)/m)[1];
			}
			//item.itemType = "journalArticle";
			item.url = false;
			// RIS translator tries to download the link in "UR" this leads to unhappyness
			item.attachments = [];
			item.complete();

		});
		translator.translate();

		Zotero.done();
	});
}

function doWeb(doc, url) {
	var namespace = doc.documentElement.namespaceURI;
	var nsResolver = namespace ? function(prefix) {
		if (prefix == 'x') return namespace; else return null;
	} : null;

	var hostRe = new RegExp("^(https?://[^/]+)/");
	var hostMatch = hostRe.exec(url);
	host = hostMatch[1];

	var searchResult = doc.evaluate('//ul[@class="result-list" or @class="folder-list"]/li/div[@class="result-list-record" or @class="folder-item"]', doc, nsResolver,
	                                XPathResult.ANY_TYPE, null).iterateNext();

	if(searchResult) {
		var titlex = '//a[@class = "title-link color-p4"]';
		var titles = doc.evaluate(titlex, doc, nsResolver, XPathResult.ANY_TYPE, null);
		var items = new Object();
		var title;
		while (title = titles.iterateNext()) {
			items[title.href] = title.textContent;
		}

		var items = Zotero.selectItems(items);
		if(!items) {
			return true;
		}

		var uris = new Array();
		for(var i in items) {
			uris.push(i);
		}

		Zotero.Utilities.processDocuments(uris, function(newDoc){
			var postURL = newDoc.evaluate('//form[@name="aspnetForm"]/@action', newDoc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext();
			postURL = host+"/ehost/"+postURL.nodeValue;
			var deliverString = generateDeliverString(nsResolver, newDoc);
			Zotero.Utilities.HTTP.doPost(postURL, deliverString, downloadFunction);
		});
	} else {
		//This is a hack, generateDeliveryString is acting up for single pages, but it works on the plink url
		var link = [doc.evaluate("//input[@id ='pLink']/@value", doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext().nodeValue];
		Zotero.Utilities.processDocuments(link, function(newDoc){
			var postURL = newDoc.evaluate('//form[@name="aspnetForm"]/@action', newDoc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext();
			postURL = host+"/ehost/"+postURL.nodeValue;
			var deliverString = generateDeliverString(nsResolver, newDoc);
			Zotero.Utilities.HTTP.doPost(postURL, deliverString, downloadFunction);
		});

	}
	Zotero.wait();
}
<commit_msg>Trans: Fix for misinterpretation of EBSCO's M3 field as DOI<commit_after>{
	"translatorID":"d0b1914a-11f1-4dd7-8557-b32fe8a3dd47",
	"translatorType":4,
	"label":"EBSCOhost",
	"creator":"Simon Kornblith and Michael Berkowitz",
	"target":"https?://[^/]+/(?:bsi|ehost)/(?:results|detail|folder)",
	"minVersion":"1.0.0b3.r1",
	"maxVersion":"",
	"priority":100,
	"inRepository":true,
	"lastUpdated":"2010-09-12 20:35:00"
}

function detectWeb(doc, url) {
	var namespace = doc.documentElement.namespaceURI;
	var nsResolver = namespace ? function(prefix) {
		if (prefix == 'x') return namespace; else return null;
	} : null;
		// The Scientific American Archive breaks this translator, disabling
		try {
			var databases = doc.evaluate("//span[@class = 'selected-databases']", doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext().textContent;
			if(databases.indexOf("Scientific American Archive Online") != -1) {
				return false;
			}
		} catch(e) {
		}

	// See if this is a search results or folder results page
	var searchResult = doc.evaluate('//ul[@class="result-list" or @class="folder-list"]/li/div[@class="result-list-record" or @class="folder-item"]', doc, nsResolver,
	                                XPathResult.ANY_TYPE, null).iterateNext();
	if(searchResult) {
		return "multiple";
	}
/*
	var xpath = '//div[@class="citation-wrapping-div"]/dl[@class="citation-fields"]/dt[starts-with(text(), "Persistent link to this record")'
		+' or starts-with(text(), "Vínculo persistente a este informe")'
		+' or starts-with(text(), "Lien permanent à cette donnée")'
		+' or starts-with(text(), "Permanenter Link zu diesem Datensatz")'
		+' or starts-with(text(), "Link permanente al record")'
		+' or starts-with(text(), "Link permanente para este registro")'
		+' or starts-with(text(), "本記錄固定連結")'
		+' or starts-with(text(), "此记录的永久链接")'
		+' or starts-with(text(), "このレコードへのパーシスタント リンク")'
		+' or starts-with(text(), "레코드 링크 URL")'
		+' or starts-with(text(), "Постоянная ссылка на эту запись")'
		+' or starts-with(text(), "Bu kayda sürekli bağlantı")'
		+' or starts-with(text(), "Μόνιμος σύνδεσμος σε αυτό το αρχείο")]';
*/
	var xpath = '//input[@id="ctl00_ctl00_Column2_Column2_topDeliveryControl_deliveryButtonControl_lnkExport"]';
	var persistentLink = doc.evaluate(xpath, doc, nsResolver, XPathResult.ANY_TYPE, null);
	if(persistentLink) {
		return "journalArticle";
	}
}

var customViewStateMatch = /<input type="hidden" name="__CUSTOMVIEWSTATE" id="__CUSTOMVIEWSTATE" value="([^"]+)" \/>/
var host;

function fullEscape(text) {
	return escape(text).replace(/\//g, "%2F").replace(/\+/g, "%2B");
}

function generateDeliverString(nsResolver, doc){
	var hiddenInputs = doc.evaluate('//input[@type="hidden" and not(contains(@name, "folderHas")) and not(@name ="ajax")]', doc, nsResolver, XPathResult.ANY_TYPE, null);
	var hiddenInput;
	var deliverString ="";
	while(hiddenInput = hiddenInputs.iterateNext()) {
		if (hiddenInput.name !== "__EVENTTARGET" && hiddenInput.name !== "") {
			deliverString = deliverString+hiddenInput.name.replace(/\$/g, "%24")+"="+encodeURIComponent(hiddenInput.value) + "&";
		}
	}
	var otherHiddenInputs = doc.evaluate('//input[@type="hidden" and contains(@name, "folderHas")]', doc, nsResolver, XPathResult.ANY_TYPE, null);
	while(hiddenInput = otherHiddenInputs.iterateNext()) {
		deliverString = deliverString+hiddenInput.name.replace(/\$/g, "%24")+"="+escape(hiddenInput.value).replace(/\//g, "%2F").replace(/%20/g, "+") + "&";
	}

	deliverString = "__EVENTTARGET=ctl00%24ctl00%24Column2%24Column2%24topDeliveryControl%24deliveryButtonControl%24lnkExport&" + deliverString;

	return deliverString;
}

/*
 * given the text of the delivery page, downloads an item
 */
function downloadFunction(text) {

	//Zotero.debug("POSTTEXT="+text);
	var postLocation = /<form (?:autocomplete="o(?:ff|n)" )?name="aspnetForm" method="post" action="([^"]+)"/
	var postMatch = postLocation.exec(text);
	var deliveryURL = postMatch[1].replace(/&/g, "&");
	postMatch = customViewStateMatch.exec(text);
	var downloadString = "__EVENTTARGET=&__EVENTARGUMENT=&__CUSTOMVIEWSTATE="+fullEscape(postMatch[1])+"&__VIEWSTATE=&ctl00%24ctl00%24MainContentArea%24MainContentArea%24ctl00%24btnSubmit=Save&ctl00%24ctl00%24MainContentArea%24MainContentArea%24ctl00%24BibFormat=1&ajax=enabled";

	Zotero.Utilities.HTTP.doPost(host+"/ehost/"+deliveryURL,
								 downloadString, function(text) {	// get marked records as RIS
		Zotero.debug(text);
		// load translator for RIS
		if (text.match(/^AB\s\s\-/m)) text = text.replace(/^AB\s\s\-/m, "N2  -");
		if (!text.match(/^TY\s\s-/m)) text = text+"\nTY  - JOUR\n";
		// load translator for RIS
		var translator = Zotero.loadTranslator("import");
		translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
		translator.setString(text);
		translator.setHandler("itemDone", function(obj, item) {
			if (text.match(/^L3\s+-\s*(.*)/m)) {
				item.DOI = text.match(/^L3\s+\-\s*(.*)/m)[1];
			}
			if (text.match(/^M3\s+-\s*(.*)/m)) {
				if (item.DOI == text.match(/^M3\s+\-\s*(.*)/m)[1]) item.DOI = "";
			}
			if (text.match(/^DO\s+-\s*(.*)/m)) {
				item.DOI = text.match(/^DO\s+-\s*(.*)/m)[1];
			}
			if (text.match(/^T1\s+-/m)) {
				item.title = text.match(/^T1\s+-\s*(.*)/m)[1];
			}
			//item.itemType = "journalArticle";
			item.url = false;
			// RIS translator tries to download the link in "UR" this leads to unhappyness
			item.attachments = [];
			item.complete();

		});
		translator.translate();

		Zotero.done();
	});
}

function doWeb(doc, url) {
	var namespace = doc.documentElement.namespaceURI;
	var nsResolver = namespace ? function(prefix) {
		if (prefix == 'x') return namespace; else return null;
	} : null;

	var hostRe = new RegExp("^(https?://[^/]+)/");
	var hostMatch = hostRe.exec(url);
	host = hostMatch[1];

	var searchResult = doc.evaluate('//ul[@class="result-list" or @class="folder-list"]/li/div[@class="result-list-record" or @class="folder-item"]', doc, nsResolver,
	                                XPathResult.ANY_TYPE, null).iterateNext();

	if(searchResult) {
		var titlex = '//a[@class = "title-link color-p4"]';
		var titles = doc.evaluate(titlex, doc, nsResolver, XPathResult.ANY_TYPE, null);
		var items = new Object();
		var title;
		while (title = titles.iterateNext()) {
			items[title.href] = title.textContent;
		}

		var items = Zotero.selectItems(items);
		if(!items) {
			return true;
		}

		var uris = new Array();
		for(var i in items) {
			uris.push(i);
		}

		Zotero.Utilities.processDocuments(uris, function(newDoc){
			var postURL = newDoc.evaluate('//form[@name="aspnetForm"]/@action', newDoc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext();
			postURL = host+"/ehost/"+postURL.nodeValue;
			var deliverString = generateDeliverString(nsResolver, newDoc);
			Zotero.Utilities.HTTP.doPost(postURL, deliverString, downloadFunction);
		});
	} else {
		//This is a hack, generateDeliveryString is acting up for single pages, but it works on the plink url
		var link = [doc.evaluate("//input[@id ='pLink']/@value", doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext().nodeValue];
		Zotero.Utilities.processDocuments(link, function(newDoc){
			var postURL = newDoc.evaluate('//form[@name="aspnetForm"]/@action', newDoc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext();
			postURL = host+"/ehost/"+postURL.nodeValue;
			var deliverString = generateDeliverString(nsResolver, newDoc);
			Zotero.Utilities.HTTP.doPost(postURL, deliverString, downloadFunction);
		});

	}
	Zotero.wait();
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import H3 from 'components/H3'
import Divider from 'material-ui/Divider'
import LanguageSelector from 'components/LanguageSelector'
import { FormattedMessage } from 'react-intl'
import api from 'services'
import P from 'components/P'
import SoundPlayer from 'components/SoundPlayer'
import { LOCUTIONS_URL } from 'services/config'
import IconButton from 'material-ui/IconButton'
// import CloudDownloadIcon from 'material-ui/svg-icons/file/cloud-download'
import CloudDownloadIcon from 'material-ui/svg-icons/action/get-app'
import messages from './messages'

export default class RelatedWords extends Component {
  static propTypes = {
    language: PropTypes.string,
    idPictogram: PropTypes.number.isRequired,
    onLanguageChange: PropTypes.func.isRequired,
    onDownloadLocution: PropTypes.func.isRequired,
    style: PropTypes.object
  };

  state = {
    keywords: []
  };

  componentDidMount = () => {
    const { idPictogram, language } = this.props
    api.GET_KEYWORDS_BY_PICTOID({ language, idPictogram }).then((data) => {
      this.setState({ keywords: data.keywords })
    })
  };

  // getSoundPlayer = (idLocution, locale) => (
  //   <SoundPlayer
  //     crossOrigin='anonymous'
  //     streamUrl={`${LOCUTIONS_URL}/${locale}/${idLocution}`}
  //     preloadType='metadata'
  //     showProgress={false}
  //     showTimer={false}
  //   />
  // );

  getSoundPlayer = (hasLocution, locale, keyword, download) => {
    // split('/').join("\\\\") for pictos like 1/3, rewrote to 1\\3 for file system restrictions
    const streamUrl = hasLocution ? `${LOCUTIONS_URL}/${locale}/${encodeURIComponent(keyword.toLowerCase().split('/').join('\\\\'))}.mp3` : null
    return (

      {!download &&
        <SoundPlayer
          crossOrigin='anonymous'
          streamUrl={streamUrl}
          keyword={keyword}
          preloadType='metadata'
          showProgress={false}
          showTimer={false}
        />
      }

        {download && hasLocution && (
          <IconButton
            touch={true}
            onClick={
              () =>this.props.onDownloadLocution(locale, keyword)
            }
          >
            <CloudDownloadIcon/>
          </IconButton>
        )}

    )
  };

  handleLanguageChange = (language) => {
    const { idPictogram, onLanguageChange } = this.props
    onLanguageChange(language)
    api.GET_KEYWORDS_BY_PICTOID({ language, idPictogram }).then((data) => {
      this.setState({ keywords: data.keywords })
    })
  };

  render() {
    const { keywords } = this.state
    const { language, style } = this.props
    return (

{<FormattedMessage {...messages.description} />}

        <Divider />

{<FormattedMessage {...messages.changePictoLanguage} />}

        <LanguageSelector
          value={language}
          onChange={this.handleLanguageChange}
          shortOption={true}
          showToolTip={false}
        />
        {keywords &&
          keywords.map((keyword, index) => {
            return (

              <div key={`${keyword.keyword}-${index}`}>

                  {
                    this.getSoundPlayer(
                      keyword.hasLocution,
                      language,
                      keyword.keyword,
                      false
                    )}

                                      {
                    this.getSoundPlayer(
                      keyword.hasLocution,
                      language,
                      keyword.keyword,
                      true
                    )}

                    {keyword.keyword}{' '}

{keyword.meaning}

            )
          })}

    )
  }
}
<commit_msg>remove meaning<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import H3 from 'components/H3'
import Divider from 'material-ui/Divider'
import LanguageSelector from 'components/LanguageSelector'
import { FormattedMessage } from 'react-intl'
import api from 'services'
import P from 'components/P'
import SoundPlayer from 'components/SoundPlayer'
import { LOCUTIONS_URL } from 'services/config'
import IconButton from 'material-ui/IconButton'
// import CloudDownloadIcon from 'material-ui/svg-icons/file/cloud-download'
import CloudDownloadIcon from 'material-ui/svg-icons/action/get-app'
import messages from './messages'

export default class RelatedWords extends Component {
  static propTypes = {
    language: PropTypes.string,
    idPictogram: PropTypes.number.isRequired,
    onLanguageChange: PropTypes.func.isRequired,
    onDownloadLocution: PropTypes.func.isRequired,
    style: PropTypes.object
  };

  state = {
    keywords: []
  };

  componentDidMount = () => {
    const { idPictogram, language } = this.props
    api.GET_KEYWORDS_BY_PICTOID({ language, idPictogram }).then((data) => {
      this.setState({ keywords: data.keywords })
    })
  };

  // getSoundPlayer = (idLocution, locale) => (
  //   <SoundPlayer
  //     crossOrigin='anonymous'
  //     streamUrl={`${LOCUTIONS_URL}/${locale}/${idLocution}`}
  //     preloadType='metadata'
  //     showProgress={false}
  //     showTimer={false}
  //   />
  // );

  getSoundPlayer = (hasLocution, locale, keyword, download) => {
    // split('/').join("\\\\") for pictos like 1/3, rewrote to 1\\3 for file system restrictions
    const streamUrl = hasLocution ? `${LOCUTIONS_URL}/${locale}/${encodeURIComponent(keyword.toLowerCase().split('/').join('\\\\'))}.mp3` : null
    return (

      {!download &&
        <SoundPlayer
          crossOrigin='anonymous'
          streamUrl={streamUrl}
          keyword={keyword}
          preloadType='metadata'
          showProgress={false}
          showTimer={false}
        />
      }

        {download && hasLocution && (
          <IconButton
            touch={true}
            onClick={
              () =>this.props.onDownloadLocution(locale, keyword)
            }
          >
            <CloudDownloadIcon/>
          </IconButton>
        )}

    )
  };

  handleLanguageChange = (language) => {
    const { idPictogram, onLanguageChange } = this.props
    onLanguageChange(language)
    api.GET_KEYWORDS_BY_PICTOID({ language, idPictogram }).then((data) => {
      this.setState({ keywords: data.keywords })
    })
  };

  render() {
    const { keywords } = this.state
    const { language, style } = this.props
    return (

{<FormattedMessage {...messages.description} />}

        <Divider />

{<FormattedMessage {...messages.changePictoLanguage} />}

        <LanguageSelector
          value={language}
          onChange={this.handleLanguageChange}
          shortOption={true}
          showToolTip={false}
        />
        {keywords &&
          keywords.map((keyword, index) => {
            return (

              <div key={`${keyword.keyword}-${index}`}>

                  {
                    this.getSoundPlayer(
                      keyword.hasLocution,
                      language,
                      keyword.keyword,
                      false
                    )}

                                      {
                    this.getSoundPlayer(
                      keyword.hasLocution,
                      language,
                      keyword.keyword,
                      true
                    )}

                    {keyword.keyword}

            )
          })}

    )
  }
}
<|endoftext|>


<commit_before>(function (FMS, Backbone, _, $) {
    _.extend( FMS, {
        SearchView: FMS.FMSView.extend({
            template: 'address_search',
            id: 'search-page',

            events: {
                'click a.address': 'goAddress',
                'click #submit': 'search',
                'click #locate': 'goLocate',
                'pagehide': 'destroy',
                'pageshow': 'afterDisplay'
            },

            search: function() {
                var pc = this.$('#pc').val();
                this.listenTo(FMS.locator, 'search_located', this.searchSuccess );
                this.listenTo(FMS.locator, 'search_failed', this.searchFail);

                $('#ajaxOverlay').show();
                FMS.locator.lookup(pc);
            },

            searchSuccess: function( info ) {
                this.stopListening(FMS.locator);
                var coords = info.coordinates;
                FMS.currentLocation = coords;
                this.navigate('around');
            },

            goAddress: function(e) {
                var t = $(e.target);
                var lat = t.attr('data-lat');
                var long = t.attr('data-long');

                FMS.currentLocation = { latitude: lat, longitude: long };
                this.navigate('around');
            },

            searchFail: function( details ) {
                this.stopListening(FMS.locator);
                $('#ajaxOverlay').hide();
                if ( details.msg ) {
                    this.displayError( details.msg );
                } else if ( details.locations ) {
                    var multiple = '';
                    for ( var i = 0; i < details.locations.length; i++ ) {
                        var loc = details.locations[i];
                        var li = '
' + loc.address + '
';
                        multiple = multiple + li;
                    }
                    $('#front-howto').html('
' + multiple + '
');
                } else {
                    this.displayError( FMS.strings.location_problem );
                }
            },

            goLocate: function() {
                e.preventDefault();
                this.navigate( 'around' );
            },

            destroy: function() {
                delete FMS.searchMessage;
                this.stopListening(FMS.locator);
            }
        })
    });
})(FMS, Backbone, _, $);
<commit_msg>need to capture event in order to prevent default<commit_after>(function (FMS, Backbone, _, $) {
    _.extend( FMS, {
        SearchView: FMS.FMSView.extend({
            template: 'address_search',
            id: 'search-page',

            events: {
                'click a.address': 'goAddress',
                'click #submit': 'search',
                'click #locate': 'goLocate',
                'pagehide': 'destroy',
                'pageshow': 'afterDisplay'
            },

            search: function() {
                var pc = this.$('#pc').val();
                this.listenTo(FMS.locator, 'search_located', this.searchSuccess );
                this.listenTo(FMS.locator, 'search_failed', this.searchFail);

                $('#ajaxOverlay').show();
                FMS.locator.lookup(pc);
            },

            searchSuccess: function( info ) {
                this.stopListening(FMS.locator);
                var coords = info.coordinates;
                FMS.currentLocation = coords;
                this.navigate('around');
            },

            goAddress: function(e) {
                var t = $(e.target);
                var lat = t.attr('data-lat');
                var long = t.attr('data-long');

                FMS.currentLocation = { latitude: lat, longitude: long };
                this.navigate('around');
            },

            searchFail: function( details ) {
                this.stopListening(FMS.locator);
                $('#ajaxOverlay').hide();
                if ( details.msg ) {
                    this.displayError( details.msg );
                } else if ( details.locations ) {
                    var multiple = '';
                    for ( var i = 0; i < details.locations.length; i++ ) {
                        var loc = details.locations[i];
                        var li = '
' + loc.address + '
';
                        multiple = multiple + li;
                    }
                    $('#front-howto').html('
' + multiple + '
');
                } else {
                    this.displayError( FMS.strings.location_problem );
                }
            },

            goLocate: function(e) {
                e.preventDefault();
                this.navigate( 'around' );
            },

            destroy: function() {
                delete FMS.searchMessage;
                this.stopListening(FMS.locator);
            }
        })
    });
})(FMS, Backbone, _, $);
<|endoftext|>


<commit_before>let canvasSize = 600;
let padding = 20;
let newGameButton;
let gridCount = 5;

let board;
let clues = {
    cols: [],
    rows: []
};
let sizeField;
let colConfig, rowConfig;
let grid = []
let displayGrid = {
    rows: 0,
    cols: 0,
    size: (canvasSize / gridCount) - padding
}
const intParser = e => parseInt(e);

function setup()
{
    let span = createSpan("Grid Size")
    sizeField = createInput(gridCount, "text");
    sizeField.size(30);

    createSpan("cols:");
    colConfig = createInput("3,3,3 2,2 1 0 1", "text"); //createInput( "1,1 1 1,1 1,1 2,1", "text" );
    createSpan("rows:");
    rowConfig = createInput("1,2 1 1,2 0 2,1", "text");
    newGameButton = createButton("New Game");
    newGameButton.mousePressed(createNewGame);
    createCanvas(canvasSize, canvasSize);
    //Setup new game after elements are configured
    board = createNewGame();
}

function draw()
{
    background('white');
    board.draw( padding );
}

function createNewGame() {
    console.log('new game clicked');
    gridCount = parseInt(sizeField.value());
    let board = new Board( gridCount, {
        cols: parseConfigToArray(colConfig, gridCount),
        rows: parseConfigToArray(rowConfig, gridCount)
    });
    board.setDisplaySize( canvasSize, padding );
    console.log( 'board valid: ' + board.isValid());
    return board;
}

function parseConfigToArray(inputField, s) {
    let ret = [];
    let strArr = inputField.value().split(' ');
    for (let i = 0; i < s; i++) {
        if (i == 2)
            console.log(strArr[i].split(',').map(intParser));
        if (strArr[i] === undefined || strArr[i] === "0")
            ret.push([]);
        else
            ret.push(strArr[i].split(',').map(intParser));

    }
    let maxLen = ret.reduce(reducer, 0);
    ret.forEach(span => {
        while (span.length < maxLen) {
            span.unshift(null);
        }
    });

    return ret;
}<commit_msg>cleaned out unused vars and logging<commit_after>let canvasSize = 600;
let padding = 20;
let gridCount = 5;

let sizeField;
let newGameButton;
let colConfig, rowConfig;

let board;

const intParser = e => parseInt(e);

function setup()
{
    createSpan("Grid Size")
    sizeField = createInput(gridCount, "text");
    sizeField.size(30);

    createSpan("cols:");
    colConfig = createInput("3,3,3 2,2 1 0 1", "text"); //createInput( "1,1 1 1,1 1,1 2,1", "text" );
    createSpan("rows:");
    rowConfig = createInput("1,2 1 1,2 0 2,1", "text");
    newGameButton = createButton("New Game");
    newGameButton.mousePressed(createNewGame);
    createCanvas(canvasSize, canvasSize);
    //Setup new game after elements are configured
    board = createNewGame();
}

function draw()
{
    background('white');
    board.draw( padding );
}

function createNewGame() {
    console.log('new game clicked');
    gridCount = parseInt(sizeField.value());
    board = new Board( gridCount, {
        cols: parseConfigToArray(colConfig, gridCount),
        rows: parseConfigToArray(rowConfig, gridCount)
    });
    board.setDisplaySize( canvasSize, padding );
    return board;
}

function parseConfigToArray(inputField, s) {
    let ret = [];
    let strArr = inputField.value().split(' ');
    for (let i = 0; i < s; i++) {
        if (i >= strArr.length || strArr[i] === undefined || strArr[i] === "0")
                ret.push([]);
            else
                ret.push(strArr[i].split(',').map(intParser));

    }
    let maxLen = ret.reduce((acc, cur) => Math.max(acc, cur.length), 0);
    ret.forEach(span => {
        while (span.length < maxLen) {
            span.unshift(null);
        }
    });

    return ret;
}<|endoftext|>


<commit_before>
if( SUPPORT_FILTERS ) {
	var isChrome = root['chrome'];
	var _filters = {}, doc = root.document;

	if( !isChrome && !server ) {
		var DOMtext 	= doc.createTextNode(""),
			DOMelement 	= doc.createElement("span");
		DOMelement.appendChild( DOMtext );
	}

	var
		amp = /&/g,
		q1 	= /"/g,
		q2	= /'/g,
		t1	= />/g,
		t2	= /</g,
		sl 	= /\//g;

	Wzhik['e'] = _filters["escape"] = function( code ) {
		return isChrome
			? code
				.replace(amp, '&')
				.replace(t2, '<')
				.replace(t1, '>')
				.replace(q1, '"')
				.replace(q2, ''')
				.replace(sl,'/')
			: (DOMtext.nodeValue = code) && DOMelement.innerHTML;
	}

	Wzhik['f'] = _filters;
	Wzhik['addFilter'] = function(name, fn){
		_filters[name] = fn;
		return Wzhik
	}
}

if( IGNORE_NULLS ) {
	// Ignoring empty values
	// Example:
	// v(null) === ""
	// v(false) === ""
	// v(undefined) === ""
	// v(0) === 0
	Wzhik['v'] = function( value, templateID, lineNumber ){
		if( DEBUG ) {
			if( lineNumber ) {
				if( value === undefined ) {
    				console.warn(
    					"Undefined value: ",
    					variable, '===', value,
    					"in template", "#" +templateID,
    					"at line #", lineNumber,
    					"(", (_cacheOriginals[templateID][originalLineNumber] || "").trim(), ")");
    			}
			}
		}
		return (typeof value === "number" || value) ? value : "";
	}
}

// @todo perf test: array detection vs 2 functions for object and array
// Each function
Wzhik["each"] = function(subject, fn){
	for(
		var index = -1,
			isarr = subject instanceof Array,
			arr = isarr ? subject : Object.keys( subject ),
			length = arr.length,
			value, key, r, last = length - 1;
		++index < length;
	) {
		if ( isarr ) {
			value = arr[index];
			key = index;
		} else {
			key = arr[index];
			value = subject[key];
		}

		if((r = fn( value,  key, index === 0, index === last, index % 2)) === false){
			return r
		};
	}
}<commit_msg>isarray fallback<commit_after>

var isArray = Array.isArray || function(arg) {
    return toString.call(arg) === '[object Array]';
};

if( SUPPORT_FILTERS ) {
	var isChrome = root['chrome'];
	var _filters = {}, doc = root.document;

	if( !isChrome && !server ) {
		var DOMtext 	= doc.createTextNode(""),
			DOMelement 	= doc.createElement("span");
		DOMelement.appendChild( DOMtext );
	}

	var
		amp = /&/g,
		q1 	= /"/g,
		q2	= /'/g,
		t1	= />/g,
		t2	= /</g,
		sl 	= /\//g;

	Wzhik['e'] = _filters["escape"] = function( code ) {
		return isChrome
			? code
				.replace(amp, '&')
				.replace(t2, '<')
				.replace(t1, '>')
				.replace(q1, '"')
				.replace(q2, ''')
				.replace(sl,'/')
			: (DOMtext.nodeValue = code) && DOMelement.innerHTML;
	}

	Wzhik['f'] = _filters;
	Wzhik['addFilter'] = function(name, fn){
		_filters[name] = fn;
		return Wzhik
	}
}

if( IGNORE_NULLS ) {
	// Ignoring empty values
	// Example:
	// v(null) === ""
	// v(false) === ""
	// v(undefined) === ""
	// v(0) === 0
	Wzhik['v'] = function( value, templateID, lineNumber ){
		if( DEBUG ) {
			if( lineNumber ) {
				if( value === undefined ) {
    				console.warn(
    					"Undefined value: ",
    					variable, '===', value,
    					"in template", "#" +templateID,
    					"at line #", lineNumber,
    					"(", (_cacheOriginals[templateID][originalLineNumber] || "").trim(), ")"
    				);
    			}
			}
		}
		return (typeof value === "number" || value) ? value : "";
	}
}

// @todo perf test: array detection vs 2 functions for object and array
// Each function
Wzhik["each"] = function(subject, fn){
	for(
		var index = -1,
			isarr = subject instanceof Array,
			arr = isarr ? subject : Object.keys( subject ),
			length = arr.length,
			value, key, r, last = length - 1;
		++index < length;
	) {
		if ( isarr ) {
			value = arr[index];
			key = index;
		} else {
			key = arr[index];
			value = subject[key];
		}

		if((r = fn( value,  key, index === 0, index === last, index % 2)) === false){
			return r
		};
	}
}<|endoftext|>