<commit_before>var $ = require('jquery');
var Event = require('./Event');
var City = require('./City');
var languages = require('./lang');

/**
 * @param {Object} eventsData Raw events data
 * @param {Object} citiesData Raw cities data
 * @constructor
 */
function EventsStore(eventsData, citiesData) {
  var store = this;
  this.events = [];
  this.cities = [];

  var citiesNames = citiesData.map(function(data) {
    return data.name;
  });

  var citiesMissedInDict = [];

  eventsData
    .filter(function (data) { return typeof data.location !== 'undefined'; })
    .map(function (data) { return data.location; })
    .filter(function (value, index, self) { return self.indexOf(value) === index; })
    .forEach(function(eventCity) {
      if (citiesNames.indexOf(eventCity) === -1) {
        citiesMissedInDict.push(eventCity);
      }
    });

  if (citiesMissedInDict.length > 0) {
    console.warn('Cities missed in cities.yml:\n' + citiesMissedInDict.join('\n'));
  }

  citiesData.forEach(function (data) {
    store.cities.push(new City(data));
  });

  eventsData.forEach(function (data, i) {
    var eventCityExistInDict = data.location && citiesNames.indexOf(data.location) !== -1;

    if (!eventCityExistInDict) {
      return;
    }

    data.id = i.toString();
    store.events.push(new Event(data));
  });

  store.events.forEach(function (event) {
    var eventCity = store.cities.filter(function (city) {
      return city.name == event.city;
    })[0];

    event.city = eventCity;
  });

  this.sort();
}

/**
 * @static
 * @param {string} eventsUrl
 * @param {string} citiesUrl
 * @returns {Deferred}
 */
EventsStore.create = function (eventsUrl, citiesUrl) {
  var events;
  var cities;

  return $.getJSON(eventsUrl)
    .then(function (result) { events = result })
    .then(function () { return $.getJSON(citiesUrl) })
    .then(function (result) { cities = result })
    .then(function () { return new EventsStore(events, cities) })
};

/**
 * @static
 */
EventsStore.filters = {
  time: function (time, event) {
    var isMatch = false;
    if (time == 'upcoming')
      isMatch = event.isUpcoming();
    else if (time == 'past')
      isMatch = !event.isUpcoming();
    else
      isMatch = true;

    return isMatch;
  },

  lang: function (lang, event) {
    return event.lang == lang;
  },

  materials: function (materialType, event) {
    return event.content && event.content.hasOwnProperty(materialType);
  },

  bounds: function (bounds, event) {
    return bounds.contains(event.getBounds());
  }
};

/**
 * @static
 */
EventsStore.materialsDict = {
  examples: 'Examples',
  slides: 'Slides',
  video: 'Video',
  pdf: 'PDF',
  article: 'Article'
};

EventsStore.prototype.sort = function () {
  this.events.sort(function (a, b) {
    var compareA = a.endDate;
    var compareB = b.endDate;

    if (compareA === compareB) {
      return 0;
    }

    return (compareA < compareB) ? 1 : -1;
  });
};

/**
 * @param {Array<Event>} [events]
 * @returns {Array<Event>}
 */
EventsStore.prototype.getUpcomingEvents = function (events) {
  var events = events || this.events;
  return events.filter(function (event) {
    return event.isUpcoming();
  });
};

/**
 * @param {Array<Event>} [events]
 * @returns {Array<Event>}
 */
EventsStore.prototype.getPastEvents = function (events) {
  var events = events || this.events;
  return events.filter(function (event) {
    return !event.isUpcoming();
  });
};

/**
 * @param {Object} constraints
 * @param {string} constraints.time
 * @param {string} constraints.lang
 * @param {string} constraints.materials
 * @param {google.maps.LatLng} constraints.bounds
 * @param {Array<Event>} [events]
 * @returns {Array<Event>}
 */
EventsStore.prototype.filter = function (constraints, events) {
  var events = events || this.events;
  var filtered = [];
  var constraintNames = Object.keys(constraints);

  events.forEach(function (event) {
    var performedConstraintsCount = 0;

    constraintNames.forEach(function (name) {
      var constraint = constraints[name];
      var filter = EventsStore.filters[name];
      if (filter(constraint, event)) {
        performedConstraintsCount++;
      }
    });

    if (performedConstraintsCount == constraintNames.length)
      filtered.push(event);
  });

  return filtered;
};

/**
 * @returns {Object<string, string>}
 */
EventsStore.prototype.getLanguages = function () {
  var idsList = $.unique( this.events.map(function(event){ return event.lang }) );
  var map = {};

  idsList.forEach(function (langId) {
    if (langId in languages) {
      map[langId] = languages[langId].name;
    }
  });

  return map;
};

/**
 * @see EventsStore.materialsDict
 * @returns {Object<string, string>}
 */
EventsStore.prototype.getMaterials = function () {
  var list = [];

  this.events.forEach(function (event) {
    if (event.content) {
      list = list.concat(Object.keys(event.content));
    }
  });

  var listMap = {};
  list = $.unique(list);
  list.forEach(function (materialId) {
    listMap[materialId] = EventsStore.materialsDict[materialId];
  });

  return listMap;
};

module.exports = EventsStore;<commit_msg>Events page: upcoming events sorted ascending<commit_after>var $ = require('jquery');
var Event = require('./Event');
var City = require('./City');
var languages = require('./lang');

/**
 * @param {Object} eventsData Raw events data
 * @param {Object} citiesData Raw cities data
 * @constructor
 */
function EventsStore(eventsData, citiesData) {
  var store = this;
  this.events = [];
  this.cities = [];

  var citiesNames = citiesData.map(function(data) {
    return data.name;
  });

  var citiesMissedInDict = [];

  eventsData
    .filter(function (data) { return typeof data.location !== 'undefined'; })
    .map(function (data) { return data.location; })
    .filter(function (value, index, self) { return self.indexOf(value) === index; })
    .forEach(function(eventCity) {
      if (citiesNames.indexOf(eventCity) === -1) {
        citiesMissedInDict.push(eventCity);
      }
    });

  if (citiesMissedInDict.length > 0) {
    console.warn('Cities missed in cities.yml:\n' + citiesMissedInDict.join('\n'));
  }

  citiesData.forEach(function (data) {
    store.cities.push(new City(data));
  });

  eventsData.forEach(function (data, i) {
    var eventCityExistInDict = data.location && citiesNames.indexOf(data.location) !== -1;

    if (!eventCityExistInDict) {
      return;
    }

    data.id = i.toString();
    store.events.push(new Event(data));
  });

  store.events.forEach(function (event) {
    var eventCity = store.cities.filter(function (city) {
      return city.name == event.city;
    })[0];

    event.city = eventCity;
  });

  this.sort();
}

/**
 * @static
 * @param {string} eventsUrl
 * @param {string} citiesUrl
 * @returns {Deferred}
 */
EventsStore.create = function (eventsUrl, citiesUrl) {
  var events;
  var cities;

  return $.getJSON(eventsUrl)
    .then(function (result) { events = result })
    .then(function () { return $.getJSON(citiesUrl) })
    .then(function (result) { cities = result })
    .then(function () { return new EventsStore(events, cities) })
};

/**
 * @static
 */
EventsStore.filters = {
  time: function (time, event) {
    var isMatch = false;
    if (time == 'upcoming')
      isMatch = event.isUpcoming();
    else if (time == 'past')
      isMatch = !event.isUpcoming();
    else
      isMatch = true;

    return isMatch;
  },

  lang: function (lang, event) {
    return event.lang == lang;
  },

  materials: function (materialType, event) {
    return event.content && event.content.hasOwnProperty(materialType);
  },

  bounds: function (bounds, event) {
    return bounds.contains(event.getBounds());
  }
};

/**
 * @static
 */
EventsStore.materialsDict = {
  examples: 'Examples',
  slides: 'Slides',
  video: 'Video',
  pdf: 'PDF',
  article: 'Article'
};

EventsStore.prototype.sort = function () {
  this.events.sort(function (a, b) {
    var compareA = a.endDate;
    var compareB = b.endDate;

    if (compareA === compareB) {
      return 0;
    }

    return (compareA < compareB) ? 1 : -1;
  });
};

/**
 * @param {Array<Event>} [events]
 * @returns {Array<Event>}
 */
EventsStore.prototype.getUpcomingEvents = function (events) {
  var events = events || this.events;
  return events.filter(function (event) {
    return event.isUpcoming();
  }).sort(function(eventA, eventB) {
    var startA = eventA.startDate;
    var startB = eventB.startDate;

    if (startA === startB) {
      return 0;
    }

    return startA < startB ? -1 : 1;
  });
};

/**
 * @param {Array<Event>} [events]
 * @returns {Array<Event>}
 */
EventsStore.prototype.getPastEvents = function (events) {
  var events = events || this.events;
  return events.filter(function (event) {
    return !event.isUpcoming();
  });
};

/**
 * @param {Object} constraints
 * @param {string} constraints.time
 * @param {string} constraints.lang
 * @param {string} constraints.materials
 * @param {google.maps.LatLng} constraints.bounds
 * @param {Array<Event>} [events]
 * @returns {Array<Event>}
 */
EventsStore.prototype.filter = function (constraints, events) {
  var events = events || this.events;
  var filtered = [];
  var constraintNames = Object.keys(constraints);

  events.forEach(function (event) {
    var performedConstraintsCount = 0;

    constraintNames.forEach(function (name) {
      var constraint = constraints[name];
      var filter = EventsStore.filters[name];
      if (filter(constraint, event)) {
        performedConstraintsCount++;
      }
    });

    if (performedConstraintsCount == constraintNames.length)
      filtered.push(event);
  });

  return filtered;
};

/**
 * @returns {Object<string, string>}
 */
EventsStore.prototype.getLanguages = function () {
  var idsList = $.unique( this.events.map(function(event){ return event.lang }) );
  var map = {};

  idsList.forEach(function (langId) {
    if (langId in languages) {
      map[langId] = languages[langId].name;
    }
  });

  return map;
};

/**
 * @see EventsStore.materialsDict
 * @returns {Object<string, string>}
 */
