<commit_before>// ==UserScript==
// @name          MusicBrainz power editor
// @description   Provide power editor tools for quick massive editing in MusicBrainz
// @include       http://musicbrainz.org/*
// @match         http://musicbrainz.org/*
// ==/UserScript==

function PowerEditor() {
	function prependChild(whereTo, what) {
		var whereToFc = whereTo.firstChild;
		whereTo.insertBefore(what, whereToFc);
	}

	this.addPowerEditorPanel = function() {
		// Add styles
		var styles = document.createElement('style');
		styles.innerHTML = '' +
			'body { position: relative; padding: 0 0 0 30.5em; }\n' +
			'#pwe-panel { position: absolute; top: 0; bottom: 0; left: 0; width: 30em; }\n' +
			'#pwe-panel-back { padding: 0 0.5em; background: #ffffd8; }\n' +
			'#pwe-go { width: 10em; float: right; }\n' +
			'#pwe-mode { width: auto; }\n' +
			'.cmd { width: 2em; float: right; background: #ccc; display: inline-block; text-align: center; border: 1px solid #999; cursor: pointer; }\n' +
			'#pwe-panel .checked { background: #999; border: 1px solid #555; }\n' +
			'#pwe-panel .settings-button { display: inline-block; float: right; background: #ccc; border: 1px solid #999; cursor: pointer; padding: 0 1em; }\n' +
			'#pwe-settings-panel { position: absolute; width: 30em; height: 15em; top: 5em; left: 20em; z-index: 100500; background: #eee; border: 1px solid #a1a1a1; padding: 0.5em 1em; display: none; }\n' +
			'#pwe-settings button { width: 10em; padding: 0 5em; }\n' +
			'#header-menu div.l { display: none; }\n' +
			'#header-menu div.r { display: none; }\n' +
			'#header-menu { border-bottom-right-radius: 8px; border-bottom-left-radius: 8px; }\n' +
			'.br { display: none !important; }\n' +
			'.bl { display: none !important; }\n' +
			'.tr { display: none !important; }\n' +
			'.tl { display: none !important; }\n' +
			'#page { border-radius: 8px; }\n' +
			'';
		prependChild(document.body, styles);

		// Add panel
		var panel = document.createElement('div');
		panel.setAttribute('id', 'pwe-panel');

		panel.innerHTML = '' +
			'
\n' +
			'settings\n' +
			'
Power editor
\n' +
			'
\n' +
			'<button type="button" id="pwe-go" onclick="pwe.go()">Go!</button>\n' +
			'Mode: <select id="pwe-mode" onchange="pwe.updateMode(this.value)">\n' +
			'<option value="rel">Relate</option>\n' +
			'<option value="recwork">Rec → Work</option>\n' +
			'</select>\n' +
			'
\n' +
			'
Relationships...
\n' +
			'
Rec - work...
\n' +
			'
Music
\n' +
			'

\n' +
			'
Group
\n' +
			'

\n' +
			'
People
\n' +
			'

\n' +
			'
Works
\n' +
			'

\n' +
			'
\n' +
			'
Settings - Power MusicBrainz Editor
\n' +
			'<form name="pweSettings">\n' +
			'
\n' +
			'<input type="checkbox" name="fixRounded"/>' +
			'Fix rounded corners\n' +
			'
\n' +
			'<button type="button" onclick="pwe.settingsOk()">OK</button>\n' +
			'<button type="button" onclick="pwe.settingsClose()">Cancel</button>\n' +
			'</form>\n' +
			'
\n' +
			'
\n';

		prependChild(document.body, panel);

		this.updateMode('rel');
	}

	this.loadJSONArrayFromStorage = function(key) {
		var str = localStorage[key];
		if (str) {
			return JSON.parse(str);
		} else {
			return [];
		}
	}

	this.loadJSONObjectFromStorage = function(key) {
		var str = localStorage[key];
		if (str) {
			return JSON.parse(str);
		} else {
			return {};
		}
	}

	this.saveToStorage = function() {
		localStorage['pwe_releases'] = JSON.stringify(this.releases);
		localStorage['pwe_groups'] = JSON.stringify(this.groups);
		localStorage['pwe_people'] = JSON.stringify(this.people);
		localStorage['pwe_works'] = JSON.stringify(this.works);
		localStorage['pwe_settings'] = JSON.stringify(this.settings);
	}

	this.updateList = function(listId) {
		var mode = document.getElementById('pwe-mode').value;

		var str = '';
		var arr = this[listId];
		for (var i = 0; i < arr.length; i++) {
			str = '
' + this.listLine(mode, listId, arr, i) + '
\n' + str;
		}
		str = '
\n' + str + '
\n';

		var listDiv = document.getElementById('pwe-' + listId);
		listDiv.innerHTML = str;
	}

	this.updateLists = function() {
		this.updateList('releases');
		this.updateList('groups');
		this.updateList('people');
		this.updateList('works');
	}

	listToEntity = {
		releases: 'release',
		groups: 'artist',
		people: 'artist',
		works: 'work',
	};

	this.listLine = function(mode, listId, arr, i) {
		var cmd = '⊗';
		if (mode == 'rel') {
			cmd += '◗';
			cmd += '◖';
		}
		return cmd + '' + arr[i].title + '';
	}

	this.memorize = function(listId, title, href) {
		var id = href.replace(/^.*\//, '');
		var arr = this[listId];

		// Check if it already exists
		for (var i = 0; i < arr.length; i++) {
			if (arr[i].id == id) {
				// Already exists, do nothing
				// TODO: pump it to the top of the list
				return;
			}
		}
		arr.push({id: id, title: title});
		this.saveToStorage();

		this.updateList(listId);
	}

	this.grabCurrentPageEntities = function() {
		var content = document.getElementById('content');

		// No content on this page? We won't grab anything
		if (!content)
			return;

		var hdr = content.firstElementChild;
		if (hdr.className == 'releaseheader') {
			// Release page
			var link = hdr.firstElementChild.firstElementChild;
			this.memorize('releases', link.innerHTML, link.href);
		}
		if (content.firstElementChild.className == 'artistheader') {
			// Artist page
			var artistType = hdr.children[1].innerText;
			var link = hdr.firstElementChild.firstElementChild;
			if (artistType == '~ Person') {
				this.memorize('people', link.innerHTML, link.href);
			} else if (artistType == '~ Group') {
				this.memorize('groups', link.innerHTML, link.href);
			}
		}
		if (hdr.className == 'workheader') {
			// Work page
			var link = hdr.firstElementChild.firstElementChild;
			this.memorize('works', link.innerHTML, link.href);
		}
	}

	this.modifyPage = function() {
		// Add "relate work" buttons to all tracks, if applicable
		var r = document.evaluate('//*[@rel="mo:track"]', document, null, XPathResult.ANY_TYPE, null);
		var tracks = [];
		var n = r.iterateNext();
		while (n) {
			tracks.push(n);
			n = r.iterateNext();
		}
		for (var i = 0; i < tracks.length; i++) {
			var td = tracks[i].children[1];

			// Check if we already have some recording relationships
			var ars = td.getElementsByClassName('ars');
			if (ars.length > 0) {
				// We do => don't show any buttons
				continue;
			}

			var title = td.getElementsByTagName('span')[0].getAttribute('content');
			var id = td.getElementsByTagName('a')[0].getAttribute('resource');
			id = id.replace(/^.*\//, '').replace(/#_$/, '');

			// setTimeout is a hack to make sure that relate
			// to dialog would be shown, despite on "hide"
			// default action firing on any onclick event in
			// the body; it's lame, but it works for now
			td.innerHTML = '<button class="cmd" id="pwe-relcmd' + i + '" onclick="setTimeout(function(){pwe.relateRecToWork(' + i + ', \'' + id + '\', \'' + title + '\');}, 50); return false;">○</button>' + td.innerHTML;
		}
	}

	allModes = [
		'rel',
		'recwork',
	];

	this.updateMode = function(newMode) {
		for (var i = 0; i < allModes.length; i++) {
			var el = document.getElementById('pwe-mode-' + allModes[i]);
			el.style.display = (allModes[i] == newMode) ? 'block' : 'none';
		}
		this.updateLists();
	}

	this.forget = function(listId, num) {
		this[listId].splice(num, 1);
		this.updateList(listId);
		this.saveToStorage();
	}

	this.relate = function(side, listId, num) {
		relName = (side == 0) ? 'relL' : 'relR';
		var el = this[listId][num];
		if (el[relName]) {
			delete el[relName];
		} else {
			el[relName] = 1;
		}
		this.updateList(listId);
		this.saveToStorage();
	}

	this.go = function() {
		var mode = document.getElementById('pwe-mode').value;

		if (mode == 'rel') {
			this.goRel();
		} else {
			console.error("Unknown mode: " + mode);
		}
	}

	this.goRel = function() {
		var arrL = this.groups;
		var arrR = this.people;

		var indL = null;
		for (var i = 0; i < arrL.length; i++) {
			if (arrL[i].relL == 1) {
				indL = i;
				break;
			}
		}
		if (indL == null) {
			alert("No group chosen");
			return;
		}
		var elL = arrL[indL];

		var indR = null;
		for (var i = 0; i < arrR.length; i++) {
			if (arrR[i].relR == 1) {
				indR = i;
				break;
			}
		}
		if (indR == null) {
			alert("No member chosen");
			return;
		}
		var elR = arrR[indR];

		window.location.href = 'http://musicbrainz.org/edit/relationship/create?type0=artist&type1=artist&entity0=' + elL.id + '&entity1=' + elR.id;
	}

	this.relateRecToWork = function(num, recId, title) {
		var btn = $('#pwe-relcmd' + num);

		// Show relateTo dialog
		var relateTo = MB.Control.RelateTo();
		relateTo.$relate.appendTo($('body')).show();
		relateTo.$relate.offset(btn.offset());

		// Set up "from" entity
		relateTo.$type0 = { val: function() { return 'recording'; }};
		relateTo.$gid0 = { val: function() { return recId; }};

		// Search for work title = recording title
		relateTo.$select.val('work');
		relateTo.autocomplete.changeEntity('work');
		relateTo.autocomplete.$input.val(title);
		relateTo.autocomplete.searchAgain();
	}

	this.settingsDialog = function() {
		document.forms.pweSettings.elements.fixRounded.checked = this.settings.fixRounded;
		document.getElementById('pwe-settings-panel').style.display = 'block';
	}

	this.settingsOk = function() {
		this.settings.fixRounded = document.forms.pweSettings.elements.fixRounded.checked;
		this.saveToStorage();
		this.settingsClose();
	}

	this.settingsClose = function() {
		document.getElementById('pwe-settings-panel').style.display = 'none';
	}

	this.releases = this.loadJSONArrayFromStorage('pwe_releases');
	this.groups = this.loadJSONArrayFromStorage('pwe_groups');
	this.people = this.loadJSONArrayFromStorage('pwe_people');
	this.works = this.loadJSONArrayFromStorage('pwe_works');
	this.settings = this.loadJSONObjectFromStorage('pwe_settings');

	this.addPowerEditorPanel();
	this.grabCurrentPageEntities();
	this.modifyPage();
}

// Trick to escape default userscripts scope into global window scope
var script = document.createElement('script');
script.appendChild(document.createTextNode('' + PowerEditor + '; window.pwe = new PowerEditor();'));
document.body.appendChild(script);
<commit_msg>Added multiple work gathering algorithm from a table<commit_after>// ==UserScript==
// @name          MusicBrainz power editor
// @description   Provide power editor tools for quick massive editing in MusicBrainz
// @include       http://musicbrainz.org/*
// @match         http://musicbrainz.org/*
// ==/UserScript==

function PowerEditor() {
	function prependChild(whereTo, what) {
		var whereToFc = whereTo.firstChild;
		whereTo.insertBefore(what, whereToFc);
	}

	this.addPowerEditorPanel = function() {
		// Add styles
		var styles = document.createElement('style');
		styles.innerHTML = '' +
			'body { position: relative; padding: 0 0 0 30.5em; }\n' +
			'#pwe-panel { position: absolute; top: 0; bottom: 0; left: 0; width: 30em; }\n' +
			'#pwe-panel-back { padding: 0 0.5em; background: #ffffd8; }\n' +
			'#pwe-go { width: 10em; float: right; }\n' +
			'#pwe-mode { width: auto; }\n' +
			'.cmd { width: 2em; float: right; background: #ccc; display: inline-block; text-align: center; border: 1px solid #999; cursor: pointer; }\n' +
			'#pwe-panel .checked { background: #999; border: 1px solid #555; }\n' +
			'#pwe-panel .settings-button { display: inline-block; float: right; background: #ccc; border: 1px solid #999; cursor: pointer; padding: 0 1em; }\n' +
			'#pwe-settings-panel { position: absolute; width: 30em; height: 15em; top: 5em; left: 20em; z-index: 100500; background: #eee; border: 1px solid #a1a1a1; padding: 0.5em 1em; display: none; }\n' +
			'#pwe-settings button { width: 10em; padding: 0 5em; }\n' +
			'#header-menu div.l { display: none; }\n' +
			'#header-menu div.r { display: none; }\n' +
			'#header-menu { border-bottom-right-radius: 8px; border-bottom-left-radius: 8px; }\n' +
			'.br { display: none !important; }\n' +
			'.bl { display: none !important; }\n' +
			'.tr { display: none !important; }\n' +
			'.tl { display: none !important; }\n' +
			'#page { border-radius: 8px; }\n' +
			'';
		prependChild(document.body, styles);

		// Add panel
		var panel = document.createElement('div');
		panel.setAttribute('id', 'pwe-panel');

		panel.innerHTML = '' +
			'
\n' +
			'settings\n' +
			'
Power editor
\n' +
			'
\n' +
			'<button type="button" id="pwe-go" onclick="pwe.go()">Go!</button>\n' +
			'Mode: <select id="pwe-mode" onchange="pwe.updateMode(this.value)">\n' +
			'<option value="rel">Relate</option>\n' +
			'<option value="recwork">Rec → Work</option>\n' +
			'</select>\n' +
			'
\n' +
			'
Relationships...
\n' +
			'
Rec - work...
\n' +
			'
Music
\n' +
			'

\n' +
			'
Group
\n' +
			'

\n' +
			'
People
\n' +
			'

\n' +
			'
Works
\n' +
			'

\n' +
			'
\n' +
			'
Settings - Power MusicBrainz Editor
\n' +
			'<form name="pweSettings">\n' +
			'
\n' +
			'<input type="checkbox" name="fixRounded"/>' +
			'Fix rounded corners\n' +
			'
\n' +
			'<button type="button" onclick="pwe.settingsOk()">OK</button>\n' +
			'<button type="button" onclick="pwe.settingsClose()">Cancel</button>\n' +
			'</form>\n' +
			'
\n' +
			'
\n';

		prependChild(document.body, panel);

		this.updateMode('rel');
	}

	this.loadJSONArrayFromStorage = function(key) {
		var str = localStorage[key];
		if (str) {
			return JSON.parse(str);
		} else {
			return [];
		}
	}

	this.loadJSONObjectFromStorage = function(key) {
		var str = localStorage[key];
		if (str) {
			return JSON.parse(str);
		} else {
			return {};
		}
	}

	this.saveToStorage = function() {
		localStorage['pwe_releases'] = JSON.stringify(this.releases);
		localStorage['pwe_groups'] = JSON.stringify(this.groups);
		localStorage['pwe_people'] = JSON.stringify(this.people);
		localStorage['pwe_works'] = JSON.stringify(this.works);
		localStorage['pwe_settings'] = JSON.stringify(this.settings);
	}

	this.updateList = function(listId) {
		var mode = document.getElementById('pwe-mode').value;

		var str = '';
		var arr = this[listId];
		for (var i = 0; i < arr.length; i++) {
			str = '
' + this.listLine(mode, listId, arr, i) + '
\n' + str;
		}
		str = '
\n' + str + '
\n';

		var listDiv = document.getElementById('pwe-' + listId);
		listDiv.innerHTML = str;
	}

	this.updateLists = function() {
		this.updateList('releases');
		this.updateList('groups');
		this.updateList('people');
		this.updateList('works');
	}

	listToEntity = {
		releases: 'release',
		groups: 'artist',
		people: 'artist',
		works: 'work',
	};

	this.listLine = function(mode, listId, arr, i) {
		var cmd = '⊗';
		if (mode == 'rel') {
			cmd += '◗';
			cmd += '◖';
		}
		return cmd + '' + arr[i].title + '';
	}

	this.memorize = function(listId, title, href) {
		var list = this[listId];
		this.memorizeOne(list, title, href);
		this.saveToStorage();
		this.updateList(listId);
	}

	this.memorizeOne = function(list, title, href) {
		var id = href.replace(/^.*\//, '');
		// Check if it already exists
		for (var i = 0; i < list.length; i++) {
			if (list[i].id == id) {
				// Already exists, do nothing
				// TODO: pump it to the top of the list
				return;
			}
		}
		list.push({id: id, title: title});
	}

	this.memorizeArray = function(listId, arr) {
		var list = this[listId];
		for (var i = 0; i < arr.length; i++) {
			this.memorizeOne(list, arr[i].title, arr[i].href);
		}
		this.saveToStorage();
		this.updateList(listId);
	}

	this.grabCurrentPageEntities = function() {
		var content = document.getElementById('content');

		// No content on this page? We won't grab anything
		if (!content)
			return;

		var hdr = content.firstElementChild;
		if (hdr.className == 'releaseheader') {
			// Release page
			var link = hdr.firstElementChild.firstElementChild;
			this.memorize('releases', link.innerHTML, link.href);
		}
		if (content.firstElementChild.className == 'artistheader') {
			// Artist page
			var artistType = hdr.children[1].innerText;
			var link = hdr.firstElementChild.firstElementChild;
			if (artistType == '~ Person') {
				this.memorize('people', link.innerHTML, link.href);
			} else if (artistType == '~ Group') {
				this.memorize('groups', link.innerHTML, link.href);
			}
		}
		if (hdr.className == 'workheader') {
			// Work page
			var link = hdr.firstElementChild.firstElementChild;
			this.memorize('works', link.innerHTML, link.href);
		}

		// Find works in the main content area
		var r = document.evaluate("//div[@id='content']//a[contains(@href, '/work/')]", document, null, XPathResult.ANY_TYPE, null);
		var wrk = r.iterateNext();
		var wrks = [];
		while (wrk) {
			console.debug(wrk);
			console.debug(wrk.innerText);
			console.debug(wrk.href);
			wrks.push({href: wrk.href, title: wrk.innerText});
			wrk = r.iterateNext();
		}
		if (wrks.length > 0) {
			this.memorizeArray('works', wrks);
		}
	}

	this.modifyPage = function() {
		// Add "relate work" buttons to all tracks, if applicable
		var r = document.evaluate('//*[@rel="mo:track"]', document, null, XPathResult.ANY_TYPE, null);
		var tracks = [];
		var n = r.iterateNext();
		while (n) {
			tracks.push(n);
			n = r.iterateNext();
		}
		for (var i = 0; i < tracks.length; i++) {
			var td = tracks[i].children[1];

			// Check if we already have some recording relationships
			var ars = td.getElementsByClassName('ars');
			if (ars.length > 0) {
				// We do => don't show any buttons
				continue;
			}

			var title = td.getElementsByTagName('span')[0].getAttribute('content');
			var id = td.getElementsByTagName('a')[0].getAttribute('resource');
			id = id.replace(/^.*\//, '').replace(/#_$/, '');

			// setTimeout is a hack to make sure that relate
			// to dialog would be shown, despite on "hide"
			// default action firing on any onclick event in
			// the body; it's lame, but it works for now
			td.innerHTML = '<button class="cmd" id="pwe-relcmd' + i + '" onclick="setTimeout(function(){pwe.relateRecToWork(' + i + ', \'' + id + '\', \'' + title + '\');}, 50); return false;">○</button>' + td.innerHTML;
		}
	}

	allModes = [
		'rel',
		'recwork',
	];

	this.updateMode = function(newMode) {
		for (var i = 0; i < allModes.length; i++) {
			var el = document.getElementById('pwe-mode-' + allModes[i]);
			el.style.display = (allModes[i] == newMode) ? 'block' : 'none';
		}
		this.updateLists();
	}

	this.forget = function(listId, num) {
		this[listId].splice(num, 1);
		this.updateList(listId);
		this.saveToStorage();
	}

	this.relate = function(side, listId, num) {
		relName = (side == 0) ? 'relL' : 'relR';
		var el = this[listId][num];
		if (el[relName]) {
			delete el[relName];
		} else {
			el[relName] = 1;
		}
		this.updateList(listId);
		this.saveToStorage();
	}

	this.go = function() {
		var mode = document.getElementById('pwe-mode').value;

		if (mode == 'rel') {
			this.goRel();
		} else {
			console.error("Unknown mode: " + mode);
		}
	}

	this.goRel = function() {
		var arrL = this.groups;
		var arrR = this.people;

		var indL = null;
		for (var i = 0; i < arrL.length; i++) {
			if (arrL[i].relL == 1) {
				indL = i;
				break;
			}
		}
		if (indL == null) {
			alert("No group chosen");
			return;
		}
		var elL = arrL[indL];

		var indR = null;
		for (var i = 0; i < arrR.length; i++) {
			if (arrR[i].relR == 1) {
				indR = i;
				break;
			}
		}
		if (indR == null) {
			alert("No member chosen");
			return;
		}
		var elR = arrR[indR];

		window.location.href = 'http://musicbrainz.org/edit/relationship/create?type0=artist&type1=artist&entity0=' + elL.id + '&entity1=' + elR.id;
	}

	this.relateRecToWork = function(num, recId, title) {
		var btn = $('#pwe-relcmd' + num);

		// Show relateTo dialog
		var relateTo = MB.Control.RelateTo();
		relateTo.$relate.appendTo($('body')).show();
		relateTo.$relate.offset(btn.offset());

		// Set up "from" entity
		relateTo.$type0 = { val: function() { return 'recording'; }};
		relateTo.$gid0 = { val: function() { return recId; }};

		// Search for work title = recording title
		relateTo.$select.val('work');
		relateTo.autocomplete.changeEntity('work');
		relateTo.autocomplete.$input.val(title);
		relateTo.autocomplete.searchAgain();
	}

	this.settingsDialog = function() {
		document.forms.pweSettings.elements.fixRounded.checked = this.settings.fixRounded;
		document.getElementById('pwe-settings-panel').style.display = 'block';
	}

	this.settingsOk = function() {
		this.settings.fixRounded = document.forms.pweSettings.elements.fixRounded.checked;
		this.saveToStorage();
		this.settingsClose();
	}

	this.settingsClose = function() {
		document.getElementById('pwe-settings-panel').style.display = 'none';
	}

	this.releases = this.loadJSONArrayFromStorage('pwe_releases');
	this.groups = this.loadJSONArrayFromStorage('pwe_groups');
	this.people = this.loadJSONArrayFromStorage('pwe_people');
	this.works = this.loadJSONArrayFromStorage('pwe_works');
	this.settings = this.loadJSONObjectFromStorage('pwe_settings');

	this.addPowerEditorPanel();
	this.grabCurrentPageEntities();
	this.modifyPage();
}

// Trick to escape default userscripts scope into global window scope
var script = document.createElement('script');
script.appendChild(document.createTextNode('' + PowerEditor + '; window.pwe = new PowerEditor();'));
document.body.appendChild(script);
<|endoftext|>


<commit_before>module.exports = function(api) {
  var validEnv = ['development', 'test', 'production']
  var currentEnv = api.env()
  var isDevelopmentEnv = api.env('development')
  var isProductionEnv = api.env('production')
  var isTestEnv = api.env('test')

  if (!validEnv.includes(currentEnv)) {
    throw new Error(
      'Please specify a valid `NODE_ENV` or ' +
        '`BABEL_ENV` environment variables. Valid values are "development", ' +
        '"test", and "production". Instead, received: ' +
        JSON.stringify(currentEnv) +
        '.'
    )
  }

  return {
    presets: [
      isTestEnv && [
        '@babel/preset-env',
        {
          targets: {
            node: 'current'
          }
        }
      ],
      (isProductionEnv || isDevelopmentEnv) && [
        '@babel/preset-env',
        {
          forceAllTransforms: true,
          useBuiltIns: 'entry',
          corejs: 3,
          modules: false,
          exclude: ['transform-typeof-symbol']
        }
      ]
    ].filter(Boolean),
    plugins: [
      'babel-plugin-macros',
      '@babel/plugin-syntax-dynamic-import',
      isTestEnv && 'babel-plugin-dynamic-import-node',
      '@babel/plugin-transform-destructuring',
      [
        '@babel/plugin-proposal-class-properties',
        {
          loose: true
        }
      ],
      [
        '@babel/plugin-proposal-object-rest-spread',
        {
          useBuiltIns: true
        }
      ],
      [
        '@babel/plugin-transform-runtime',
        {
          helpers: false,
          regenerator: true,
          corejs: false
        }
      ],
      [
        '@babel/plugin-transform-regenerator',
        {
          async: false
        }
      ]
    ].filter(Boolean)
  }
}
<commit_msg>Add React preset<commit_after>module.exports = function(api) {
  var validEnv = ['development', 'test', 'production']
  var currentEnv = api.env()
  var isDevelopmentEnv = api.env('development')
  var isProductionEnv = api.env('production')
  var isTestEnv = api.env('test')

  if (!validEnv.includes(currentEnv)) {
    throw new Error(
      'Please specify a valid `NODE_ENV` or ' +
        '`BABEL_ENV` environment variables. Valid values are "development", ' +
        '"test", and "production". Instead, received: ' +
        JSON.stringify(currentEnv) +
        '.'
    )
  }

  return {
    presets: [
      isTestEnv && [
        '@babel/preset-env',
        '@babel/preset-react',
        {
          targets: {
            node: 'current'
          }
        }
      ],
      (isProductionEnv || isDevelopmentEnv) && [
        '@babel/preset-env',
        '@babel/preset-react',
        {
          forceAllTransforms: true,
          useBuiltIns: 'entry',
          corejs: 3,
          modules: false,
          exclude: ['transform-typeof-symbol']
        }
      ]
    ].filter(Boolean),
    plugins: [
      'babel-plugin-macros',
      '@babel/plugin-syntax-dynamic-import',
      isTestEnv && 'babel-plugin-dynamic-import-node',
      '@babel/plugin-transform-destructuring',
      [
        '@babel/plugin-proposal-class-properties',
        {
          loose: true
        }
      ],
      [
        '@babel/plugin-proposal-object-rest-spread',
        {
          useBuiltIns: true
        }
      ],
      [
        '@babel/plugin-transform-runtime',
        {
          helpers: false,
          regenerator: true,
          corejs: false
        }
      ],
      [
        '@babel/plugin-transform-regenerator',
        {
          async: false
        }
      ]
    ].filter(Boolean)
  }
}
<|endoftext|>


<commit_before>/* Set up the environment before loading the rest of the files into Zotero */
Zotero.RDF.AJAW = {
  Util: {
    ArrayIndexOf: function (arr, item, i) {
      //supported in all browsers except IE<9
      return arr.indexOf(item, i);
    },
    RDFArrayRemove: function (a, x) { //removes all statements equal to x from a
      for(var i = 0; i < a.length; i++) {
        //TODO: This used to be the following, which didnt always work..why
        //if(a[i] == x)
        if(a[i].subject.sameTerm(x.subject)
          && a[i].predicate.sameTerm(x.predicate)
          && a[i].object.sameTerm(x.object)
          && a[i].why.sameTerm(x.why)) {
          a.splice(i, 1);
          return;
        }
      }
      throw "RDFArrayRemove: Array did not contain " + x;
    },
  },
  tabulator: {
  	log: {
    	debug: Zotero.debug,
    	warn: Zotero.debug
  	}
	},
	alert: Zotero.debug
};

Zotero.RDF.AJAW.$rdf = Zotero.RDF.AJAW;
<commit_msg>Get tabulator code working in connector after upgrade, part 1<commit_after>/* Set up the environment before loading the rest of the files into Zotero */
var $rdf = {
  Util: {
    ArrayIndexOf: function (arr, item, i) {
      //supported in all browsers except IE<9
      return arr.indexOf(item, i);
    },
    RDFArrayRemove: function (a, x) { //removes all statements equal to x from a
      for(var i = 0; i < a.length; i++) {
        //TODO: This used to be the following, which didnt always work..why
        //if(a[i] == x)
        if(a[i].subject.sameTerm(x.subject)
          && a[i].predicate.sameTerm(x.predicate)
          && a[i].object.sameTerm(x.object)
          && a[i].why.sameTerm(x.why)) {
          a.splice(i, 1);
          return;
        }
      }
      throw "RDFArrayRemove: Array did not contain " + x;
    },
  },
  tabulator: {
  	log: {
    	debug: Zotero.debug,
    	warn: Zotero.debug
  	}
	},
	alert: Zotero.debug
};

if(!Zotero.RDF) {	// For connector
	Zotero.RDF = {AJAW:$rdf};
} else {			// For extension
	Zotero.RDF.AJAW.$rdf = $rdf;
}<|endoftext|>


<commit_before>require("dotenv").config();
const keysEnvVar = process.env["GOOGLE_TRANSLATE_CREDENTIALS"];
const csvtojsonV2 = require("csvtojson/v2");
const { Translate } = require("@google-cloud/translate").v2;
const authKeys = JSON.parse(keysEnvVar);
authKeys["key"] = process.env.GOOGLE_API_KEY;
const translate = new Translate(authKeys);

let loadedCSV;
let highScoreEntries = [];
const lowScoreEntries = [];
const { Client } = require("pg");
const client = new Client(process.env.DATABASE_URL);
let loadingCSV = false;
const itemsToTranslate = 1;
const fileName = "case";
const fileToWriteName = "case_report";

if (!keysEnvVar) {
  throw new Error(
    "The GOOGLE_TRANSLATE_CREDENTIALS environment variable was not found!"
  );
  return;
}

function loadCsvAsJSON(fileName = "case_test") {
  const csvFilePath = `csvs/${fileName}.csv`;
  loadedCSV = null;
  loadingCSV = true;
  return csvtojsonV2()
    .fromFile(csvFilePath)
    .then(
      jsonObj => {
        loadedCSV = jsonObj;
        loadingCSV = false;
        return Promise.resolve();
      },
      err => {
        console.log("Loading CSV failed", err);
        loadingCSV = false;
        return Promise.reject();
      }
    );
}

function filterHighScoreEntries() {
  if (loadedCSV) {
    const filtered = loadedCSV.filter((el, i) => {
      return (
        Number(el.Score) > 0.9 &&
        el.language === el.original_language &&
        el.languageDetected !== el.language
      );
    });
    highScoreEntries = filtered;
    console.log(highScoreEntries);
    return filtered;
  }
  throw new Error("CSV entries not found");
}

async function saveRecord(record) {
  const { body, title, description, language } = record;
  const query = `UPDATE localized_texts lt SET lt.body = $1, lt.title = $2, lt.description = $3, lt.language = $4 WHERE id = ${record.id} RETURNING *`;
  client.query(query, [body, title, description, language], (err, res) => {
    if (err) {
      console.log(err.stack);
    } else {
      console.log("Updated: ", JSON.stringify(res.rows[0]));
      writeToCSVFile(res.rows[0]);
    }
  });
}

async function getRecordToCopy(thingID, language, detected_language) {
  const query = `SELECT * FROM localized_texts lt LEFT JOIN things t ON t.id = lt.thingid WHERE lt.thingid = ${thingID} AND lt.language = '${language}' AND lt.language != '${detected_language}' ORDER BY timestamp DESC LIMIT 1`;
  return client.query(query).then(
    reslt => {
      return reslt.rows[0];
    },
    err => console.log("Record fetch failed", err)
  );
}

async function translateText(text, targetLanguage) {
  const target = targetLanguage;
  const [translation] = await translate
    .translate(text, target)
    .catch(function(error) {
      console.log(error);
    });
  return translation;
}

async function writeToCSVFile(data) {
  const opts = {
    fields: [
      "textSample",
      "languageDetected",
      "original_language",
      "language",
      "Score",
      "thingID",
    ],
    fieldNames: [
      "Detected Language",
      "Original Language",
      "Language",
      "Confidence",
      "Thing ID",
    ],
  };
  const filePath = "csvs/" + fileToWriteName + ".csv";
  try {
    let parser;
    let csv;
    if (fs.existsSync(filePath)) {
      parser = new Parser();
      csv = parser.parse(data);
      csv = csv.replace(
        '"textSample","languageDetected","original_language","language","Score","thingID"\n',
        ""
      );

      fs.appendFileSync(filePath, `\n${csv}`);
    } else {
      parser = new Parser(opts);
      csv = parser.parse(data);
      fs.writeFileSync(filePath, csv);
    }
  } catch (err) {
    console.error(err);
  }
}

function copyEntry(entryData) {
  saveRecord(entryData);
}

client.connect().then(res => {
  loadCsvAsJSON(fileName).then(res => {
    filterHighScoreEntries();
    highScoreEntries
      .splice(0, itemsToTranslate || Infinity)
      .forEach((el, i) => {
        getRecordToCopy(
          el.thingID,
          el.original_language,
          el.languageDetected
        ).then(res => {
          // translateText(res.description || res.text, el.language);
          copyEntry(res);
        });
      });
  });
});
<commit_msg>Translated languages that do not match<commit_after>require("dotenv").config();
const fs = require("fs");
const { Parser } = require("json2csv");
const { htmlToText } = require("html-to-text");
const keysEnvVar = process.env["GOOGLE_TRANSLATE_CREDENTIALS"];
const csvtojsonV2 = require("csvtojson/v2");
const { Translate } = require("@google-cloud/translate").v2;
const authKeys = JSON.parse(keysEnvVar);
authKeys["key"] = process.env.GOOGLE_API_KEY;
const translate = new Translate(authKeys);

let loadedCSV;
let highScoreEntries = [];
const lowScoreEntries = [];
const { Client } = require("pg");
const client = new Client(process.env.DATABASE_URL);
let loadingCSV = false;
const itemsToTranslate = 10;
const fileName = "case";
const fileToWriteName = "case_report";

if (!keysEnvVar) {
  throw new Error(
    "The GOOGLE_TRANSLATE_CREDENTIALS environment variable was not found!"
  );
  return;
}

function loadCsvAsJSON(fileName = "case_test") {
  const csvFilePath = `csvs/${fileName}.csv`;
  loadedCSV = null;
  loadingCSV = true;
  return csvtojsonV2()
    .fromFile(csvFilePath)
    .then(
      jsonObj => {
        loadedCSV = jsonObj;
        loadingCSV = false;
        return Promise.resolve();
      },
      err => {
        console.log("Loading CSV failed", err);
        loadingCSV = false;
        return Promise.reject();
      }
    );
}

function filterHighScoreEntries() {
  if (loadedCSV) {
    const filtered = loadedCSV.filter((el, i) => {
      return (
        Number(el.Score) > 0.9 &&
        el.language === el.original_language &&
        el.languageDetected !== el.language
      );
    });
    highScoreEntries = filtered;
    console.log(highScoreEntries);
    return filtered;
  }
  throw new Error("CSV entries not found");
}

async function saveRecord(record) {
  const { body, description } = record;
  const query = `UPDATE localized_texts SET body = $1, description = $2 WHERE ctid = (SELECT ctid FROM localized_texts lt WHERE lt.thingid = ${record.id} AND lt.language = '${record.language}' ORDER BY timestamp DESC LIMIT 1) RETURNING *, ctid`;
  client.query(query, [body, description], (err, res) => {
    if (err) {
      console.log(err.stack);
    } else {
      console.info("Updated data: ", JSON.stringify(res.rows[0]));
      const { body, description, thingid, language } = res.rows[0];
      writeToCSVFile({
        textSample: htmlToText(
          description && description.trim().length
            ? description.substr(0, 150)
            : body.substr(0, 150) || ""
        ),
        language,
        thingid,
      });
    }
  });
}

async function getRecordToCopy(thingID, language, detected_language) {
  const query = `SELECT * FROM localized_texts lt LEFT JOIN things t ON t.id = lt.thingid WHERE lt.thingid = ${thingID} AND lt.language = '${language}' ORDER BY timestamp DESC LIMIT 1`;
  return client.query(query).then(
    reslt => {
      return reslt.rows[0];
    },
    err => console.log("Record fetch failed", err)
  );
}

async function translateText(text, targetLanguage) {
  const target = targetLanguage;
  const [translation] = await translate
    .translate(text, target)
    .catch(function(error) {
      console.log(error);
    });
  return translation;
}

async function writeToCSVFile(data) {
  const opts = {
    fields: ["textSample", "language", "thingid"],
    fieldNames: ["Sample", "Language", "Thing ID"],
  };
  const filePath = "csvs/" + fileToWriteName + ".csv";
  try {
    let parser;
    let csv;
    if (fs.existsSync(filePath)) {
      parser = new Parser();
      csv = parser.parse(data);
      csv = csv.replace(
        '"textSample","languageDetected","original_language","language","Score","thingID"\n',
        ""
      );

      fs.appendFileSync(filePath, `\n${csv}`);
    } else {
      parser = new Parser(opts);
      csv = parser.parse(data);
      fs.writeFileSync(filePath, csv);
    }
  } catch (err) {
    console.error(err);
  }
}

function copyEntry(entryData) {
  saveRecord(entryData);
}

client.connect().then(res => {
  loadCsvAsJSON(fileName).then(res => {
    filterHighScoreEntries();
    highScoreEntries
      .splice(0, itemsToTranslate || Infinity)
      .forEach((el, i) => {
        getRecordToCopy(
          el.thingID,
          el.original_language,
          el.languageDetected
        ).then(res => {
          translateText(res.description || res.body, el.language).then(
            reslt => {
              if (res.description.trim().length > 0) {
                res.description = reslt;
              } else {
                res.body = reslt;
              }
              copyEntry(res);
            }
          );
        });
      });
  });
});
<|endoftext|>


<commit_before>let mongoose = require("mongoose");
let Pahlawan = require('./pahlawan');

//Require the dev-dependencies
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('./index');
let should = chai.should();

chai.use(chaiHttp);

describe('/GET pahlawan', () => {
    it('it should GET all the pahlawan', (done) => {
        chai.request(server)
            .get('/api/pahlawan')
            .end((err, res) => {
                res.should.have.status(200);
                res.body.should.be.a('array');
                res.body[0].should.have.property('_id');
                res.body[0].should.have.property('name');
                res.body[0].should.have.property('area');
                res.body[0].name.should.equal('Cut Nyak Dhien');
                res.body[0].area.should.equal('Aceh');
                done();
            });
    });
});

// describe('/POST pahlawan', () => {
//     // it('it should not POST a pahlawan without pages field', (done) => {
//     //   let pahlawan = {
//     //       title: "The Lord of the Rings",
//     //       author: "J.R.R. Tolkien",
//     //       year: 1954
//     //   }
//     //       chai.request(server)
//     //       .post('/pahlawan')
//     //       .send(pahlawan)
//     //       .end((err, res) => {
//     //           res.should.have.status(200);
//     //           res.body.should.be.a('object');
//     //           res.body.should.have.property('errors');
//     //           res.body.errors.should.have.property('pages');
//     //           res.body.errors.pages.should.have.property('kind').eql('required');
//     //         done();
//     //       });
//     // });
//     it('it should POST a pahlawan ', (done) => {
//         let pahlawan = {
//             name: "Pangeran Diponegoro",
//             area: "Jogja",
//             senjata: "keris",
//             die: "50",

//         }
//         chai.request(server)
//             .post('/api/pahlawan')
//             .send(pahlawan)
//             .end((err, res) => {
//                 var firstItem = body.items[0];
//                 res.should.have.status(200);
//                 res.body.should.be.a('object');
//                 res.firstItem.should.have.property('message').eql('Pahlawan created!');
//                 res.firstItem.should.have.property('name');
//                 res.firstItem.should.have.property('area');
//                 // res.body.pahlawan.should.have.property('senjata');
//                 // res.body.pahlawan.should.have.property('die');
//                 done();
//             });
//     });
// });<commit_msg>Modified unnecessary test<commit_after>let mongoose = require("mongoose");
let Pahlawan = require('./pahlawan');

//Require the dev-dependencies
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('./index');
let should = chai.should();

chai.use(chaiHttp);

describe('/GET pahlawan', () => {
    it('it should GET all the pahlawan', (done) => {
        chai.request(server)
            .get('/api/pahlawan')
            .end((err, res) => {
                res.should.have.status(200);
                res.body.should.be.a('array');
                res.body[0].should.have.property('_id');
                res.body[0].should.have.property('name');
                res.body[0].should.have.property('area');
                res.body[0].name.should.equal('Cut Nyak Dhien');
                res.body[0].area.should.equal('Aceh');
                done();
            });
    });
});

//     it('it should POST a pahlawan ', (done) => {
//         let pahlawan = {
//             name: "Pangeran Diponegoro",
//             area: "Jogja",
//             senjata: "keris",
//             die: "50",

//         }
//         chai.request(server)
//             .post('/api/pahlawan')
//             .send(pahlawan)
//             .end((err, res) => {
//                 var firstItem = body.items[0];
//                 res.should.have.status(200);
//                 res.body.should.be.a('object');
//                 res.firstItem.should.have.property('message').eql('Pahlawan created!');
//                 res.firstItem.should.have.property('name');
//                 res.firstItem.should.have.property('area');
//                 // res.body.pahlawan.should.have.property('senjata');
//                 // res.body.pahlawan.should.have.property('die');
//                 done();
//             });
//     });
// });<|endoftext|>


<commit_before>"use strict";

var http = require('http');
var path = require('path');
var fs = require('fs');
var mime = require('mime');

function send404 (response) {
	response.writeHead(404, {"Content-type" : "text/plain"});
	response.write("Error 404: Resource not found");
	response.end();
}

function sendPage (response, filePath, fileContents) {
	response.writeHead(200, { "Content-type": mime.lookup(path.basename(filePath)) });
	response.end(fileContents);
}

function serverWorking (response, absPath) {
	fs.exists(absPath, function(exists) {
		if (exists) {
			fs.readFile(absPath, function (e, data) {
				if (e) send404(response);
				else sendPage(response, absPath, data);
			});
		} else send404(response);
	});
}

var server = http.createServer(function (request, response) {
	var filePath;
	if (request.url === '/') filePath = 'index.html';
	else if (request.url.indexOf('/bus-tracker') === 0) filePath = 'bus-tracker.html';
	else filePath = request.url;

	serverWorking(response, "./" + filePath);
});

server.listen(process.env.PORT || 8080);
console.log("Please go to http://127.0.0.1:8080");
<commit_msg>Changed file system readin<commit_after>"use strict";

var http = require('http');
var path = require('path');
var fs = require('fs');
var mime = require('mime');

function send404 (response) {
	response.writeHead(404, {"Content-type" : "text/plain"});
	response.write("Error 404: Resource not found");
	response.end();
}

function sendPage (response, filePath, fileContents) {
	response.writeHead(200, { "Content-type": mime.lookup(path.basename(filePath)) });
	response.end(fileContents);
}

function serverWorking (response, absPath) {
	fs.exists(absPath, function (exists) {
		if (exists) {
			fs.readFile(absPath, function (e, data) {
				if (e) send404(response);
				else sendPage(response, absPath, data);
			});
		} else send404(response);
	});
}

var server = http.createServer(function (request, response) {
	var filePath;
	if (request.url === '/') filePath = 'index.html';
	else if (request.url === '/bus-tracker' || request.url === '/bus-tracker/') filePath = 'bus-tracker.html';
	else filePath = request.url;

	serverWorking(response, "./" + filePath);
});

server.listen(8080);
console.log("Please go to http://127.0.0.1:8080");
<|endoftext|>


<commit_before>// [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
// Author: Larry Kuhns.
//
// ## Description
//
// This file implements articulations and accents as modifiers that can be
// attached to notes. The complete list of articulations is available in
// `tables.js` under `Vex.Flow.articulationCodes`.
//
// See `tests/articulation_tests.js` for usage examples.

import { Vex } from './vex';
import { Flow } from './tables';
import { Modifier } from './modifier';
import { Glyph } from './glyph';
import { Stem } from './stem';

// To enable logging for this class. Set `Vex.Flow.Articulation.DEBUG` to `true`.
function L(...args) { if (Articulation.DEBUG) Vex.L('Vex.Flow.Articulation', args); }

const { ABOVE, BELOW } = Modifier.Position;

const roundToNearestHalf = (mathFn, value) => mathFn(value / 0.5) * 0.5;

// This includes both staff and ledger lines
const isWithinLines = (line, position) => position === ABOVE ? line <= 5 : line >= 1;

const getRoundingFunction = (line, position) => {
  if (isWithinLines(line, position)) {
    if (position === ABOVE) {
      return Math.ceil;
    } else {
      return Math.floor;
    }
  } else {
    return Math.round;
  }
};

const snapLineToStaff = (canSitBetweenLines, line, position, offsetDirection) => {
  // Initially, snap to nearest staff line or space
  const snappedLine = roundToNearestHalf(getRoundingFunction(line, position), line);
  const onStaffLine = snappedLine % 1 === 0;

  const shouldSnapToStaffSpace =
    canSitBetweenLines && isWithinLines(snappedLine, position) && onStaffLine;

  if (shouldSnapToStaffSpace) {
    const HALF_STAFF_SPACE = 0.5;
    return snappedLine + (HALF_STAFF_SPACE * -offsetDirection);
  } else {
    return snappedLine;
  }
};

const getTopY = (note, textLine) => {
  const stave = note.getStave();
  const stemDirection = note.getStemDirection();
  const { topY: stemTipY, baseY: stemBaseY } = note.getStemExtents();

  if (note.getCategory() === 'stavenotes') {
    if (stemDirection === Stem.UP) {
      return stemTipY;
    } else {
      return stemBaseY;
    }
  } else if (note.getCategory() === 'tabnotes') {
    if (note.hasStem()) {
      if (stemDirection === Stem.UP) {
        return stemTipY;
      } else {
        return stave.getYForTopText(textLine);
      }
    } else {
      return stave.getYForTopText(textLine);
    }
  } else {
    throw new Vex.RERR(
      'UnknownCategory', 'Only can get the top and bottom ys of stavenotes and tabnotes'
    );
  }
};

const getBottomY = (note, textLine) => {
  const stave = note.getStave();
  const stemDirection = note.getStemDirection();
  const { topY: stemTipY, baseY: stemBaseY } = note.getStemExtents();

  if (note.getCategory() === 'stavenotes') {
    if (stemDirection === Stem.UP) {
      return stemBaseY;
    } else {
      return stemTipY;
    }
  } else if (note.getCategory() === 'tabnotes') {
    if (note.hasStem()) {
      if (stemDirection === Stem.UP) {
        return stave.getYForBottomText(textLine);
      } else {
        return stemTipY;
      }
    } else {
      return stave.getYForBottomText(textLine);
    }
  } else {
    throw new Vex.RERR(
      'UnknownCategory', 'Only can get the top and bottom ys of stavenotes and tabnotes'
    );
  }
};

export class Articulation extends Modifier {
  static get CATEGORY() { return 'articulations'; }

  static format(articulations, state) {
    if (!articulations || articulations.length === 0) return false;

    let width = 0;
    for (let i = 0; i < articulations.length; ++i) {
      let increment = 1;
      const articulation = articulations[i];
      width = Math.max(articulation.getWidth(), width);

      const type = Flow.articulationCodes(articulation.type);

      if (!type.between_lines) increment += 1.5;

      if (articulation.getPosition() === ABOVE) {
        articulation.setTextLine(state.top_text_line);
        state.top_text_line += increment;
      } else {
        articulation.setTextLine(state.text_line);
        state.text_line += increment;
      }
    }

    state.left_shift += width / 2;
    state.right_shift += width / 2;
    return true;
  }

  // Create a new articulation of type `type`, which is an entry in
  // `Vex.Flow.articulationCodes` in `tables.js`.
  constructor(type) {
    super();

    this.note = null;
    this.index = null;
    this.type = type;
    this.position = BELOW;
    this.render_options = {
      font_scale: 38,
    };

    this.articulation = Flow.articulationCodes(this.type);
    if (!this.articulation) {
      throw new Vex.RERR('ArgumentError', `Articulation not found: ${this.type}`);
    }

    this.glyph = new Glyph(this.articulation.code, this.render_options.font_scale);

    // Default width comes from articulation table.
    this.setWidth(this.glyph.getMetrics().width);
  }

  getCategory() { return Articulation.CATEGORY; }

  // Render articulation in position next to note.
  draw() {
    const {
      note, index, position, glyph,
      articulation: { between_lines: canSitBetweenLines },
      text_line: textLine,
      context: ctx,
    } = this;

    if (!ctx) {
      throw new Vex.RERR('NoContext', "Can't draw Articulation without a context.");
    }

    if (!note || index == null) {
      throw new Vex.RERR('NoAttachedNote', "Can't draw Articulation without a note and index.");
    }

    const stave = note.getStave();
    const staffSpace = stave.getSpacingBetweenLines();
    const isTab = note.getCategory() === 'tabnotes';

    // Articulations are centered over/under the note head.
    const { x } = note.getModifierStartXY(position, index);
    const shouldSitOutsideStaff = !canSitBetweenLines || isTab;

    let y = {
      [ABOVE]: () => {
        glyph.setOrigin(0.5, 1);
        const y = getTopY(note, textLine) - ((textLine + 1) * staffSpace);
        return shouldSitOutsideStaff ? Math.min(stave.getYForTopText(0), y) : y;
      },
      [BELOW]: () => {
        glyph.setOrigin(0.5, 0);
        const y = getBottomY(note, textLine) + ((textLine + 1) * staffSpace);
        return shouldSitOutsideStaff ? Math.max(stave.getYForBottomText(0), y) : y;
      },
    }[position]();

    if (!isTab) {
      const offsetDirection = position === ABOVE ? -1 : +1;
      const noteLine = isTab ? note.positions[index].str : note.getKeyProps()[index].line;
      const distanceFromNote = (note.getYs()[index] - y) / staffSpace;
      const articLine = distanceFromNote + noteLine;
      const snappedLine = snapLineToStaff(canSitBetweenLines, articLine, position, offsetDirection);

      if (isWithinLines(snappedLine, position)) glyph.setOrigin(0.5, 0.5);

      y += Math.abs(snappedLine - articLine) * staffSpace * offsetDirection;
    }

    L(`Rendering articulation at (x: ${x}, y: ${y})`);

    glyph.render(ctx, x, y);
  }
}
<commit_msg>Add support for notes without a stem<commit_after>// [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
// Author: Larry Kuhns.
//
// ## Description
//
// This file implements articulations and accents as modifiers that can be
// attached to notes. The complete list of articulations is available in
// `tables.js` under `Vex.Flow.articulationCodes`.
//
// See `tests/articulation_tests.js` for usage examples.

import { Vex } from './vex';
import { Flow } from './tables';
import { Modifier } from './modifier';
import { Glyph } from './glyph';
import { Stem } from './stem';

// To enable logging for this class. Set `Vex.Flow.Articulation.DEBUG` to `true`.
function L(...args) { if (Articulation.DEBUG) Vex.L('Vex.Flow.Articulation', args); }

const { ABOVE, BELOW } = Modifier.Position;

const roundToNearestHalf = (mathFn, value) => mathFn(value / 0.5) * 0.5;

// This includes both staff and ledger lines
const isWithinLines = (line, position) => position === ABOVE ? line <= 5 : line >= 1;

const getRoundingFunction = (line, position) => {
  if (isWithinLines(line, position)) {
    if (position === ABOVE) {
      return Math.ceil;
    } else {
      return Math.floor;
    }
  } else {
    return Math.round;
  }
};

const snapLineToStaff = (canSitBetweenLines, line, position, offsetDirection) => {
  // Initially, snap to nearest staff line or space
  const snappedLine = roundToNearestHalf(getRoundingFunction(line, position), line);
  const onStaffLine = snappedLine % 1 === 0;

  const shouldSnapToStaffSpace =
    canSitBetweenLines && isWithinLines(snappedLine, position) && onStaffLine;

  if (shouldSnapToStaffSpace) {
    const HALF_STAFF_SPACE = 0.5;
    return snappedLine + (HALF_STAFF_SPACE * -offsetDirection);
  } else {
    return snappedLine;
  }
};

const getTopY = (note, textLine) => {
  const stave = note.getStave();
  const stemDirection = note.getStemDirection();
  const { topY: stemTipY, baseY: stemBaseY } = note.getStemExtents();

  if (note.getCategory() === 'stavenotes') {
    if (note.hasStem()) {
      if (stemDirection === Stem.UP) {
        return stemTipY;
      } else {
        return stemBaseY;
      }
    } else {
      return Math.min(...note.getYs());
    }
  } else if (note.getCategory() === 'tabnotes') {
    if (note.hasStem()) {
      if (stemDirection === Stem.UP) {
        return stemTipY;
      } else {
        return stave.getYForTopText(textLine);
      }
    } else {
      return stave.getYForTopText(textLine);
    }
  } else {
    throw new Vex.RERR(
      'UnknownCategory', 'Only can get the top and bottom ys of stavenotes and tabnotes'
    );
  }
};

const getBottomY = (note, textLine) => {
  const stave = note.getStave();
  const stemDirection = note.getStemDirection();
  const { topY: stemTipY, baseY: stemBaseY } = note.getStemExtents();

  if (note.getCategory() === 'stavenotes') {
    if (note.hasStem()) {
      if (stemDirection === Stem.UP) {
        return stemBaseY;
      } else {
        return stemTipY;
      }
    } else {
      return Math.max(...note.getYs());
    }
  } else if (note.getCategory() === 'tabnotes') {
    if (note.hasStem()) {
      if (stemDirection === Stem.UP) {
        return stave.getYForBottomText(textLine);
      } else {
        return stemTipY;
      }
    } else {
      return stave.getYForBottomText(textLine);
    }
  } else {
    throw new Vex.RERR(
      'UnknownCategory', 'Only can get the top and bottom ys of stavenotes and tabnotes'
    );
  }
};

export class Articulation extends Modifier {
  static get CATEGORY() { return 'articulations'; }

  static format(articulations, state) {
    if (!articulations || articulations.length === 0) return false;

    let width = 0;
    for (let i = 0; i < articulations.length; ++i) {
      let increment = 1;
      const articulation = articulations[i];
      width = Math.max(articulation.getWidth(), width);

      const type = Flow.articulationCodes(articulation.type);

      if (!type.between_lines) increment += 1.5;

      if (articulation.getPosition() === ABOVE) {
        articulation.setTextLine(state.top_text_line);
        state.top_text_line += increment;
      } else {
        articulation.setTextLine(state.text_line);
        state.text_line += increment;
      }
    }

    state.left_shift += width / 2;
    state.right_shift += width / 2;
    return true;
  }

  // Create a new articulation of type `type`, which is an entry in
  // `Vex.Flow.articulationCodes` in `tables.js`.
  constructor(type) {
    super();

    this.note = null;
    this.index = null;
    this.type = type;
    this.position = BELOW;
    this.render_options = {
      font_scale: 38,
    };

    this.articulation = Flow.articulationCodes(this.type);
    if (!this.articulation) {
      throw new Vex.RERR('ArgumentError', `Articulation not found: ${this.type}`);
    }

    this.glyph = new Glyph(this.articulation.code, this.render_options.font_scale);

    // Default width comes from articulation table.
    this.setWidth(this.glyph.getMetrics().width);
  }

  getCategory() { return Articulation.CATEGORY; }

  // Render articulation in position next to note.
  draw() {
    const {
      note, index, position, glyph,
      articulation: { between_lines: canSitBetweenLines },
      text_line: textLine,
      context: ctx,
    } = this;

    if (!ctx) {
      throw new Vex.RERR('NoContext', "Can't draw Articulation without a context.");
    }

    if (!note || index == null) {
      throw new Vex.RERR('NoAttachedNote', "Can't draw Articulation without a note and index.");
    }

    const stave = note.getStave();
    const staffSpace = stave.getSpacingBetweenLines();
    const isTab = note.getCategory() === 'tabnotes';

    // Articulations are centered over/under the note head.
    const { x } = note.getModifierStartXY(position, index);
    const shouldSitOutsideStaff = !canSitBetweenLines || isTab;

    let y = {
      [ABOVE]: () => {
        glyph.setOrigin(0.5, 1);
        const y = getTopY(note, textLine) - ((textLine + 1) * staffSpace);
        return shouldSitOutsideStaff ? Math.min(stave.getYForTopText(0), y) : y;
      },
      [BELOW]: () => {
        glyph.setOrigin(0.5, 0);
        const y = getBottomY(note, textLine) + ((textLine + 1) * staffSpace);
        return shouldSitOutsideStaff ? Math.max(stave.getYForBottomText(0), y) : y;
      },
    }[position]();

    if (!isTab) {
      const offsetDirection = position === ABOVE ? -1 : +1;
      const noteLine = isTab ? note.positions[index].str : note.getKeyProps()[index].line;
      const distanceFromNote = (note.getYs()[index] - y) / staffSpace;
      const articLine = distanceFromNote + noteLine;
      const snappedLine = snapLineToStaff(canSitBetweenLines, articLine, position, offsetDirection);

      if (isWithinLines(snappedLine, position)) glyph.setOrigin(0.5, 0.5);

      y += Math.abs(snappedLine - articLine) * staffSpace * offsetDirection;
    }

    L(`Rendering articulation at (x: ${x}, y: ${y})`);

    glyph.render(ctx, x, y);
  }
}
<|endoftext|>


<commit_before>// this script is injected into every page.

/**
 * Install the hook on window, which is an event emitter.
 * Note because Chrome content scripts cannot directly modify the window object,
 * we are evaling this function by inserting a script tag. That's why we have
 * to inline the whole event emitter implementation here.
 *
 * @param {Window|global} target
 */

export function installHook (target) {
  let listeners = {}

  if (target.hasOwnProperty('__VUE_DEVTOOLS_GLOBAL_HOOK__')) return

  const hook = {
    Vue: null,

    _buffer: [],

    _replayBuffer (event) {
      let buffer = this._buffer
      this._buffer = []

      for (let i = 0, l = buffer.length; i < l; i++) {
        let allArgs = buffer[i]
        allArgs[0] === event
          ? this.emit.apply(this, allArgs)
          : this._buffer.push(allArgs)
      }
    },

    on (event, fn) {
      const $event = '$' + event
      if (listeners[$event]) {
        listeners[$event].push(fn)
      } else {
        listeners[$event] = [fn]
        this._replayBuffer(event)
      }
    },

    once (event, fn) {
      function on () {
        this.off(event, on)
        fn.apply(this, arguments)
      }
      this.on(event, on)
    },

    off (event, fn) {
      event = '$' + event
      if (!arguments.length) {
        listeners = {}
      } else {
        const cbs = listeners[event]
        if (cbs) {
          if (!fn) {
            listeners[event] = null
          } else {
            for (let i = 0, l = cbs.length; i < l; i++) {
              const cb = cbs[i]
              if (cb === fn || cb.fn === fn) {
                cbs.splice(i, 1)
                break
              }
            }
          }
        }
      }
    },

    emit (event) {
      const $event = '$' + event
      let cbs = listeners[$event]
      if (cbs) {
        const eventArgs = [].slice.call(arguments, 1)
        cbs = cbs.slice()
        for (let i = 0, l = cbs.length; i < l; i++) {
          cbs[i].apply(this, eventArgs)
        }
      } else {
        const allArgs = [].slice.call(arguments)
        this._buffer.push(allArgs)
      }
    }
  }

  hook.once('init', Vue => {
    hook.Vue = Vue

    Vue.prototype.$inspect = function () {
      const fn = target.__VUE_DEVTOOLS_INSPECT__
      fn && fn(this)
    }
  })

  hook.once('vuex:init', store => {
    hook.store = store
    hook.initialStore = {
      state: clone(store.state),
      getters: store.getters
    }
    // Dynamic modules
    if (store.registerModule) {
      hook.storeModules = []
      const origRegister = store.registerModule.bind(store)
      store.registerModule = (path, module, options) => {
        if (typeof path === 'string') path = [path]
        hook.storeModules.push({ path, module, options })
        origRegister(path, module, options)
        if (process.env.NODE_ENV !== 'production') console.log('early register module', path)
      }
      const origUnregister = store.unregisterModule.bind(store)
      store.unregisterModule = (path) => {
        if (typeof path === 'string') path = [path]
        const key = path.join('/')
        const index = hook.storeModules.findIndex(m => m.path.join('/') === key)
        if (index !== -1) hook.storeModules.splice(index, 1)
        origUnregister(path)
        if (process.env.NODE_ENV !== 'production') console.log('early unregister module', path)
      }
      hook.flushStoreModules = () => {
        store.registerModule = origRegister
        store.unregisterModule = origUnregister
        return hook.storeModules
      }
    } else {
      hook.flushStoreModules = () => []
    }
  })

  Object.defineProperty(target, '__VUE_DEVTOOLS_GLOBAL_HOOK__', {
    get () {
      return hook
    }
  })

  // Clone deep utility for cloning initial state of the store
  // REFERENCE: https://github.com/pvorb/clone

  let NativeMap
  try {
    NativeMap = Map
  } catch (_) {
    // maybe a reference error because no `Map`. Give it a dummy value that no
    // value will ever be an instanceof.
    NativeMap = function () {}
  }

  let NativeSet
  try {
    NativeSet = Set
  } catch (_) {
    NativeSet = function () {}
  }

  let NativePromise
  try {
    NativePromise = Promise
  } catch (_) {
    NativePromise = function () {}
  }

  function clone (parent, circular, depth, prototype, includeNonEnumerable) {
    if (typeof circular === 'object') {
      depth = circular.depth
      prototype = circular.prototype
      includeNonEnumerable = circular.includeNonEnumerable
      circular = circular.circular
    }
    // maintain two arrays for circular references, where corresponding parents
    // and children have the same index
    var allParents = []
    var allChildren = []

    var useBuffer = typeof Buffer !== 'undefined' && typeof Buffer.isBuffer === 'function'

    if (typeof circular === 'undefined') { circular = true }

    if (typeof depth === 'undefined') { depth = Infinity }

    // recurse this function so we don't reset allParents and allChildren
    function _clone (parent, depth) {
      // cloning null always returns null
      if (parent === null) { return null }

      if (depth === 0) { return parent }

      var child
      var proto
      if (typeof parent !== 'object') {
        return parent
      }

      if (_instanceof(parent, NativeMap)) {
        child = new NativeMap()
      } else if (_instanceof(parent, NativeSet)) {
        child = new NativeSet()
      } else if (_instanceof(parent, NativePromise)) {
        child = new NativePromise(function (resolve, reject) {
          parent.then(function (value) {
            resolve(_clone(value, depth - 1))
          }, function (err) {
            reject(_clone(err, depth - 1))
          })
        })
      } else if (clone.__isArray(parent)) {
        child = []
      } else if (clone.__isRegExp(parent)) {
        child = new RegExp(parent.source, __getRegExpFlags(parent))
        if (parent.lastIndex) child.lastIndex = parent.lastIndex
      } else if (clone.__isDate(parent)) {
        child = new Date(parent.getTime())
      } else if (useBuffer && Buffer.isBuffer(parent)) {
        if (Buffer.from) {
          // Node.js >= 5.10.0
          child = Buffer.from(parent)
        } else {
          // Older Node.js versions
          // eslint-disable-next-line node/no-deprecated-api
          child = new Buffer(parent.length)
          parent.copy(child)
        }
        return child
      } else if (_instanceof(parent, Error)) {
        child = Object.create(parent)
      } else {
        if (typeof prototype === 'undefined') {
          proto = Object.getPrototypeOf(parent)
          child = Object.create(proto)
        } else {
          child = Object.create(prototype)
          proto = prototype
        }
      }

      if (circular) {
        var index = allParents.indexOf(parent)

        if (index !== -1) {
          return allChildren[index]
        }
        allParents.push(parent)
        allChildren.push(child)
      }

      if (_instanceof(parent, NativeMap)) {
        parent.forEach(function (value, key) {
          var keyChild = _clone(key, depth - 1)
          var valueChild = _clone(value, depth - 1)
          child.set(keyChild, valueChild)
        })
      }
      if (_instanceof(parent, NativeSet)) {
        parent.forEach(function (value) {
          var entryChild = _clone(value, depth - 1)
          child.add(entryChild)
        })
      }

      for (var i in parent) {
        var attrs = Object.getOwnPropertyDescriptor(parent, i)
        if (attrs) {
          if (attrs.hasOwnProperty('get') && attrs.get.name === 'computedGetter') {
            Object.defineProperty(child, i, attrs)
            continue
          }

          child[i] = _clone(parent[i], depth - 1)
        }
      }

      if (Object.getOwnPropertySymbols) {
        var symbols = Object.getOwnPropertySymbols(parent)
        for (let i = 0; i < symbols.length; i++) {
          // Don't need to worry about cloning a symbol because it is a primitive,
          // like a number or string.
          var symbol = symbols[i]
          var descriptor = Object.getOwnPropertyDescriptor(parent, symbol)
          if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
            continue
          }
          child[symbol] = _clone(parent[symbol], depth - 1)
          Object.defineProperty(child, symbol, descriptor)
        }
      }

      if (includeNonEnumerable) {
        var allPropertyNames = Object.getOwnPropertyNames(parent)
        for (let i = 0; i < allPropertyNames.length; i++) {
          const propertyName = allPropertyNames[i]
          let descriptor = Object.getOwnPropertyDescriptor(parent, propertyName)
          if (descriptor && descriptor.enumerable) {
            continue
          }
          child[propertyName] = _clone(parent[propertyName], depth - 1)
          Object.defineProperty(child, propertyName, descriptor)
        }
      }

      return child
    }

    return _clone(parent, depth)
  }

  // private utility functions

  function __objToStr (o) {
    return Object.prototype.toString.call(o)
  }
  clone.__objToStr = __objToStr

  function __isDate (o) {
    return typeof o === 'object' && __objToStr(o) === '[object Date]'
  }
  clone.__isDate = __isDate

  function __isArray (o) {
    return typeof o === 'object' && __objToStr(o) === '[object Array]'
  }
  clone.__isArray = __isArray

  function __isRegExp (o) {
    return typeof o === 'object' && __objToStr(o) === '[object RegExp]'
  }
  clone.__isRegExp = __isRegExp

  function __getRegExpFlags (re) {
    var flags = ''
    if (re.global) flags += 'g'
    if (re.ignoreCase) flags += 'i'
    if (re.multiline) flags += 'm'
    return flags
  }
  clone.__getRegExpFlags = __getRegExpFlags

  function _instanceof (obj, type) {
    return type != null && obj instanceof type
  }
}
<commit_msg>fix(vuex): early replace state (i.e. nuxt/SSR)<commit_after>// this script is injected into every page.

/**
 * Install the hook on window, which is an event emitter.
 * Note because Chrome content scripts cannot directly modify the window object,
 * we are evaling this function by inserting a script tag. That's why we have
 * to inline the whole event emitter implementation here.
 *
 * @param {Window|global} target
 */

export function installHook (target) {
  let listeners = {}

  if (target.hasOwnProperty('__VUE_DEVTOOLS_GLOBAL_HOOK__')) return

  const hook = {
    Vue: null,

    _buffer: [],

    _replayBuffer (event) {
      let buffer = this._buffer
      this._buffer = []

      for (let i = 0, l = buffer.length; i < l; i++) {
        let allArgs = buffer[i]
        allArgs[0] === event
          ? this.emit.apply(this, allArgs)
          : this._buffer.push(allArgs)
      }
    },

    on (event, fn) {
      const $event = '$' + event
      if (listeners[$event]) {
        listeners[$event].push(fn)
      } else {
        listeners[$event] = [fn]
        this._replayBuffer(event)
      }
    },

    once (event, fn) {
      function on () {
        this.off(event, on)
        fn.apply(this, arguments)
      }
      this.on(event, on)
    },

    off (event, fn) {
      event = '$' + event
      if (!arguments.length) {
        listeners = {}
      } else {
        const cbs = listeners[event]
        if (cbs) {
          if (!fn) {
            listeners[event] = null
          } else {
            for (let i = 0, l = cbs.length; i < l; i++) {
              const cb = cbs[i]
              if (cb === fn || cb.fn === fn) {
                cbs.splice(i, 1)
                break
              }
            }
          }
        }
      }
    },

    emit (event) {
      const $event = '$' + event
      let cbs = listeners[$event]
      if (cbs) {
        const eventArgs = [].slice.call(arguments, 1)
        cbs = cbs.slice()
        for (let i = 0, l = cbs.length; i < l; i++) {
          cbs[i].apply(this, eventArgs)
        }
      } else {
        const allArgs = [].slice.call(arguments)
        this._buffer.push(allArgs)
      }
    }
  }

  hook.once('init', Vue => {
    hook.Vue = Vue

    Vue.prototype.$inspect = function () {
      const fn = target.__VUE_DEVTOOLS_INSPECT__
      fn && fn(this)
    }
  })

  hook.once('vuex:init', store => {
    hook.store = store
    hook.initialStore = {
      state: clone(store.state),
      getters: store.getters
    }
    const origReplaceState = store.replaceState.bind(store)
    store.replaceState = state => {
      hook.initialStore.state = clone(state)
      origReplaceState(state)
    }
    // Dynamic modules
    if (store.registerModule) {
      hook.storeModules = []
      const origRegister = store.registerModule.bind(store)
      store.registerModule = (path, module, options) => {
        if (typeof path === 'string') path = [path]
        hook.storeModules.push({ path, module, options })
        origRegister(path, module, options)
        if (process.env.NODE_ENV !== 'production') console.log('early register module', path)
      }
      const origUnregister = store.unregisterModule.bind(store)
      store.unregisterModule = (path) => {
        if (typeof path === 'string') path = [path]
        const key = path.join('/')
        const index = hook.storeModules.findIndex(m => m.path.join('/') === key)
        if (index !== -1) hook.storeModules.splice(index, 1)
        origUnregister(path)
        if (process.env.NODE_ENV !== 'production') console.log('early unregister module', path)
      }
      hook.flushStoreModules = () => {
        store.registerModule = origRegister
        store.unregisterModule = origUnregister
        store.replaceState = origReplaceState
        return hook.storeModules
      }
    } else {
      hook.flushStoreModules = () => {
        store.replaceState = origReplaceState
        return []
      }
    }
  })

  Object.defineProperty(target, '__VUE_DEVTOOLS_GLOBAL_HOOK__', {
    get () {
      return hook
    }
  })

  // Clone deep utility for cloning initial state of the store
  // REFERENCE: https://github.com/pvorb/clone

  let NativeMap
  try {
    NativeMap = Map
  } catch (_) {
    // maybe a reference error because no `Map`. Give it a dummy value that no
    // value will ever be an instanceof.
    NativeMap = function () {}
  }

  let NativeSet
  try {
    NativeSet = Set
  } catch (_) {
    NativeSet = function () {}
  }

  let NativePromise
  try {
    NativePromise = Promise
  } catch (_) {
    NativePromise = function () {}
  }

  function clone (parent, circular, depth, prototype, includeNonEnumerable) {
    if (typeof circular === 'object') {
      depth = circular.depth
      prototype = circular.prototype
      includeNonEnumerable = circular.includeNonEnumerable
      circular = circular.circular
    }
    // maintain two arrays for circular references, where corresponding parents
    // and children have the same index
    var allParents = []
    var allChildren = []

    var useBuffer = typeof Buffer !== 'undefined' && typeof Buffer.isBuffer === 'function'

    if (typeof circular === 'undefined') { circular = true }

    if (typeof depth === 'undefined') { depth = Infinity }

    // recurse this function so we don't reset allParents and allChildren
    function _clone (parent, depth) {
      // cloning null always returns null
      if (parent === null) { return null }

      if (depth === 0) { return parent }

      var child
      var proto
      if (typeof parent !== 'object') {
        return parent
      }

      if (_instanceof(parent, NativeMap)) {
        child = new NativeMap()
      } else if (_instanceof(parent, NativeSet)) {
        child = new NativeSet()
      } else if (_instanceof(parent, NativePromise)) {
        child = new NativePromise(function (resolve, reject) {
          parent.then(function (value) {
            resolve(_clone(value, depth - 1))
          }, function (err) {
            reject(_clone(err, depth - 1))
          })
        })
      } else if (clone.__isArray(parent)) {
        child = []
      } else if (clone.__isRegExp(parent)) {
        child = new RegExp(parent.source, __getRegExpFlags(parent))
        if (parent.lastIndex) child.lastIndex = parent.lastIndex
      } else if (clone.__isDate(parent)) {
        child = new Date(parent.getTime())
      } else if (useBuffer && Buffer.isBuffer(parent)) {
        if (Buffer.from) {
          // Node.js >= 5.10.0
          child = Buffer.from(parent)
        } else {
          // Older Node.js versions
          // eslint-disable-next-line node/no-deprecated-api
          child = new Buffer(parent.length)
          parent.copy(child)
        }
        return child
      } else if (_instanceof(parent, Error)) {
        child = Object.create(parent)
      } else {
        if (typeof prototype === 'undefined') {
          proto = Object.getPrototypeOf(parent)
          child = Object.create(proto)
        } else {
          child = Object.create(prototype)
          proto = prototype
        }
      }

      if (circular) {
        var index = allParents.indexOf(parent)

        if (index !== -1) {
          return allChildren[index]
        }
        allParents.push(parent)
        allChildren.push(child)
      }

      if (_instanceof(parent, NativeMap)) {
        parent.forEach(function (value, key) {
          var keyChild = _clone(key, depth - 1)
          var valueChild = _clone(value, depth - 1)
          child.set(keyChild, valueChild)
        })
      }
      if (_instanceof(parent, NativeSet)) {
        parent.forEach(function (value) {
          var entryChild = _clone(value, depth - 1)
          child.add(entryChild)
        })
      }

      for (var i in parent) {
        var attrs = Object.getOwnPropertyDescriptor(parent, i)
        if (attrs) {
          if (attrs.hasOwnProperty('get') && attrs.get.name === 'computedGetter') {
            Object.defineProperty(child, i, attrs)
            continue
          }

          child[i] = _clone(parent[i], depth - 1)
        }
      }

      if (Object.getOwnPropertySymbols) {
        var symbols = Object.getOwnPropertySymbols(parent)
        for (let i = 0; i < symbols.length; i++) {
          // Don't need to worry about cloning a symbol because it is a primitive,
          // like a number or string.
          var symbol = symbols[i]
          var descriptor = Object.getOwnPropertyDescriptor(parent, symbol)
          if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
            continue
          }
          child[symbol] = _clone(parent[symbol], depth - 1)
          Object.defineProperty(child, symbol, descriptor)
        }
      }

      if (includeNonEnumerable) {
        var allPropertyNames = Object.getOwnPropertyNames(parent)
        for (let i = 0; i < allPropertyNames.length; i++) {
          const propertyName = allPropertyNames[i]
          let descriptor = Object.getOwnPropertyDescriptor(parent, propertyName)
          if (descriptor && descriptor.enumerable) {
            continue
          }
          child[propertyName] = _clone(parent[propertyName], depth - 1)
          Object.defineProperty(child, propertyName, descriptor)
        }
      }

      return child
    }

    return _clone(parent, depth)
  }

  // private utility functions

  function __objToStr (o) {
    return Object.prototype.toString.call(o)
  }
  clone.__objToStr = __objToStr

  function __isDate (o) {
    return typeof o === 'object' && __objToStr(o) === '[object Date]'
  }
  clone.__isDate = __isDate

  function __isArray (o) {
    return typeof o === 'object' && __objToStr(o) === '[object Array]'
  }
  clone.__isArray = __isArray

  function __isRegExp (o) {
    return typeof o === 'object' && __objToStr(o) === '[object RegExp]'
  }
  clone.__isRegExp = __isRegExp

  function __getRegExpFlags (re) {
    var flags = ''
    if (re.global) flags += 'g'
    if (re.ignoreCase) flags += 'i'
    if (re.multiline) flags += 'm'
    return flags
  }
  clone.__getRegExpFlags = __getRegExpFlags

  function _instanceof (obj, type) {
    return type != null && obj instanceof type
  }
}
<|endoftext|>


<commit_before>$(document).ready(function() {
    var $graphic = $('#graphic');
    var graphic_data_url = 'data.csv';
    var graphic_data;
    var graphic_aspect_width = 16;
    var graphic_aspect_height = 9;
    var mobile_threshold = 500;

    function drawGraphic(width) {

        var margin = {top: 10, right: 15, bottom: 25, left: 35};
        var width = width - margin.left - margin.right;
        var height = Math.ceil((width * graphic_aspect_height) / graphic_aspect_width) - margin.top - margin.bottom;
        var num_ticks = 13;
        if (width < mobile_threshold) {
            num_ticks = 5;
        }

        // clear out existing graphics
        $graphic.empty();

        var x = d3.time.scale()
            .range([0, width]);

        var y = d3.scale.linear()
            .range([height, 0]);

        var formatAsPercentage = d3.formatPrefix('%',0);

        var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom")
//            .ticks(num_ticks)
            .tickFormat(function(d,i) {
                if (width <= mobile_threshold) {
                    var fmt = d3.time.format('%y');
                    return '\u2019' + fmt(d);
                } else {
                    var fmt = d3.time.format('%Y');
                    return fmt(d);
                }
            });

        var x_axis_grid = function() { return xAxis; }

        var yAxis = d3.svg.axis()
            .scale(y)
            .orient('left')
            .ticks(num_ticks);

        var y_axis_grid = function() { return yAxis; }

        var line = d3.svg.line()
//            .interpolate('monotone')
            .x(function(d) { return x(d.date); })
            .y(function(d) { return y(d.amt); });

        // parse data into columns
        var lines = {};
        for (var column in graphic_data[0]) {
            if (column == 'date') continue;
            lines[column] = graphic_data.map(function(d) {
                return {
                    'date': d.date,
                    'amt': d[column]
                };
            });
        }

        var svg = d3.select('#graphic').append('svg')
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        x.domain(d3.extent(graphic_data, function(d) { return d.date; }));

        y.domain([
            d3.min(d3.entries(lines), function(c) {
                return d3.min(c.value, function(v) {
                    var n = v.amt;
                    return Math.floor(n) - 1;
//                    return Math.floor(n/10) * 10; // round to next 10
                });
            }),
            d3.max(d3.entries(lines), function(c) {
                return d3.max(c.value, function(v) {
                    var n = v.amt;
                    return Math.ceil(n) + 1;
//                    return Math.ceil(n/10) * 10; // round to next 10
                });
            })
        ]);

        svg.append('g')
            .attr('class', 'x axis')
            .attr('transform', 'translate(0,' + height + ')')
            .call(xAxis);

        svg.append('g')
            .attr('class', 'y axis')
            .call(yAxis);

        svg.append('g')
            .attr('class', 'x grid')
            .attr('transform', 'translate(0,' + height + ')')
            .call(x_axis_grid()
                .tickSize(-height, 0, 0)
                .tickFormat('')
            );

        svg.append('g')
            .attr('class', 'y grid')
            .call(y_axis_grid()
                .tickSize(-width, 0, 0)
                .tickFormat('')
            );

        svg.append('g').selectAll('path')
            .data(d3.entries(lines))
            .enter()
            .append('path')
                .attr('class', function(d, i) {
                    return 'line line-' + i;
                })
                .attr('d', function(d) {
                    console.log(d.value);
                    return line(d.value);
                });

        /*
        svg.append('g').selectAll('text')
            .data(d3.entries(lines))
            .enter()
                .append('text')
                    .attr('x', 5)
                    .attr('y', 5)
                    .attr('dx', -6)
                    .attr('dy', 28)
                    .attr('text-anchor', 'end')
                    .attr('class', function(d) { return 'value value-' + d.key.replace(' ', '-').toLowerCase() })
                    .text(function(d) { console.log(d); return d.value });
        */

        sendHeightToParent();
    }

    function setup() {
        if (Modernizr.svg) {
            d3.csv(graphic_data_url, function(error, data) {
                graphic_data = data;

                graphic_data.forEach(function(d) {
                    d.date = d3.time.format('%Y-%m').parse(d.date);
                    d.jobs = d.jobs / 1000;
                });

                setupResponsiveChild({
                    renderCallback: drawGraphic
                });
            });
        }
    }

    setup();
});
<commit_msg>remove extra console log messages. trim margins<commit_after>$(document).ready(function() {
    var $graphic = $('#graphic');
    var graphic_data_url = 'data.csv';
    var graphic_data;
    var graphic_aspect_width = 16;
    var graphic_aspect_height = 9;
    var mobile_threshold = 500;

    function drawGraphic(width) {

        var margin = {top: 10, right: 15, bottom: 25, left: 35};
        var width = width - margin.left - margin.right;
        var height = Math.ceil((width * graphic_aspect_height) / graphic_aspect_width) - margin.top - margin.bottom;
        var num_ticks = 13;
        if (width < mobile_threshold) {
            num_ticks = 5;
        }

        // clear out existing graphics
        $graphic.empty();

        var x = d3.time.scale()
            .range([0, width]);

        var y = d3.scale.linear()
            .range([height, 0]);

        var formatAsPercentage = d3.formatPrefix('%',0);

        var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom")
//            .ticks(num_ticks)
            .tickFormat(function(d,i) {
                if (width <= mobile_threshold) {
                    var fmt = d3.time.format('%y');
                    return '\u2019' + fmt(d);
                } else {
                    var fmt = d3.time.format('%Y');
                    return fmt(d);
                }
            });

        var x_axis_grid = function() { return xAxis; }

        var yAxis = d3.svg.axis()
            .scale(y)
            .orient('left')
            .ticks(num_ticks);

        var y_axis_grid = function() { return yAxis; }

        var line = d3.svg.line()
//            .interpolate('monotone')
            .x(function(d) { return x(d.date); })
            .y(function(d) { return y(d.amt); });

        // parse data into columns
        var lines = {};
        for (var column in graphic_data[0]) {
            if (column == 'date') continue;
            lines[column] = graphic_data.map(function(d) {
                return {
                    'date': d.date,
                    'amt': d[column]
                };
            });
        }

        var svg = d3.select('#graphic').append('svg')
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        x.domain(d3.extent(graphic_data, function(d) { return d.date; }));

        y.domain([
            d3.min(d3.entries(lines), function(c) {
                return d3.min(c.value, function(v) {
                    var n = v.amt;
                    return Math.floor(n);
//                    return Math.floor(n/10) * 10; // round to next 10
                });
            }),
            d3.max(d3.entries(lines), function(c) {
                return d3.max(c.value, function(v) {
                    var n = v.amt;
                    return Math.ceil(n);
//                    return Math.ceil(n/10) * 10; // round to next 10
                });
            })
        ]);

        svg.append('g')
            .attr('class', 'x axis')
            .attr('transform', 'translate(0,' + height + ')')
            .call(xAxis);

        svg.append('g')
            .attr('class', 'y axis')
            .call(yAxis);

        svg.append('g')
            .attr('class', 'x grid')
            .attr('transform', 'translate(0,' + height + ')')
            .call(x_axis_grid()
                .tickSize(-height, 0, 0)
                .tickFormat('')
            );

        svg.append('g')
            .attr('class', 'y grid')
            .call(y_axis_grid()
                .tickSize(-width, 0, 0)
                .tickFormat('')
            );

        svg.append('g').selectAll('path')
            .data(d3.entries(lines))
            .enter()
            .append('path')
                .attr('class', function(d, i) {
                    return 'line line-' + i;
                })
                .attr('d', function(d) {
                    return line(d.value);
                });

        sendHeightToParent();
    }

    function setup() {
        if (Modernizr.svg) {
            d3.csv(graphic_data_url, function(error, data) {
                graphic_data = data;

                graphic_data.forEach(function(d) {
                    d.date = d3.time.format('%Y-%m').parse(d.date);
                    d.jobs = d.jobs / 1000;
                });

                setupResponsiveChild({
                    renderCallback: drawGraphic
                });
            });
        }
    }

    setup();
});
<|endoftext|>


<commit_before>
  basis.require('basis.dom.computedStyle');

 /**
  * @namespace basis.layout
  */

  var namespace = this.path;

  //
  // import names
  //

  var document = global.document;
  var documentElement = document.documentElement;
  var computedStyle = basis.dom.computedStyle.get;

  //
  // Main part
  //

  function getOffsetParent(node){
    var offsetParent = node.offsetParent || documentElement;

    while (offsetParent && offsetParent !== documentElement && computedStyle(offsetParent, 'position') == 'static')
      offsetParent = offsetParent.offsetParent;

    return offsetParent || documentElement;
  }

  function getPageOffset(){
    var top = 0;
    var left = 0;

    if (document.compatMode == 'CSS1Compat')
    {
      top = global.pageYOffset || documentElement.scrollTop;
      left = global.pageXOffset || documentElement.scrollLeft;
    }
    else
    {
      // IE6 and lower
      var body = document.body;
      if (element !== body)
      {
        top = body.scrollTop - body.clientTop;
        left = body.scrollLeft - body.clientLeft;
      }
    }

    return {
      x: left,
      y: top
    };
  }

  function getTopLeftPoint(element){
    var left = 0;
    var top = 0;

    if (element && element.getBoundingClientRect)
    {
      var box = element.getBoundingClientRect();
      var offset = getPageOffset();

      top = box.top + offset.y;
      left = box.left + offset.x;
    }

    return {
      top: top,
      left: left
    };
  }

  function getBoundingRect(element, relElement){
    var top = 0;
    var left = 0;
    var right = 0;
    var bottom = 0;

    if (element && element.getBoundingClientRect)
    {
      var rect = element.getBoundingClientRect();
      var offset;

      // coords relative of relElement
      if (relElement && relElement.getBoundingClientRect)
      {
        var relRect = relElement.getBoundingClientRect();
        offset = {
          x: -relRect.left,
          y: -relRect.top
        };
      }
      else
      {
        offset = getPageOffset();
      }

      top = rect.top + offset.y;
      left = rect.left + offset.x;
      right = rect.right + offset.x;
      bottom = rect.bottom + offset.y;
    }

    return {
      top: top,
      left: left,
      right: right,
      bottom: bottom,
      width: right - left,
      height: bottom - top
    };
  }

  function getViewportRect(element){
    var point = getTopLeftPoint(element);
    var top = point.top;
    var left = point.left;
    var width = element.clientWidth;
    var height = element.clientHeight;

    top += element.clientTop + (global.pageYOffset || documentElement.scrollTop);
    left += element.clientLeft + (global.pageXOffset || documentElement.scrollLeft);

    return {
      top: top,
      left: left,
      bottom: top + height,
      right: left + width,
      width: width,
      height: height
    };
  }

  //
  // export names
  //

  module.exports = {
    getOffsetParent: getOffsetParent,
    getTopLeftPoint: getTopLeftPoint,
    getBoundingRect: getBoundingRect,
    getViewportRect: getViewportRect
  };
<commit_msg>layout: fix getViewportRect adds page scroll offset twice<commit_after>
  basis.require('basis.dom.computedStyle');

 /**
  * @namespace basis.layout
  */

  var namespace = this.path;

  //
  // import names
  //

  var document = global.document;
  var documentElement = document.documentElement;
  var computedStyle = basis.dom.computedStyle.get;

  //
  // Main part
  //

  function getOffsetParent(node){
    var offsetParent = node.offsetParent || documentElement;

    while (offsetParent && offsetParent !== documentElement && computedStyle(offsetParent, 'position') == 'static')
      offsetParent = offsetParent.offsetParent;

    return offsetParent || documentElement;
  }

  function getPageOffset(){
    var top = 0;
    var left = 0;

    if (document.compatMode == 'CSS1Compat')
    {
      top = global.pageYOffset || documentElement.scrollTop;
      left = global.pageXOffset || documentElement.scrollLeft;
    }
    else
    {
      // IE6 and lower
      var body = document.body;
      if (element !== body)
      {
        top = body.scrollTop - body.clientTop;
        left = body.scrollLeft - body.clientLeft;
      }
    }

    return {
      x: left,
      y: top
    };
  }

  function getTopLeftPoint(element){
    var left = 0;
    var top = 0;

    if (element && element.getBoundingClientRect)
    {
      var box = element.getBoundingClientRect();
      var offset = getPageOffset();

      top = box.top + offset.y;
      left = box.left + offset.x;
    }

    return {
      top: top,
      left: left
    };
  }

  function getBoundingRect(element, relElement){
    var top = 0;
    var left = 0;
    var right = 0;
    var bottom = 0;

    if (element && element.getBoundingClientRect)
    {
      var rect = element.getBoundingClientRect();
      var offset;

      // coords relative of relElement
      if (relElement && relElement.getBoundingClientRect)
      {
        var relRect = relElement.getBoundingClientRect();
        offset = {
          x: -relRect.left,
          y: -relRect.top
        };
      }
      else
      {
        offset = getPageOffset();
      }

      top = rect.top + offset.y;
      left = rect.left + offset.x;
      right = rect.right + offset.x;
      bottom = rect.bottom + offset.y;
    }

    return {
      top: top,
      left: left,
      right: right,
      bottom: bottom,
      width: right - left,
      height: bottom - top
    };
  }

  function getViewportRect(element){
    var point = getTopLeftPoint(element);
    var top = point.top + element.clientTop;
    var left = point.left + element.clientLeft;
    var width = element.clientWidth;
    var height = element.clientHeight;

    return {
      top: top,
      left: left,
      bottom: top + height,
      right: left + width,
      width: width,
      height: height
    };
  }

  //
  // export names
  //

  module.exports = {
    getOffsetParent: getOffsetParent,
    getTopLeftPoint: getTopLeftPoint,
    getBoundingRect: getBoundingRect,
    getViewportRect: getViewportRect
  };
<|endoftext|>


<commit_before>// @flow

/* global window, requestAnimationFrame, Event */

/* eslint consistent-this: ["error", "view"], react/jsx-no-bind: 0 */

import type {Node} from 'react';
import React, {Component} from 'react';
import Swiper from 'swiper';
import classnames from 'classnames';
import style from './style.scss';

type StateType = void;
type PropsType = {|
    className?: string,
    children: Node | Array<Node>
|};
type NodeType = {|
    wrapper: HTMLElement | null
|};

type AttrType = {|
    swiper: Swiper | null
|};

export default class Scroll extends Component<StateType, PropsType> {
    state: StateType;
    props: PropsType;
    node: NodeType;
    attr: AttrType;

    constructor() {
        super();

        const view = this;

        view.node = {
            wrapper: null
        };

        view.attr = {
            swiper: null
        };
    }

    async initSwiper(): Promise<void> {
        const view = this;

        const {wrapper} = view.node;

        if (wrapper === null) {
            return Promise.resolve();
        }

        view.attr.swiper = new Swiper(wrapper, {
            direction: 'vertical',
            slidesPerView: 'auto',
            freeMode: true,
            watchOverflow: true, // disable this cause swiper has scroll bar and bug after resize
            scrollbar: {
                // eslint-disable-next-line id-length
                el: '.swiper-scrollbar'
            },
            mousewheel: true
        });

        return view.recount();
    }

    componentDidMount() {
        const view = this;

        view.initSwiper()
            .then((): void => console.log('swiper initialized'))
            .catch((error: Error) => {
                console.error('error with view.initSwiper()');
                console.error(error);
            });
    }

    componentDidUpdate() {
        const view = this;

        view.recount()
            .then((): void => console.log('swiper recounted'))
            .catch((error: Error) => {
                console.error('error with swiper recounted');
                console.error(error);
            });
    }

    async recount(): Promise<void> {
        return new Promise((resolve: () => void) => {
            requestAnimationFrame(() => {
                window.dispatchEvent(new Event('resize'));
                requestAnimationFrame(resolve);
            });
        });
    }

    renderSwiper(): Node {
        const view = this;
        const {props} = view;

        return (

 {
                    view.node.wrapper = wrapper;
                }}
            >

{props.children}

        );
    }

    render(): Node {
        const view = this;
        const {props} = view;

        return (

{view.renderSwiper()}

        );
    }
}
<commit_msg>update<commit_after>// @flow

/* global window, requestAnimationFrame, Event */

/* eslint consistent-this: ["error", "view"] */

import type {Node} from 'react';
import React, {Component} from 'react';
import Swiper from 'swiper';
import classnames from 'classnames';
import style from './style.scss';

type StateType = void;
type PropsType = {|
    className?: string,
    children: Node | Array<Node>
|};
type NodeType = {|
    wrapper: HTMLElement | null
|};

type AttrType = {|
    swiper: Swiper | null
|};

export default class Scroll extends Component<StateType, PropsType> {
    state: StateType;
    props: PropsType;
    node: NodeType;
    attr: AttrType;

    constructor() {
        super();

        const view = this;

        view.node = {
            wrapper: null
        };

        view.attr = {
            swiper: null
        };
    }

    async initSwiper(): Promise<void> {
        const view = this;

        const {wrapper} = view.node;

        if (wrapper === null) {
            return Promise.resolve();
        }

        view.attr.swiper = new Swiper(wrapper, {
            direction: 'vertical',
            slidesPerView: 'auto',
            freeMode: true,
            watchOverflow: true, // disable this cause swiper has scroll bar and bug after resize
            scrollbar: {
                // eslint-disable-next-line id-length
                el: '.swiper-scrollbar'
            },
            mousewheel: true
        });

        return view.recount();
    }

    componentDidMount() {
        const view = this;

        view.initSwiper()
            .then((): void => console.log('swiper initialized'))
            .catch((error: Error) => {
                console.error('error with view.initSwiper()');
                console.error(error);
            });
    }

    componentDidUpdate() {
        const view = this;

        view.recount()
            .then((): void => console.log('swiper recounted'))
            .catch((error: Error) => {
                console.error('error with swiper recounted');
                console.error(error);
            });
    }

    async recount(): Promise<void> {
        return new Promise((resolve: () => void) => {
            requestAnimationFrame(() => {
                window.dispatchEvent(new Event('resize'));
                requestAnimationFrame(resolve);
            });
        });
    }

    defineRefWrapper = (wrapper: HTMLElement | null) => {
        const view = this;
        const {node} = view;

        node.wrapper = wrapper;
    };

    renderSwiper(): Node {
        const view = this;
        const {props} = view;

        return (

{props.children}

        );
    }

    render(): Node {
        const view = this;
        const {props} = view;

        return (

{view.renderSwiper()}

        );
    }
}
<|endoftext|>