EventsStore.prototype.getMaterials = function () {
  var list = [];

  this.events.forEach(function (event) {
    if (event.content) {
      list = list.concat(Object.keys(event.content));
    }
  });

  var listMap = {};
  list = $.unique(list);
  list.forEach(function (materialId) {
    listMap[materialId] = EventsStore.materialsDict[materialId];
  });

  return listMap;
};

module.exports = EventsStore;<|endoftext|>


<commit_before>var script = document.createElement('script');
script.src = 'js/jquery-3.2.1.min.js';
script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script);

var contextMenuItem = {
  "id": "searchWord",
  "title": "Search Word",
  "contexts": ["selection"]
};

chrome.contextMenus.create(contextMenuItem);

function parseDictCCEntry(entry) {
  // given a HTML DOM  object in dict.cc of class 'td7nl',
  // get the innerText of its children attribute tags, and
  // add the words to an array.
  //
  // Return a concatenated string of innerText of
  // within .
  var entryWords = [];
  var entryAttributes = $(entry).find('a').filter('a');

  for (var i=0; i<entryAttributes.length; i++) {
    entryWords.push(entryAttributes[i].innerText);
  }
  return entryWords.join(' ');
}

chrome.contextMenus.onClicked.addListener(function(clickData, tab) {
  if (clickData.menuItemId == "searchWord" && clickData.selectionText && tab)
  {
    var query = clickData.selectionText;
    var url_dictcc = "http://www.dict.cc/?s=" + query;
    var url_linguee = "https://www.linguee.com/english-german/search?query=" + query;
    var parsed_html = null;

    // use AJAX to get HTML of dictionary query
    $.get(url_dictcc, function(data, status) {
      // scrape content table
      var content_table =  $($.parseHTML(data)).filter("#maincontent").find('table');
      // scrape definition rows
      var content_rows = $(content_table[2]).find('tbody').find('tr').filter(function() {
        return this.id.match(/tr[0-9]+/)
      });

      console.log("Found " + content_rows.length + " translations.");

      var i, j;
      var text = [];
      for (i=0; i<content_rows.length; i++) {
        text.push($(content_rows[i]).find('td').filter(function() {
          return this.className.match('td7nl')
        }));
        //console.log(text[text.length-1]);
        for (j=0; j<2; j++) { // index 0 is the English entry, entry 1 is the German entry
          // number of words in the entry
          console.log(text[text.length-1][j]);
          text[text.length-1][j] = parseDictCCEntry(text[text.length-1][j]);
          //text[text.length-1][j] = ($(text[text.length-1][j]).find('a'))[0].innerText;
        }
        console.log(text[text.length-1]);
      }

      // inject code into active tab
      chrome.tabs.executeScript(tab.id, { file: "js/sidebar.js" }, function() {
        chrome.tabs.sendMessage(tab.id, text);
      });
    });
  }
});

<commit_msg>refactor: use Promise.all and AJAX to get and parse page content on dict.cc and linguee.com asynchronously<commit_after>var script = document.createElement('script');
script.src = 'js/jquery-3.2.1.min.js';
script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script);

var contextMenuItem = {
  "id": "searchWord",
  "title": "Search Word",
  "contexts": ["selection"]
};

chrome.contextMenus.create(contextMenuItem);

function parseDictCCEntry(entry) {
  // given a HTML DOM  object in dict.cc of class 'td7nl',
  // get the innerText of its children attribute tags, and
  // add the words to an array.
  //
  // Return a concatenated string of innerText of
  // within .
  var entryWords = [];
  var entryAttributes = $(entry).find('a').filter('a');

  for (var i=0; i<entryAttributes.length; i++) {
    entryWords.push(entryAttributes[i].innerText);
  }
  return entryWords.join(' ');
}

function parseDictCC(data) {
  // parse the DOM (data) for dictionary entries.
  // Returns an array of [English, German] array entries.

  var text = [];

  // scrape content table
  var content_table =  $($.parseHTML(data)).filter("#maincontent").find('table');

  // scrape definition rows
  var content_rows = $(content_table[2]).find('tbody').find('tr').filter(function() {
    return this.id.match(/tr[0-9]+/)
  });

  console.log("Found " + content_rows.length + " translations.");

  var i, j;
  for (i=0; i<content_rows.length; i++) {
    // first add relevant DOM objects to `text` array
    text.push($(content_rows[i]).find('td').filter(function() {
      //  tags with class 'td7nl' contain dictionary entries
      return this.className.match('td7nl')
    }));

    // now parse the DOM object for innerText,
    // and replace object with string (dictionary entries)
    for (j=0; j<2; j++) {
      // index 0 is the English, entry 1 is the German entry
      text[text.length-1][j] = parseDictCCEntry(text[text.length-1][j]);
      console.log(text[text.length-1]);
    }
  }
  console.log('Finished parsing DictCC.');
  return text;
}

function getData(url, parse) {
  // get the page content using AJAX

  return new Promise((resolve, reject) => {
    $.get(url)
    .done((data) => {
      console.log('Success: got data from ' + url);
      resolve(data); // resolve the promise if data is retrieved
    })
    .fail((xhr, status, err) => {
      console.log('Failed to get data from ' + url);
      reject(status + err.message);
    });
  });
}

function parseLinguee(data) {
  var text = [];
  console.log('Finished parsing Linguee.');
  return text;
}

function displayEntries(url_dictcc, url_linguee, tabId) {

  // have a getData generic function that $.gets the url content,
  // and then if success, apply the callback parseDictCC on the data
  // returned.
  Promise.all([
    getData(url_dictcc),
    getData(url_linguee)
  ])
  .then((datas) => {
    return [parseDictCC(datas[0]), parseLinguee(datas[1])]
  })
  .then((entries) => {
    chrome.tabs.executeScript(
      tabId,
      { file: "js/sidebar.js" },
      chrome.tabs.sendMessage(tabId, entries)
    );
  })
  .catch((error) => {
    console.log('Woops! ' + error.message);
  });

  // $.when(
  //   // wait for AJAX to scrape the two webpages
  //   getDictCcEntries(url_dictcc),
  //   getLingueeEntries(url_linguee)

  // ).then(function(dictcc_entries, linguee_entries) {
  //   // inject sidebar into active tab
  //   // use Chrome message API to pass entry arrays to js/sidebar.js
  //   console.log('Executing script after AJAX');
  //   chrome.tabs.executeScript(tabId, { file: "js/sidebar.js" }, function() {
  //     chrome.tabs.sendMessage(tabId, dictcc_entries);
  //   });
  // });
}

chrome.contextMenus.onClicked.addListener(function(clickData, tab) {
  if (clickData.menuItemId == "searchWord" && clickData.selectionText && tab)
  {
    var query = clickData.selectionText;
    var url_dictcc = "http://www.dict.cc/?s=" + query;
    var url_linguee = "https://www.linguee.com/english-german/search?query=" + query;

    displayEntries(url_dictcc, url_linguee, tab.id);
  }
});

<|endoftext|>


<commit_before>/*
    ***** BEGIN LICENSE BLOCK *****

    Copyright © 2009 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org

    This file is part of Zotero.

    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.

    ***** END LICENSE BLOCK *****
*/

Zotero.Translate.ItemSaver = function(libraryID, attachmentMode, forceTagType) {
	this.newItems = [];

	this._itemsToSaveToServer = [];
	this._timeoutID = null;
}

Zotero.Translate.ItemSaver.ATTACHMENT_MODE_IGNORE = 0;
Zotero.Translate.ItemSaver.ATTACHMENT_MODE_DOWNLOAD = 1;
Zotero.Translate.ItemSaver.ATTACHMENT_MODE_FILE = 2;

Zotero.Translate.ItemSaver.prototype = {
	"saveItem":function(item) {
		// don't save documents as documents, since we can't pass them around
		for(var i in item.attachments) {
			if(item.attachments[i].document) {
				item.attachments[i].url = item.attachments[i].document.location.href;
				delete item.attachments[i].document;
			}
		}

		// save items
		this.newItems.push(item);
		var me = this;
		Zotero.Connector.callMethod("saveItems", {"items":[item]}, function(success) {
			if(success === false && !Zotero.isFx) {
				// attempt to save to server on a timer
				if(me._timeoutID) clearTimeout(me._timeoutID);
				me._itemsToSaveToServer.push(item);
				me._timeoutID = setTimeout(function() { me._saveToServer() }, 2000);
			}
		});
	},

	"_saveToServer":function() {
		const IGNORE_FIELDS = ["seeAlso", "attachments", "complete"];

		// clear timeout, since saving has begin
		this._timeoutID = null;

		var newItems = new Array(this._itemsToSaveToServer.length);
		for(var i in this._itemsToSaveToServer) {
			var item = this._itemsToSaveToServer[i];
			var newItem = newItems[i] = {};

			var typeID = Zotero.ItemTypes.getID(item.itemType);
			var fieldID;
			for(var field in item) {
				if(IGNORE_FIELDS.indexOf(field) !== -1) continue;

				var val = item[field];

				if(field === "itemType") {
					newItem[field] = val;
				} else if(field === "creators") {
					// TODO normalize
					newItem[field] = val;
				} else if(field === "tags") {
					var newTags = [];
					for(var j in val) {
						var tag = val[j];
						if(typeof tag === "object") {
							if(tag.tag) {
								tag = tag.tag;
							} else if(tag.name) {
								tag = tag.name;
							} else {
								continue;
							}
						}
						newTags.push({tag:tag.toString(), type:1})
					}
					newItem.tags = newTags;
				} else if(field === "notes") {
					// TODO normalize
					newItem[field] = val;
				} else if(fieldID = Zotero.ItemFields.getID(field)) {
					// if content is not a string, either stringify it or delete it
					if(typeof val !== "string") {
						if(val || val === 0) {
							val = val.toString();
						} else {
							continue;
						}
					}

					// map from base field if possible
					var itemFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(typeID, fieldID);
					if(itemFieldID) {
						newItem[Zotero.ItemFields.getName(itemFieldID)] = val;
						continue;	// already know this is valid
					}

					// if field is valid for this type, set field
					if(Zotero.ItemFields.isValidForType(fieldID, typeID)) {
						newItem[field] = val;
					} else {
						Zotero.debug("Translate: Discarded field "+field+": field not valid for type "+item.itemType, 3);
					}
				} else if(field !== "complete") {
					Zotero.debug("Translate: Discarded unknown field "+field, 3);
				}
			}
		}

		var url = 'users/%%USERID%%/items?key=%%APIKEY%%';
		var payload = JSON.stringify({"items":newItems}, null, "\t")
		this._itemsToSaveToServer = [];

		Zotero.OAuth.doAuthenticatedPost(url, payload, function(status, message) {
			if(!status) {
				Zotero.Messaging.sendMessage("saveDialog_error", status);
				Zotero.debug("Translate: Save to server payload:\n\n"+payload);
				throw new Error("Translate: Save to server failed: "+message);
			} else {
				Zotero.debug("Translate: Save to server complete");
			}
		}, true);
	}
};<commit_msg>Normalize notes and creators<commit_after>/*
    ***** BEGIN LICENSE BLOCK *****

    Copyright © 2009 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org

    This file is part of Zotero.

    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.

    ***** END LICENSE BLOCK *****
*/

Zotero.Translate.ItemSaver = function(libraryID, attachmentMode, forceTagType) {
	this.newItems = [];

	this._itemsToSaveToServer = [];
	this._timeoutID = null;
}

Zotero.Translate.ItemSaver.ATTACHMENT_MODE_IGNORE = 0;
Zotero.Translate.ItemSaver.ATTACHMENT_MODE_DOWNLOAD = 1;
Zotero.Translate.ItemSaver.ATTACHMENT_MODE_FILE = 2;

Zotero.Translate.ItemSaver.prototype = {
	"saveItem":function(item) {
		// don't save documents as documents, since we can't pass them around
		for(var i in item.attachments) {
			if(item.attachments[i].document) {
				item.attachments[i].url = item.attachments[i].document.location.href;
				delete item.attachments[i].document;
			}
		}

		// save items
		this.newItems.push(item);
		var me = this;
		Zotero.Connector.callMethod("saveItems", {"items":[item]}, function(success) {
			if(success === false && !Zotero.isFx) {
				// attempt to save to server on a timer
				if(me._timeoutID) clearTimeout(me._timeoutID);
				me._itemsToSaveToServer.push(item);
				me._timeoutID = setTimeout(function() { me._saveToServer() }, 2000);
			}
		});
	},

	"_saveToServer":function() {
		const IGNORE_FIELDS = ["seeAlso", "attachments", "complete"];

		// clear timeout, since saving has begin
		this._timeoutID = null;

		var newItems = [];
		for(var i in this._itemsToSaveToServer) {
			var item = this._itemsToSaveToServer[i];

			var newItem = {};
			newItems.push(newItem);

			var typeID = Zotero.ItemTypes.getID(item.itemType);
			if(!typeID) {
				Zotero.debug("Translate: Invalid itemType "+item.itemType+"; saving as webpage");
				item.itemType = "webpage";
				typeID = Zotero.ItemTypes.getID(item.itemType);
			}

			var fieldID;
			for(var field in item) {
				if(IGNORE_FIELDS.indexOf(field) !== -1) continue;

				var val = item[field];

				if(field === "itemType") {
					newItem[field] = val;
				} else if(field === "creators") {
					// normalize creators
					var newCreators = newItem.creators = [];
					for(var j in val) {
						var creator = val[j];

						// Single-field mode
						if (creator.fieldMode && creator.fieldMode == 1) {
							var newCreator = {
								lastName: creator.lastName,
								fieldMode: 1
							};
						}
						// Two-field mode
						else {
							var newCreator = {
								firstName: creator.firstName,
								lastName: creator.lastName
							};
						}

						// ensure creatorType is present and valid
						newCreator.creatorType = "author";
						if(creator.creatorType) {
							if(Zotero.CreatorTypes.getID(creator.creatorType)) {
								newCreator.creatorType = creator.creatorType;
							} else {
								Zotero.debug("Translate: Invalid creator type "+creator.creatorType+"; falling back to author");
							}
						}

						newCreators.push(newCreator);
					}
				} else if(field === "tags") {
					// normalize tags
					var newTags = newItem.tags = [];
					for(var j in val) {
						var tag = val[j];
						if(typeof tag === "object") {
							if(tag.tag) {
								tag = tag.tag;
							} else if(tag.name) {
								tag = tag.name;
							} else {
								Zotero.debug("Translate: Discarded invalid tag");
								continue;
							}
						}
						newTags.push({"tag":tag.toString(), "type":1})
					}
				} else if(field === "notes") {
					// normalize notes
					var newNotes = newItem.notes = [];
					for(var j in val) {
						var note = val[j];
						if(typeof note === "object") {
							if(!note.note) {
								Zotero.debug("Translate: Discarded invalid note");
								continue;
							}
							note = note.note;
						}
						newNotes.push({"itemType":"note", "note":note.toString()});
					}
				} else if(fieldID = Zotero.ItemFields.getID(field)) {
					// if content is not a string, either stringify it or delete it
					if(typeof val !== "string") {
						if(val || val === 0) {
							val = val.toString();
						} else {
							continue;
						}
					}

					// map from base field if possible
					var itemFieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(typeID, fieldID);
					if(itemFieldID) {
						newItem[Zotero.ItemFields.getName(itemFieldID)] = val;
						continue;	// already know this is valid
					}

					// if field is valid for this type, set field
					if(Zotero.ItemFields.isValidForType(fieldID, typeID)) {
						newItem[field] = val;
					} else {
						Zotero.debug("Translate: Discarded field "+field+": field not valid for type "+item.itemType, 3);
					}
				} else if(field !== "complete") {
					Zotero.debug("Translate: Discarded unknown field "+field, 3);
				}
			}
		}

		var url = 'users/%%USERID%%/items?key=%%APIKEY%%';
		var payload = JSON.stringify({"items":newItems}, null, "\t")
		this._itemsToSaveToServer = [];

		Zotero.OAuth.doAuthenticatedPost(url, payload, function(status, message) {
			if(!status) {
				Zotero.Messaging.sendMessage("saveDialog_error", status);
				Zotero.debug("Translate: Save to server payload:\n\n"+payload);
				Zotero.logError(new Error("Translate: Save to server failed: "+message));
			} else {
				Zotero.debug("Translate: Save to server complete");
			}
		}, true);
	}
};<|endoftext|>


<commit_before>// server.js

"use strict";

const jsonServer = require('json-server');
const server = jsonServer.create();
const router = jsonServer.router('app/db.json')
const middlewares = jsonServer.defaults({
  static: "app/"
});

const path = require("path");

const PORT = 3000;
const HOST_NAME = "localhost";
const HOST = `${HOST_NAME}:${PORT}`;

// To handle POST, PUT and PATCH you need to use a body-parser
// You can use the one used by JSON Server
server.use(jsonServer.bodyParser);

// Set default middlewares (logger, static, cors and no-cache)
server.use(middlewares);

// Use default router
server.use("/api", router);

// Add custom routes before JSON Server router
server.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, "app/index.html"));
})

server.listen(PORT, () => {
  console.log(`JSON Server is running on ${HOST}`);
});
<commit_msg>Edit path to index.html<commit_after>// server.js

"use strict";

const jsonServer = require('json-server');
const server = jsonServer.create();
const router = jsonServer.router('app/db.json')
const middlewares = jsonServer.defaults({
  static: "app/"
});

const path = require("path");

const PORT = 3000;
const HOST_NAME = "localhost";
const HOST = `${HOST_NAME}:${PORT}`;

// To handle POST, PUT and PATCH you need to use a body-parser
// You can use the one used by JSON Server
server.use(jsonServer.bodyParser);

// Set default middlewares (logger, static, cors and no-cache)
server.use(middlewares);

// Use default router
server.use("/api", router);

// Add custom routes before JSON Server router
server.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, "app/assets/index.html"));
})

server.listen(PORT, () => {
  console.log(`JSON Server is running on ${HOST}`);
});
<|endoftext|>


<commit_before>define([
	'vue',
	'text!components/list/list.tpl',
	'jquery'
],function(vue,tpl,$){
	var component = vue.extend({
		components : {

		},
		data : function(){
			return {
				id : '',
				emails : [
					/*{'name':'table layout布局样式一','value':'请先用这个table做第一次布局','type':'tableLay','col':1,'row':1},*/
					{'name':'table布局样式一','value':'一行一列','type':'table','col':1,'row':1},
					{'name':'table布局样式二','value':'一行两列','type':'table','col':2,'row':1},
					{'name':'table布局样式三','value':'一行三列','type':'table','col':3,'row':1},
					{'name':'table布局样式四','value':'一行四列','type':'table','col':4,'row':1},
					{'name':'table布局样式五','value':'一行六列','type':'table','col':6,'row':1},
					{'name':'table布局样式六','value':'一行八列','type':'table','col':8,'row':1}
				],
				modules : [
					{'name':'头部的Logo','value':'头部的Logo','type':'headerLogo'}
				],
				components : [
					{'name':'标题','value':'标题','type':'title'},
					{'name':'描述','value':'描述','type':'description'},
					{'name':'段落','value':'段落','type':'paragraph'},
					{'name':'图片','value':'图片','type':'img'},
					{'name':'链接','value':'链接','type':'link'},
					{'name':'列表','value':'列表','type':'itemList'},
					{'name':'按钮','value':'按钮','type':'button'}
				],
				showModal : false
			};
		},
		template : tpl,
		methods : {
			hideModal : function($event){
				this.showModal = false;
			},
			addComponent : function($event){
				var $target = $($event.target),
					$parent = $target.closest('.u-view');
				var _data = {
					type : $parent.data('type'),
					col  : $parent.data('col'),
					row  : $parent.data('row')
				};
				this.$dispatch('insertComponent',_data);
			}
		},
		events : {
			showModal : function(flag){
				this.showModal = flag;
			}
		}
	});

	vue.component('list-view',component);

	return component;
});<commit_msg>misc:v 1.0.0<commit_after>define([
	'vue',
	'text!components/list/list.tpl',
	'jquery'
],function(vue,tpl,$){
	var component = vue.extend({
		components : {

		},
		data : function(){
			return {
				id : '',
				emails : [
					{'name':'table布局样式一','value':'一行一列','type':'table','col':1,'row':1},
					{'name':'table布局样式二','value':'一行两列','type':'table','col':2,'row':1},
					{'name':'table布局样式三','value':'一行三列','type':'table','col':3,'row':1},
					{'name':'table布局样式四','value':'一行四列','type':'table','col':4,'row':1},
					{'name':'table布局样式五','value':'一行六列','type':'table','col':6,'row':1},
					{'name':'table布局样式六','value':'一行八列','type':'table','col':8,'row':1}
				],
				modules : [
					{'name':'头部的Logo','value':'头部的Logo','type':'headerLogo'}
				],
				components : [
					{'name':'标题','value':'标题','type':'title'},
					{'name':'描述','value':'描述','type':'description'},
					{'name':'段落','value':'段落','type':'paragraph'},
					{'name':'图片','value':'图片','type':'img'},
					{'name':'链接','value':'链接','type':'link'},
					{'name':'列表','value':'列表','type':'itemList'},
					{'name':'按钮','value':'按钮','type':'button'}
				],
				showModal : false
			};
		},
		template : tpl,
		methods : {
			hideModal : function($event){
				this.showModal = false;
			},
			addComponent : function($event){
				var $target = $($event.target),
					$parent = $target.closest('.u-view');
				var _data = {
					type : $parent.data('type'),
					col  : $parent.data('col'),
					row  : $parent.data('row')
				};
				this.$dispatch('insertComponent',_data);
			}
		},
		events : {
			showModal : function(flag){
				this.showModal = flag;
			}
		}
	});

	vue.component('list-view',component);

	return component;
});<|endoftext|>


<commit_before>define(['angular', 'map', 'toolbar'],

    function(angular) {
        angular.module('hs.query', ['hs.map', 'hs.toolbar'])
            .directive('infopanel', function() {
                return {
                    templateUrl: hsl_path + 'components/query/partials/infopanel.html'
                };
            }).service("WmsGetFeatureInfo", ['$http',
                function($http) {
                    this.request = function(url) {
                        var url = window.escape(url);
                        $http.get("/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + url).success(this.featureInfoReceived);
                    };

                }
            ]).service("InfoPanelService", ['$rootScope',
                function($rootScope) {
                    var me = {
                        //Used for tool specific info, such as lodexplorer region names and values
                        attributes: [],
                        //Used for getfeatureinfo. There exists a seperate group for each feature which is found at the specific coordinates
                        groups: [],
                        setAttributes: function(j) {
                            me.attributes = j;
                            $rootScope.$broadcast('infopanel.updated');
                        },
                        setGroups: function(j) {
                            me.groups = j;
                            $rootScope.$broadcast('infopanel.updated');
                        }
                    };

                    return me;
                }
            ])

        .controller('Query', ['$scope', 'OlMap', 'WmsGetFeatureInfo', 'InfoPanelService', 'ToolbarService',
            function($scope, OlMap, WmsGetFeatureInfo, InfoPanelService, ToolbarService) {
                var map = OlMap.map;
                $scope.myname = "shady";
                $scope.InfoPanelService = InfoPanelService;

                var point_clicked = new ol.geom.Point([0, 0]);
                var lyr = null;

                $scope.$on('layermanager.updated', function(event) {
                    if (lyr) map.getLayers().remove(lyr);
                    lyr = new ol.layer.Vector({
                        title: "Point clicked",
                        source: new ol.source.Vector({
                            features: [new ol.Feature({
                                geometry: point_clicked
                            })]
                        }),
                        show_in_manager: false
                    });
                    map.addLayer(lyr);
                });

                //For vector layers use this to get the selected features
                var selector = new ol.interaction.Select({
                    condition: ol.events.condition.click
                });
                selector.getFeatures().on('add', function(e) {
                    if (ToolbarService.mainpanel == 'measure') return;
                    var attributes = [];
                    e.element.getKeys().forEach(function(key) {
                        if (key == 'gid' || key == 'geometry') return;
                        attributes.push({
                            name: key,
                            value: e.element.get(key)
                        });
                    })
                    ToolbarService.setMainPanel("info");
                    InfoPanelService.setAttributes(attributes);
                })
                //map.addInteraction(selector);

                //For wms layers use this to get the features at mouse coordinates
               /* map.on('singleclick', function(evt) {
                    if (ToolbarService.mainpanel == 'measure') return;
                    point_clicked.setCoordinates(evt.coordinate, 'XY');
                    InfoPanelService.setGroups([{
                        name: "Coordinates",
                        attributes: [{
                            "name": "EPSG:4326",
                            "value": ol.coordinate.toStringHDMS(ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326'))
                        }, {
                            "name": "EPSG:3857",
                            "value": ol.coordinate.createStringXY(7)(evt.coordinate)
                        }]
                    }]);
                    map.getLayers().forEach(function(layer) {
                        queryLayer(layer, evt)
                    });
                });*/

                var queryLayer = function(layer, evt) {
                    if (layer instanceof ol.layer.Tile &&
                        layer.getSource() instanceof ol.source.TileWMS &&
                        layer.getSource().getParams().INFO_FORMAT) {
                        var source = layer.getSource();
                        var viewResolution = map.getView().getResolution();
                        var url = source.getGetFeatureInfoUrl(
                            evt.coordinate, viewResolution, source.getProjection() ? source.getProjection() : map.getView().getProjection(), {
                                'INFO_FORMAT': source.getParams().INFO_FORMAT
                            });
                        if (url) {
                            if (console) console.log(url);
                            WmsGetFeatureInfo.request(url);
                        }
                    }
                }

                WmsGetFeatureInfo.featureInfoReceived = function(response) {
                    /* Maybe this will work in future OL versions
                     *
                     * var format = new ol.format.GML();
                     *  console.log(format.readFeatures(response, {}));
                     */

                    var x2js = new X2JS();
                    var json = x2js.xml_str2json(response);
                    var something_updated = false;
                    for (var feature in json.FeatureCollection.featureMember) {
                        if (feature == "__prefix") continue;
                        feature = json.FeatureCollection.featureMember[feature];
                        var group = {
                            name: "Feature",
                            attributes: []
                        };

                        for (var attribute in feature) {
                            if (feature[attribute].__text) {
                                group.attributes.push({
                                    "name": attribute,
                                    "value": feature[attribute].__text
                                });
                                something_updated = true;
                            }
                        }
                        if (something_updated)
                            InfoPanelService.groups.push(group);
                    }
                    if (something_updated) InfoPanelService.setGroups(InfoPanelService.groups);
                }

                $scope.$on('infopanel.updated', function(event) {
                    if (console) console.log(new Date());
                    if (!$scope.$$phase) $scope.$digest();
                });

            }
        ]);
    })
<commit_msg>uncomment map query<commit_after>define(['angular', 'map', 'toolbar'],

    function(angular) {
        angular.module('hs.query', ['hs.map', 'hs.toolbar'])
            .directive('infopanel', function() {
                return {
                    templateUrl: hsl_path + 'components/query/partials/infopanel.html'
                };
            }).service("WmsGetFeatureInfo", ['$http',
                function($http) {
                    this.request = function(url) {
                        var url = window.escape(url);
                        $http.get("/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + url).success(this.featureInfoReceived);
                    };

                }
            ]).service("InfoPanelService", ['$rootScope',
                function($rootScope) {
                    var me = {
                        //Used for tool specific info, such as lodexplorer region names and values
                        attributes: [],
                        //Used for getfeatureinfo. There exists a seperate group for each feature which is found at the specific coordinates
                        groups: [],
                        setAttributes: function(j) {
                            me.attributes = j;
                            $rootScope.$broadcast('infopanel.updated');
                        },
                        setGroups: function(j) {
                            me.groups = j;
                            $rootScope.$broadcast('infopanel.updated');
                        }
                    };

                    return me;
                }
            ])

        .controller('Query', ['$scope', 'OlMap', 'WmsGetFeatureInfo', 'InfoPanelService', 'ToolbarService',
            function($scope, OlMap, WmsGetFeatureInfo, InfoPanelService, ToolbarService) {
                var map = OlMap.map;
                $scope.myname = "shady";
                $scope.InfoPanelService = InfoPanelService;

                var point_clicked = new ol.geom.Point([0, 0]);
                var lyr = null;

                $scope.$on('layermanager.updated', function(event) {
                    if (lyr) map.getLayers().remove(lyr);
                    lyr = new ol.layer.Vector({
                        title: "Point clicked",
                        source: new ol.source.Vector({
                            features: [new ol.Feature({
                                geometry: point_clicked
                            })]
                        }),
                        show_in_manager: false
                    });
                    map.addLayer(lyr);
                });

                //For vector layers use this to get the selected features
                var selector = new ol.interaction.Select({
                    condition: ol.events.condition.click
                });
                selector.getFeatures().on('add', function(e) {
                    if (ToolbarService.mainpanel == 'measure') return;
                    var attributes = [];
                    e.element.getKeys().forEach(function(key) {
                        if (key == 'gid' || key == 'geometry') return;
                        attributes.push({
                            name: key,
                            value: e.element.get(key)
                        });
                    })
                    ToolbarService.setMainPanel("info");
                    InfoPanelService.setAttributes(attributes);
                })
                map.addInteraction(selector);

                //For wms layers use this to get the features at mouse coordinates
                map.on('singleclick', function(evt) {
                    if (ToolbarService.mainpanel == 'measure') return;
                    point_clicked.setCoordinates(evt.coordinate, 'XY');
                    InfoPanelService.setGroups([{
                        name: "Coordinates",
                        attributes: [{
                            "name": "EPSG:4326",
                            "value": ol.coordinate.toStringHDMS(ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326'))
                        }, {
                            "name": "EPSG:3857",
                            "value": ol.coordinate.createStringXY(7)(evt.coordinate)
                        }]
                    }]);
                    map.getLayers().forEach(function(layer) {
                        queryLayer(layer, evt)
                    });
                });

                var queryLayer = function(layer, evt) {
                    if (layer instanceof ol.layer.Tile &&
                        layer.getSource() instanceof ol.source.TileWMS &&
                        layer.getSource().getParams().INFO_FORMAT) {
                        var source = layer.getSource();
                        var viewResolution = map.getView().getResolution();
                        var url = source.getGetFeatureInfoUrl(
                            evt.coordinate, viewResolution, source.getProjection() ? source.getProjection() : map.getView().getProjection(), {
                                'INFO_FORMAT': source.getParams().INFO_FORMAT
                            });
                        if (url) {
                            if (console) console.log(url);
                            WmsGetFeatureInfo.request(url);
                        }
                    }
                }

                WmsGetFeatureInfo.featureInfoReceived = function(response) {
                    /* Maybe this will work in future OL versions
                     *
                     * var format = new ol.format.GML();
                     *  console.log(format.readFeatures(response, {}));
                     */

                    var x2js = new X2JS();
                    var json = x2js.xml_str2json(response);
                    var something_updated = false;
                    for (var feature in json.FeatureCollection.featureMember) {
                        if (feature == "__prefix") continue;
                        feature = json.FeatureCollection.featureMember[feature];
                        var group = {
                            name: "Feature",
                            attributes: []
                        };

                        for (var attribute in feature) {
                            if (feature[attribute].__text) {
                                group.attributes.push({
                                    "name": attribute,
                                    "value": feature[attribute].__text
                                });
                                something_updated = true;
                            }
                        }
                        if (something_updated)
                            InfoPanelService.groups.push(group);
                    }
                    if (something_updated) InfoPanelService.setGroups(InfoPanelService.groups);
                }

                $scope.$on('infopanel.updated', function(event) {
                    if (console) console.log(new Date());
                    if (!$scope.$$phase) $scope.$digest();
                });

            }
        ]);
    })
<|endoftext|>


<commit_before>import {getCourse} from './get-courses'
import Bluebird from 'bluebird'
import Student from '../models/student'
import Schedule from '../models/schedule'
import groupBy from 'lodash/groupBy'
import map from 'lodash/map'
import forEach from 'lodash/forEach'
import uniq from 'lodash/uniq'
import fromPairs from 'lodash/fromPairs'
import plur from 'plur'
import filter from 'lodash/filter'
import {v4 as uuid} from 'uuid'

export default async function convertStudent({courses, degrees}) {
	let {
		schedulesAndFabrications,
		info,
	} = await Bluebird.props({
		schedulesAndFabrications: processSchedules(courses),
		info: processDegrees(degrees),
	})

	let {schedules, fabrications} = schedulesAndFabrications

	return Student({
		...info,
		schedules,
		fabrications,
	})
}

async function processSchedules(courses) {
	courses = await Bluebird.all(map(courses, course => {
		return getCourse(course).then(resolvedCourse => {
			if (resolvedCourse.error) {
				course._fabrication = true
				course.clbid = course.clbid || uuid()
				return course
			}
			return resolvedCourse
		})
	}))

	let fabrications = fromPairs(map(filter(courses, '_fabrication'), c => [c.clbid, c]))

	let schedules = groupBy(courses, 'term')
	schedules = map(schedules, (courses, term) => {
		term = String(term)
		return Schedule({
			courses,
			active: true,
			clbids: map(courses, c => c.clbid),
			year: parseInt(term.substr(0, 4), 10),
			semester: parseInt(term.substr(4, 1), 10),
		})
	})
	schedules = fromPairs(map(schedules, s => [s.id, s]))

	return {schedules, fabrications}
}

function processDegrees(degrees) {
	let singularData = resolveSingularDataPoints(degrees)
	let studies = []

	for (let {concentrations, emphases, majors, degree} of degrees) {
		studies.push({name: degree, type: 'degree', revision: 'latest'})
		studies = studies.concat(majors.map(name =>         ({name, type: 'major', revision: 'latest'})))
		studies = studies.concat(concentrations.map(name => ({name, type: 'concentration', revision: 'latest'})))
		studies = studies.concat(emphases.map(name =>       ({name, type: 'emphasis', revision: 'latest'})))
	}

	return {
		...singularData,
		studies,
	}
}

function resolveSingularDataPoints(degrees) {
	let thereShouldOnlyBeOne = {
		names: map(degrees, d => d.name),
		advisors: map(degrees, d => d.advisor),
		matriculations: map(degrees, d => d.matriculation),
		graduations: map(degrees, d => d.graduation),
	}

	forEach(thereShouldOnlyBeOne, (group, name) => {
		let len = uniq(group).length
		if (len > 1) {
			throw new Error(`convertStudent: The student has more than one ${plur(name, 2)}: ${JSON.stringify(group)}`)
		}
		else if (!len) {
			throw new Error(`convertStudent: The student has zero ${plur(name, 0)}: ${JSON.stringify(group)}`)
		}
	})

	let name = thereShouldOnlyBeOne.names[0]
	let advisor = thereShouldOnlyBeOne.advisors[0]
	let matriculation = parseInt(thereShouldOnlyBeOne.matriculations[0], 10)
	let graduation = parseInt(thereShouldOnlyBeOne.graduations[0], 10)

	return {name, advisor, matriculation, graduation}
}
<commit_msg>remove the "nameses" problem<commit_after>import {getCourse} from './get-courses'
import Bluebird from 'bluebird'
import Student from '../models/student'
import Schedule from '../models/schedule'
import groupBy from 'lodash/groupBy'
import map from 'lodash/map'
import forEach from 'lodash/forEach'
import uniq from 'lodash/uniq'
import fromPairs from 'lodash/fromPairs'
import plur from 'plur'
import filter from 'lodash/filter'
import {v4 as uuid} from 'uuid'

export default async function convertStudent({courses, degrees}) {
	let {
		schedulesAndFabrications,
		info,
	} = await Bluebird.props({
		schedulesAndFabrications: processSchedules(courses),
		info: processDegrees(degrees),
	})

	let {schedules, fabrications} = schedulesAndFabrications

	return Student({
		...info,
		schedules,
		fabrications,
	})
}

async function processSchedules(courses) {
	courses = await Bluebird.all(map(courses, course => {
		return getCourse(course).then(resolvedCourse => {
			if (resolvedCourse.error) {
				course._fabrication = true
				course.clbid = course.clbid || uuid()
				return course
			}
			return resolvedCourse
		})
	}))

	let fabrications = fromPairs(map(filter(courses, '_fabrication'), c => [c.clbid, c]))

	let schedules = groupBy(courses, 'term')
	schedules = map(schedules, (courses, term) => {
		term = String(term)
		return Schedule({
			courses,
			active: true,
			clbids: map(courses, c => c.clbid),
			year: parseInt(term.substr(0, 4), 10),
			semester: parseInt(term.substr(4, 1), 10),
		})
	})
	schedules = fromPairs(map(schedules, s => [s.id, s]))

	return {schedules, fabrications}
}

function processDegrees(degrees) {
	let singularData = resolveSingularDataPoints(degrees)
	let studies = []

	for (let {concentrations, emphases, majors, degree} of degrees) {
		studies.push({name: degree, type: 'degree', revision: 'latest'})
		studies = studies.concat(majors.map(name =>         ({name, type: 'major', revision: 'latest'})))
		studies = studies.concat(concentrations.map(name => ({name, type: 'concentration', revision: 'latest'})))
		studies = studies.concat(emphases.map(name =>       ({name, type: 'emphasis', revision: 'latest'})))
	}

	return {
		...singularData,
		studies,
	}
}

function resolveSingularDataPoints(degrees) {
	let thereShouldOnlyBeOne = {
		names: map(degrees, d => d.name),
		advisors: map(degrees, d => d.advisor),
		matriculations: map(degrees, d => d.matriculation),
		graduations: map(degrees, d => d.graduation),
	}

	forEach(thereShouldOnlyBeOne, (group, name) => {
		let len = uniq(group).length
		if (len > 1) {
			throw new Error(`convertStudent: The student has more than one ${name}: ${JSON.stringify(group)}`)
		}
		else if (!len) {
			throw new Error(`convertStudent: The student has no ${name}: ${JSON.stringify(group)}`)
		}
	})

	let name = thereShouldOnlyBeOne.names[0]
	let advisor = thereShouldOnlyBeOne.advisors[0]
	let matriculation = parseInt(thereShouldOnlyBeOne.matriculations[0], 10)
	let graduation = parseInt(thereShouldOnlyBeOne.graduations[0], 10)

	return {name, advisor, matriculation, graduation}
}
<|endoftext|>


<commit_before>// Copyright 2015 Volker Sorge
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Abstract class implementing highlighters.
 *
 * @author volker.sorge@gmail.com (Volker Sorge)
 */

goog.provide('sre.AbstractHighlighter');

goog.require('sre.ColorPicker');
goog.require('sre.HighlighterInterface');

/**
 * @constructor
 * @implements {sre.HighlighterInterface}
 */
sre.AbstractHighlighter = function() {
  /**
   * List of currently highlighted nodes and their original background color.
   * @type {!Array.<Array.<{node: !Node, opacity: (undefined|string),
   *          background: (undefined|string), foreground: (undefined|string)}
   *         >>}
   * @private
   */
  this.currentHighlights_ = [];

  /**
   * @type {sre.ColorPicker}
   * @protected
   */
  this.color = null;

  /**
   * @type {string}
   * @protected
   */
  this.mactionName = '';

  /**
   * @type {!Object.<string, string>}
   * @private
   */
  this.state_ = {};

};

/**
 * @override
 */
sre.AbstractHighlighter.prototype.highlight = function(nodes) {
  this.currentHighlights_.push(nodes.map(
      goog.bind(function(node) {return this.highlightNode(node);},
                this)));
};

/**
 * Highlights a single node.
 * @param {!Node} node The node to be highlighted.
 * @return {{node: !Node, opacity: (undefined|string),
 *          background: (undefined|string), foreground: (undefined|string)}
 *         } The old node
 *     information.
 * @protected
 */
sre.AbstractHighlighter.prototype.highlightNode = goog.abstractMethod;

/**
 * @override
 */
sre.AbstractHighlighter.prototype.highlightAll = function(node) {
  var mactions = this.getMactionNodes(node);
  for (var i = 0, maction; maction = mactions[i]; i++) {
    this.highlight([maction]);
  }
};

/**
 * @override
 */
sre.AbstractHighlighter.prototype.unhighlight = function() {
  var nodes = this.currentHighlights_.pop();
  if (!nodes) return;
  nodes.forEach(
      goog.bind(function(node) {return this.unhighlightNode(node);},
                this));
};

/**
 * Unhighlights a single node.
 * @param {{node: !Node, opacity: (undefined|string),
 *          background: (undefined|string), foreground: (undefined|string)}
 *         } info The info for the
 *     node to be unhighlighted.
 * @protected
 */
sre.AbstractHighlighter.prototype.unhighlightNode = goog.abstractMethod;

/**
 * @override
 */
sre.AbstractHighlighter.prototype.unhighlightAll = function() {
  while (this.currentHighlights_.length > 0) {
    this.unhighlight();
  }
};

/**
 * @override
 */
sre.AbstractHighlighter.prototype.setColor = function(color) {
  this.color = color;
};

/**
 * Turns the current color into a string representation.
 * @return {sre.ColorPicker.String} The color string, by default as rgba.
 * @protected
 */
sre.AbstractHighlighter.prototype.colorString = function() {
  return this.color.rgba();
};

/**
 * @override
 */
sre.AbstractHighlighter.prototype.addEvents = function(node, events) {
  var mactions = this.getMactionNodes(node);
  for (var i = 0, maction; maction = mactions[i]; i++) {
    for (var event in events) {
      maction.addEventListener(event, events[event]);
    }
  }
};

/**
 * Returns the maction sub nodes of a given node.
 * @param {!Node} node The root node.
 * @return {NodeList} The list of maction sub nodes.
 */
sre.AbstractHighlighter.prototype.getMactionNodes = function(node) {
  return node.getElementsByClassName(this.mactionName);
};

/**
 * Predicate to check if a node is an maction node.
 * @param {!Node} node A DOM node.
 * @return {boolean} True if the node is an maction node.
 */
sre.AbstractHighlighter.prototype.isMactionNode = function(node) {
  return node.className === this.mactionName;
};

/**
 * Removes a state for a particular node.
 * @param {string} id A node id.
 */
sre.AbstractHighlighter.prototype.resetState = function(id) {
  delete(this.state_[id]);
};

/**
 * Sets a state value for a particular node.
 * @param {string} id A node id.
 * @param {string} value The state value.
 */
sre.AbstractHighlighter.prototype.setState = function(id, value) {
  this.state_[id] = value;
};

/**
 * Returns the state a particular node if it exists.
 * @param {string} id The node id.
 * @return {string} The state value.
 */
sre.AbstractHighlighter.prototype.getState = function(id) {
  return this.state_[id];
};
<commit_msg>Fixes classname problem in commonHtml.<commit_after>// Copyright 2015 Volker Sorge
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Abstract class implementing highlighters.
 *
 * @author volker.sorge@gmail.com (Volker Sorge)
 */

goog.provide('sre.AbstractHighlighter');

goog.require('sre.ColorPicker');
goog.require('sre.HighlighterInterface');

/**
 * @constructor
 * @implements {sre.HighlighterInterface}
 */
sre.AbstractHighlighter = function() {
  /**
   * List of currently highlighted nodes and their original background color.
   * @type {!Array.<Array.<{node: !Node, opacity: (undefined|string),
   *          background: (undefined|string), foreground: (undefined|string)}
   *         >>}
   * @private
   */
  this.currentHighlights_ = [];

  /**
   * @type {sre.ColorPicker}
   * @protected
   */
  this.color = null;

  /**
   * @type {string}
   * @protected
   */
  this.mactionName = '';

  /**
   * @type {!Object.<string, string>}
   * @private
   */
  this.state_ = {};

};

/**
 * @override
 */
sre.AbstractHighlighter.prototype.highlight = function(nodes) {
  this.currentHighlights_.push(nodes.map(
      goog.bind(function(node) {return this.highlightNode(node);},
                this)));
};

/**
 * Highlights a single node.
 * @param {!Node} node The node to be highlighted.
 * @return {{node: !Node, opacity: (undefined|string),
 *          background: (undefined|string), foreground: (undefined|string)}
 *         } The old node
 *     information.
 * @protected
 */
sre.AbstractHighlighter.prototype.highlightNode = goog.abstractMethod;

/**
 * @override
 */
sre.AbstractHighlighter.prototype.highlightAll = function(node) {
  var mactions = this.getMactionNodes(node);
  for (var i = 0, maction; maction = mactions[i]; i++) {
    this.highlight([maction]);
  }
};

/**
 * @override
 */
sre.AbstractHighlighter.prototype.unhighlight = function() {
  var nodes = this.currentHighlights_.pop();
  if (!nodes) return;
  nodes.forEach(
      goog.bind(function(node) {return this.unhighlightNode(node);},
                this));
};

/**
 * Unhighlights a single node.
 * @param {{node: !Node, opacity: (undefined|string),
 *          background: (undefined|string), foreground: (undefined|string)}
 *         } info The info for the
 *     node to be unhighlighted.
 * @protected
 */
sre.AbstractHighlighter.prototype.unhighlightNode = goog.abstractMethod;

/**
 * @override
 */
sre.AbstractHighlighter.prototype.unhighlightAll = function() {
  while (this.currentHighlights_.length > 0) {
    this.unhighlight();
  }
};

/**
 * @override
 */
sre.AbstractHighlighter.prototype.setColor = function(color) {
  this.color = color;
};

/**
 * Turns the current color into a string representation.
 * @return {sre.ColorPicker.String} The color string, by default as rgba.
 * @protected
 */
sre.AbstractHighlighter.prototype.colorString = function() {
  return this.color.rgba();
};

/**
 * @override
 */
sre.AbstractHighlighter.prototype.addEvents = function(node, events) {
  var mactions = this.getMactionNodes(node);
  for (var i = 0, maction; maction = mactions[i]; i++) {
    for (var event in events) {
      maction.addEventListener(event, events[event]);
    }
  }
};

/**
 * Returns the maction sub nodes of a given node.
 * @param {!Node} node The root node.
 * @return {NodeList} The list of maction sub nodes.
 */
sre.AbstractHighlighter.prototype.getMactionNodes = function(node) {
  return node.getElementsByClassName(this.mactionName);
};

/**
 * Predicate to check if a node is an maction node.
 * @param {!Node} node A DOM node.
 * @return {boolean} True if the node is an maction node.
 */
sre.AbstractHighlighter.prototype.isMactionNode = function(node) {
  return node.className.match(new RegExp(this.mactionName));
};

/**
 * Removes a state for a particular node.
 * @param {string} id A node id.
 */
sre.AbstractHighlighter.prototype.resetState = function(id) {
  delete(this.state_[id]);
};

/**
 * Sets a state value for a particular node.
 * @param {string} id A node id.
 * @param {string} value The state value.
 */
sre.AbstractHighlighter.prototype.setState = function(id, value) {
  this.state_[id] = value;
};

/**
 * Returns the state a particular node if it exists.
 * @param {string} id The node id.
 * @return {string} The state value.
 */
sre.AbstractHighlighter.prototype.getState = function(id) {
  return this.state_[id];
};
<|endoftext|>


<commit_before>/**
 * @fileoverview
 * Mappings between various types of http data and their relevant specs as
 * well as mappings and helpers used for resolving mime types
 */
window.http_header_specification_urls = {
    // from HTTP spec
    "Accept": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1",
    "Accept-Charset": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2",
    "Accept-Encoding": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3",
    "Accept-Language": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4",
    "Accept-Ranges": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.5",
    "Age": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.6",
    "Allow": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7",
    "Authorization": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.8",
    "Cache-Control": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9",
    "Connection": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10",
    "Content-Encoding": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11",
    "Content-Language": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.12",
    "Content-Length": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13",
    "Content-Location": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.14",
    "Content-MD5": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.15",
    "Content-Range": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16",
    "Content-Type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17",
    "Date": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18",
    "Clockless Origin Server Operation": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18.1",
    "ETag": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19",
    "Expect": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.20",
    "Expires": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21",
    "From": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.22",
    "Host": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23",
    "If-Match": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24",
    "If-Modified-Since": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25",
    "If-None-Match": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26",
    "If-Range": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.27",
    "If-Unmodified-Since": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.28",
    "Last-Modified": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.29",
    "Location": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30",
    "Max-Forwards": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.31",
    "Pragma": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32",
    "Proxy-Authenticate": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.33",
    "Proxy-Authorization": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.34",
    "Range": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35",
    "Byte Ranges": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1",
    "Range Retrieval Requests": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2",
    "Referer": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36",
    "Retry-After": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37",
    "Server": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.38",
    "TE": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.39",
    "Trailer": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.40",
    "Transfer-Encoding": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.41",
    "Upgrade": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.42",
    "User-Agent": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43",
    "Vary": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44",
    "Via": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.45",
    "Warning": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46",
    "WWW-Authenticate": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.47",

    // from Cookie spec (rfc2965)
    "Cookie": "http://www.ietf.org/rfc/rfc2965.txt",
    "Cookie2": "http://www.ietf.org/rfc/rfc2965.txt",
    "Set-Cookie2": "http://www.ietf.org/rfc/rfc2965.txt"

}

window.http_method_specification_urls = {
    "options": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2",
    "get": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3",
    "head": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4",
    "post": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5",
    "put": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6",
    "delete": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.7",
    "trace": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.8",
    "connect": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.9"
}

function http_map_mime_to_type(mime)
{
    mime = mime.toLowerCase();

    if (mime in http_mime_type_map)
    {
        return http_mime_type_map[mime];
    }

    if (mime.indexOf("image/") == 0)
    {
        return "image";
    }

    if (mime.indexOf("video/") == 0)
    {
        return "video";
    }

    if (mime.indexOf("audio/") == 0)
    {
        return "audio";
    }

    return "unknown";
}

window.http_mime_type_map = {
    "text/html": "markup",
    "text/css": "css",
    "application/x-javascript": "javascript",
    "application/xhtml+xml": "markup",
    "application/pdf": "pdf",
    "application/x-shockwave-flash": "flash",
    "application/xml": "xml"
}

/**
 * This one will be deprecated when we get mime types straight from core.
 */
window.http_file_extension_map = {
    "html": "text/html", "htm": "text/html",
    "xml": "application/xml",
    "xhtml": "application/xhtml+xml", "xht": "application/xhtml+xml",
    "swf": "application/x-shockwave-flash",
    "png": "image/png",
    "ico": "image/x-icon",
    "gif": "image/gif",
    "jpg": "image/jpeg", "jpeg": "image/jpeg", "jpe": "image/jpeg",
    "css": "text/css"
}

function http_get_mime_from_extension(path)
{
    var ext = path.split(".").pop().toLowerCase();
    return http_file_extension_map[ext] || "";
}<commit_msg>Added detection of javascript that was left out<commit_after>/**
 * @fileoverview
 * Mappings between various types of http data and their relevant specs as
 * well as mappings and helpers used for resolving mime types
 */
window.http_header_specification_urls = {
    // from HTTP spec
    "Accept": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1",
    "Accept-Charset": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2",
    "Accept-Encoding": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3",
    "Accept-Language": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4",
    "Accept-Ranges": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.5",
    "Age": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.6",
    "Allow": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7",
    "Authorization": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.8",
    "Cache-Control": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9",
    "Connection": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10",
    "Content-Encoding": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11",
    "Content-Language": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.12",
    "Content-Length": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13",
    "Content-Location": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.14",
    "Content-MD5": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.15",
    "Content-Range": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16",
    "Content-Type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17",
    "Date": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18",
    "Clockless Origin Server Operation": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18.1",
    "ETag": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19",
    "Expect": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.20",
    "Expires": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21",
    "From": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.22",
    "Host": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23",
    "If-Match": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24",
    "If-Modified-Since": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25",
    "If-None-Match": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26",
    "If-Range": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.27",
    "If-Unmodified-Since": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.28",
    "Last-Modified": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.29",
    "Location": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30",
    "Max-Forwards": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.31",
    "Pragma": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32",
    "Proxy-Authenticate": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.33",
    "Proxy-Authorization": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.34",
    "Range": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35",
    "Byte Ranges": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1",
    "Range Retrieval Requests": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2",
    "Referer": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36",
    "Retry-After": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37",
    "Server": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.38",
    "TE": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.39",
    "Trailer": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.40",
    "Transfer-Encoding": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.41",
    "Upgrade": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.42",
    "User-Agent": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43",
    "Vary": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44",
    "Via": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.45",
    "Warning": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46",
    "WWW-Authenticate": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.47",

    // from Cookie spec (rfc2965)
    "Cookie": "http://www.ietf.org/rfc/rfc2965.txt",
    "Cookie2": "http://www.ietf.org/rfc/rfc2965.txt",
    "Set-Cookie2": "http://www.ietf.org/rfc/rfc2965.txt"

}

window.http_method_specification_urls = {
    "options": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2",
    "get": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3",
    "head": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4",
    "post": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5",
    "put": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6",
    "delete": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.7",
    "trace": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.8",
    "connect": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.9"
}

function http_map_mime_to_type(mime)
{
    mime = mime.toLowerCase();

    if (mime in http_mime_type_map)
    {
        return http_mime_type_map[mime];
    }

    if (mime.indexOf("image/") == 0)
    {
        return "image";
    }

    if (mime.indexOf("video/") == 0)
    {
        return "video";
    }

    if (mime.indexOf("audio/") == 0)
    {
        return "audio";
    }

    return "unknown";
}

window.http_mime_type_map = {
    "text/html": "markup",
    "text/css": "css",
    "application/x-javascript": "javascript",
    "application/xhtml+xml": "markup",
    "application/pdf": "pdf",
    "application/x-shockwave-flash": "flash",
    "application/xml": "xml"
}

/**
 * This one will be deprecated when we get mime types straight from core.
 */
window.http_file_extension_map = {
    "html": "text/html", "htm": "text/html",
    "xml": "application/xml",
    "xhtml": "application/xhtml+xml", "xht": "application/xhtml+xml",
    "swf": "application/x-shockwave-flash",
    "png": "image/png",
    "ico": "image/x-icon",
    "gif": "image/gif",
    "jpg": "image/jpeg", "jpeg": "image/jpeg", "jpe": "image/jpeg",
    "css": "text/css",
    "js":  "application/x-javascript"
}

function http_get_mime_from_extension(path)
{
    var ext = path.split(".").pop().toLowerCase();
    return http_file_extension_map[ext] || "";
}<|endoftext|>


<commit_before>import React from "react";
import Moment from "moment";
import Numeral from "numeral";
import { connect } from "react-redux";
import { ClipLoader } from "halogenium";
import { Panel, Alert, Table } from "react-bootstrap";

import { blastNuvs } from "../../../actions";
import { Button, Flex, FlexItem, Icon, RelativeTime } from "../../../../base";

const ridRoot = "https://blast.ncbi.nlm.nih.gov/Blast.cgi?\
    CMD=Web&PAGE_TYPE=BlastFormatting&OLD_BLAST=false&GET_RID_INFO=on&RID=";

const NuVsBLAST = (props) => {

    if (props.blast) {

        if (props.blast.ready) {
            const hitComponents = props.blast.result.hits.map((hit, index) =>

                        <a target="_blank" href={`https://www.ncbi.nlm.nih.gov/nuccore/${hit.accession}`}>
                            {hit.accession}

                    {hit.name}
                    {hit.evalue}
                    {hit.score}
                    {Numeral(hit.identity / hit.align_len).format("0.00")}

            );

            return (
                <Panel header="NCBI BLAST">

                                Accession
                                Name
                                E-value
                                Score
                                Identity

                            {hitComponents}

                </Panel>
            );
        }

        let timing;
        let ridText;
        let ridLink;

        if (props.blast.rid) {
            const relativeLast = <RelativeTime time={props.blast.last_checked_at} />;
            const relativeNext = Moment(props.blast.last_checked_at).add(props.blast.interval, "seconds").fromNow();

            timing = (
                <FlexItem grow={1}>

                        Last checked {relativeLast}. Checking again in {relativeNext}.

                </FlexItem>
            );

            ridText = " with RID ";

            ridLink = (

                    {props.blast.rid} <Icon name="new-tab" />

            );
        }

        return (
            <Panel>
                <Flex alignItems="center">
                    <FlexItem>
                        <ClipLoader size={16} color="#000" />
                    </FlexItem>
                    <FlexItem pad={5}>
                        BLAST in progress {ridText}
                        {ridLink}
                    </FlexItem>
                    {timing}
                </Flex>
            </Panel>
        );
    }

    return (
        <Alert bsStyle="warning">
            <Flex alignItems="center">
                <FlexItem>
                    <Icon name="info" />
                </FlexItem>
                <FlexItem grow={1} pad={5}>
                    This sequence has no BLAST information attached to it.
                </FlexItem>
                <FlexItem pad={10}>
                    <Button
                        bsSize="small"
                        icon="cloud"
                        onClick={() => props.onBlast(props.analysisId, props.sequenceIndex)}
                    >
                        BLAST at NCBI
                    </Button>
                </FlexItem>
            </Flex>
        </Alert>
    );
};

const mapStateToProps = (state) => {
    return {
        analysisId: state.samples.analysisDetail.id
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        onBlast: (analysisId, sequenceIndex) => {
            dispatch(blastNuvs(analysisId, sequenceIndex));
        }
    };
};

const Container = connect(mapStateToProps, mapDispatchToProps)(NuVsBLAST);

export default Container;
<commit_msg>Show message in client when no BLAST hits were found (NuVs)<commit_after>import React from "react";
import Moment from "moment";
import Numeral from "numeral";
import { connect } from "react-redux";
import { ClipLoader } from "halogenium";
import { Panel, Alert, Table } from "react-bootstrap";

import { blastNuvs } from "../../../actions";
import { Button, Flex, FlexItem, Icon, RelativeTime } from "../../../../base";

const ridRoot = "https://blast.ncbi.nlm.nih.gov/Blast.cgi?\
    CMD=Web&PAGE_TYPE=BlastFormatting&OLD_BLAST=false&GET_RID_INFO=on&RID=";

const NuVsBLAST = (props) => {

    if (props.blast) {

        if (props.blast.ready) {
            if (props.blast.result.hits.length) {
                const hitComponents = props.blast.result.hits.map((hit, index) =>

                            <a target="_blank" href={`https://www.ncbi.nlm.nih.gov/nuccore/${hit.accession}`}>
                                {hit.accession}

                        {hit.name}
                        {hit.evalue}
                        {hit.score}
                        {Numeral(hit.identity / hit.align_len).format("0.00")}

                );

                return (
                    <Panel header="NCBI BLAST">

                                Accession
                                Name
                                E-value
                                Score
                                Identity

                            {hitComponents}

                    </Panel>
                );
            }

            return (
                <Panel header="NCBI BLAST">
                    No BLAST hits found.
                </Panel>
            );
        }

        let timing;
        let ridText;
        let ridLink;

        if (props.blast.rid) {
            const relativeLast = <RelativeTime time={props.blast.last_checked_at} />;
            const relativeNext = Moment(props.blast.last_checked_at).add(props.blast.interval, "seconds").fromNow();

            timing = (
                <FlexItem grow={1}>

                        Last checked {relativeLast}. Checking again in {relativeNext}.

                </FlexItem>
            );

            ridText = " with RID ";

            ridLink = (

                    {props.blast.rid} <Icon name="new-tab" />

            );
        }

        return (
            <Panel>
                <Flex alignItems="center">
                    <FlexItem>
                        <ClipLoader size={16} color="#000" />
                    </FlexItem>
                    <FlexItem pad={5}>
                        BLAST in progress {ridText}
                        {ridLink}
                    </FlexItem>
                    {timing}
                </Flex>
            </Panel>
        );
    }

    return (
        <Alert bsStyle="warning">
            <Flex alignItems="center">
                <FlexItem>
                    <Icon name="info" />
                </FlexItem>
                <FlexItem grow={1} pad={5}>
                    This sequence has no BLAST information attached to it.
                </FlexItem>
                <FlexItem pad={10}>
                    <Button
                        bsSize="small"
                        icon="cloud"
                        onClick={() => props.onBlast(props.analysisId, props.sequenceIndex)}
                    >
                        BLAST at NCBI
                    </Button>
                </FlexItem>
            </Flex>
        </Alert>
    );
};

const mapStateToProps = (state) => {
    return {
        analysisId: state.samples.analysisDetail.id
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        onBlast: (analysisId, sequenceIndex) => {
            dispatch(blastNuvs(analysisId, sequenceIndex));
        }
    };
};

const Container = connect(mapStateToProps, mapDispatchToProps)(NuVsBLAST);

export default Container;
<|endoftext|>


<commit_before>

'use strict';

const Pikaday = require('pikaday');

let picker;

N.wire.on('navigate.done:users.settings.about', function initialize_datepicker() {
  let container = $('.user-settings-about-birthday');

  if (!container.length) return;

  let cldr          = N.runtime.t('l10n.cldr').dates.calendars.gregorian;
  let months        = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ].map(key =>
                        cldr.months['stand-alone'].wide[key]);
  let weekdays      = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ].map(key =>
                        cldr.days['stand-alone'].wide[key]);
  let weekdaysShort = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ].map(key =>
                        cldr.days['stand-alone'].abbreviated[key]);

  picker = new Pikaday({
    field:     container[0],
    yearRange: [ 1900, new Date().getFullYear() ],
    i18n:      { months, weekdays, weekdaysShort },
    onSelect:  date => {
      container.find('input').val(date.toISOString().slice(0, 10));
      container.find('input').trigger('change');
    }
  });
});

N.wire.on('navigate.exit:users.settings.about', function teardown_datepicker() {
  if (picker) {
    picker.destroy();
    picker = null;
  }
});
<commit_msg>Fix birthday field tz in user settings<commit_after>

'use strict';

const Pikaday = require('pikaday');

let picker;

N.wire.on('navigate.done:users.settings.about', function initialize_datepicker() {
  let container = $('.user-settings-about-birthday');

  if (!container.length) return;

  let cldr          = N.runtime.t('l10n.cldr').dates.calendars.gregorian;
  let months        = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ].map(key =>
                        cldr.months['stand-alone'].wide[key]);
  let weekdays      = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ].map(key =>
                        cldr.days['stand-alone'].wide[key]);
  let weekdaysShort = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ].map(key =>
                        cldr.days['stand-alone'].abbreviated[key]);

  picker = new Pikaday({
    field:     container[0],
    yearRange: [ 1900, new Date().getFullYear() ],
    i18n:      { months, weekdays, weekdaysShort },
    onSelect:  date => {
      // pikaday returns date in local TZ, but toISOString returns date in UTC,
      // so we need to cancel out timezone offset
      date = new Date(date.getTime() - (date.getTimezoneOffset() * 60000));
      container.find('input').val(date.toISOString().slice(0, 10));
      container.find('input').trigger('change');
    }
  });
});

N.wire.on('navigate.exit:users.settings.about', function teardown_datepicker() {
  if (picker) {
    picker.destroy();
    picker = null;
  }
});
<|endoftext|>


<commit_before>define(['/api/config'], function (ApiConfig) {
    var reject = function () {
        window.close();
    };
    if (ApiConfig.httpSafeOrigin !== window.location.origin) {
        window.alert('The bounce application must only be used from the sandbox domain, ' +
            'please report this issue on https://github.com/xwiki-labs/cryptpad');
        return;
    }
    if (typeof(URL) !== 'function') {
        window.alert("Your browser does not support functionality this page requires");
        return void reject();
    }

    window.opener = null;

    var host;
    try {
        host = new URL('', ApiConfig.httpUnsafeOrigin);
    } catch (err) {
        window.alert("This server is configured incorrectly. Its administrator should check its diagnostics page");
        return void reject();
    }

    var target;
    try {
        var bounceTo = decodeURIComponent(window.location.hash.slice(1));
        target = new URL(bounceTo, ApiConfig.httpUnsafeOrigin);
    } catch (err) {
        console.error(err);
        window.alert('The bounce application must only be used with a valid href to visit');
        return void reject();
    }

    var go = function () {
        window.location.href = target.href;
    };

    if (target.host === host.host) { return void go(); }

    require([
        '/customize/messages.js',
    ], function (Messages) {
        Messages.bounce_confirm = 'You are about to leave {0}\n\nAre you sure you want to visit "{1}"?'; // XXX
        Messages.bounce_danger = 'It looks like someone is trying to trick you into visiting a dangerous link.\n\n("{0}")\n\nBe careful!'; // XXX

        if (['javascript:', 'vbscript:', 'data:', 'blob:'].includes(target.protocol)) {
            window.alert(Messages._getKey('bounce_danger', [target.href]));
            return void reject();
        }

        var question = Messages._getKey('bounce_confirm', [host.hostname, target.href]);
        var answer = window.confirm(question);
        if (answer) { return void go(); }
        reject();
    });
});
<commit_msg>remove hardcoded translations<commit_after>define(['/api/config'], function (ApiConfig) {
    var reject = function () {
        window.close();
    };
    if (ApiConfig.httpSafeOrigin !== window.location.origin) {
        window.alert('The bounce application must only be used from the sandbox domain, ' +
            'please report this issue on https://github.com/xwiki-labs/cryptpad');
        return;
    }
    if (typeof(URL) !== 'function') {
        window.alert("Your browser does not support functionality this page requires");
        return void reject();
    }

    window.opener = null;

    var host;
    try {
        host = new URL('', ApiConfig.httpUnsafeOrigin);
    } catch (err) {
        window.alert("This server is configured incorrectly. Its administrator should check its diagnostics page");
        return void reject();
    }

    var target;
    try {
        var bounceTo = decodeURIComponent(window.location.hash.slice(1));
        target = new URL(bounceTo, ApiConfig.httpUnsafeOrigin);
    } catch (err) {
        console.error(err);
        window.alert('The bounce application must only be used with a valid href to visit');
        return void reject();
    }

    var go = function () {
        window.location.href = target.href;
    };

    if (target.host === host.host) { return void go(); }

    require([
        '/customize/messages.js',
    ], function (Messages) {
        if (['javascript:', 'vbscript:', 'data:', 'blob:'].includes(target.protocol)) {
            window.alert(Messages._getKey('bounce_danger', [target.href]));
            return void reject();
        }

        var question = Messages._getKey('bounce_confirm', [host.hostname, target.href]);
        var answer = window.confirm(question);
        if (answer) { return void go(); }
        reject();
    });
});
<|endoftext|>


<commit_before>ngapp.service('helpService', function() {
    let service = this,
        topics = [];

    // PRIVATE FUNCTIONS
    let topicExistsError = function(label) {
        return new Error(`Topic ${label} already exists.`);
    };

    let failedToResolveTopicError = function(path) {
        return new Error(`Failed to resolve help topic at path ${path}.`);
    };

    let getTopicChildren = function(path) {
        let topic = service.getTopic(path);
        if (!topic.children) topic.children = [];
        return topic.children;
    };

    let getTopicId = function(topic) {
        return topic.id || topic.label.split(' ').filter(function(part) {
            return !part.match(/\[.+\]/);
        }).join('').uncapitalize();
    };

    let processTopics = function(topics, path) {
        return topics.map(function(topic) {
            let id = getTopicId(topic);
            topic.templateUrl = `${path}/${id}.html`;
            if (!topic.children) return topic;
            topic.children = processTopics(topic.children, `${path}/${id}`);
            return topic;
        });
    };

    let loadCoreTopics = function() {
        topics = processTopics(fh.loadJsonFile('app/topics.json'), 'docs');
    };

    // API FUNCTIONS
    this.getTopics = () => { return topics };

    this.addTopic = function(topic, path) {
        let target = path ? getTopicChildren(path) : topics,
            existingTopic = target.findByKey('label', topic.label);
        if (existingTopic) throw topicExistsError(topic.label);
        target.push(topic);
    };

    this.getTopic = function(path, callback) {
        let pathParts = path.split('/'),
            result = topics.findByKey('label', pathParts[0]);
        for (let i = 1; i < pathParts.length; i++) {
            if (!result) return;
            if (callback) callback(result);
            result = result.children.findByKey('label', pathParts[i]);
        }
        if (!result) throw failedToResolveTopicError(path);
        return result;
    };

    // initialization
    loadCoreTopics()
});
<commit_msg>fixed bug with getTopic not raising exceptions properly<commit_after>ngapp.service('helpService', function() {
    let service = this,
        topics = [];

    // PRIVATE FUNCTIONS
    let topicExistsError = function(label) {
        return new Error(`Topic ${label} already exists.`);
    };

    let failedToResolveTopicError = function(path) {
        return new Error(`Failed to resolve help topic at path ${path}.`);
    };

    let getTopicChildren = function(path) {
        let topic = service.getTopic(path);
        if (!topic.children) topic.children = [];
        return topic.children;
    };

    let getTopicId = function(topic) {
        return topic.id || topic.label.split(' ').filter(function(part) {
            return !part.match(/\[.+\]/);
        }).join('').uncapitalize();
    };

    let processTopics = function(topics, path) {
        return topics.map(function(topic) {
            let id = getTopicId(topic);
            topic.templateUrl = `${path}/${id}.html`;
            if (!topic.children) return topic;
            topic.children = processTopics(topic.children, `${path}/${id}`);
            return topic;
        });
    };

    let loadCoreTopics = function() {
        topics = processTopics(fh.loadResource('app/topics.json'), 'docs');
    };

    // API FUNCTIONS
    this.getTopics = () => { return topics };

    this.addTopic = function(topic, path) {
        let target = path ? getTopicChildren(path) : topics,
            existingTopic = target.findByKey('label', topic.label);
        if (existingTopic) throw topicExistsError(topic.label);
        target.push(topic);
    };

    this.getTopic = function(path, callback) {
        let pathParts = path.split('/'),
            result = topics.findByKey('label', pathParts[0]);
        for (let i = 1; i < pathParts.length; i++) {
            if (!result) break;
            if (callback) callback(result);
            result = result.children.findByKey('label', pathParts[i]);
        }
        if (!result) throw failedToResolveTopicError(path);
        return result;
    };

    // initialization
    loadCoreTopics()
});
<|endoftext|>