<commit_before>(function() {
  var posts  = document.getElementsByClassName('userContent'),
      terms = [],
      container,
      filteredArray = [],
      controller,
      fwClear,
      washStyle = document.createElement('style');

//initialize our style block for later
washStyle.type = 'text/css';
washStyle.setAttribute('id','washStyle');
document.head.appendChild(washStyle);
washStyle = document.getElementById('washStyle');

  function findAncestor (el, cls) {
      while ((el = el.parentElement) && !el.classList.contains(cls));
      return el;
  }
  function clearFiltered(postList) {
    for (var n=0,k=postList.length;n<k;++n) {
      postList[n].style.display="block";
    }
  }
  function blockIt(terms) {
    clearFiltered(filteredArray);
    for (var i=0, x=posts.length; i<x;++i) {
      this.post = posts[i];
      for (var j = 0, y = terms.length; j < y; ++j) {
      	if (this.post.textContent.search(terms[j]) > -1) {
      	  console.log(terms[j]);
      	  container = (findAncestor(this.post, 'timelineUnitContainer') || findAncestor(this.post, 'userContentWrapper')).parentElement;
      	  this.cursor = container.getAttribute('data-cursor');
      	  console.log(this.cursor);
      	  washStyle.innerHTML += 'div[data-cursor="'+this.cursor+'"] { opacity: .15; height: 5em; }';
          filteredArray.push(container);
      	}
      }
    }
  }
  var controller = "
<input type='text' id='blockItTerms'/>X
";
  document.body.innerHTML+=controller;
  controller = document.getElementById('blockItBox');
  controller.style.position = "fixed";
  controller.style.bottom = "0",
  controller.style.left = "0";
  controller.style.lineHeight = "42px";
  controller.style.minWidth = "0";
  fwClear = document.getElementById('fw-clear');
  fwClear.style.padding = "0 1em 0 2em";
  fwClear.style.fontSize = "16px";
  fwClear.style.color = "#fff";

  document.getElementById('blockItTerms').addEventListener('change', function() {
    terms = document.getElementById('blockItTerms').value;
    terms=terms.split(',');
    blockIt(terms);
  });
  document.getElementById('fw-clear').addEventListener('click', function() {
    clearFiltered(filteredArray);
  });
  window.addEventListener('scroll', function() {
    blockIt(terms);
  });
})()
<commit_msg>removed console.log, comments<commit_after>(function() {
  var posts  = document.getElementsByClassName('userContent'),
      terms = [],
      container,
      filteredArray = [],
      controller,
      fwClear,
      washStyle = document.createElement('style');

washStyle.type = 'text/css';
washStyle.setAttribute('id','washStyle');
document.head.appendChild(washStyle);
washStyle = document.getElementById('washStyle');

  function findAncestor (el, cls) {
      while ((el = el.parentElement) && !el.classList.contains(cls));
      return el;
  }
  function clearFiltered(postList) {
    for (var n=0,k=postList.length;n<k;++n) {
      postList[n].style.display="block";
    }
  }
  function blockIt(terms) {
    clearFiltered(filteredArray);
    for (var i=0, x=posts.length; i<x;++i) {
      this.post = posts[i];
      for (var j = 0, y = terms.length; j < y; ++j) {
      	if (this.post.textContent.search(terms[j]) > -1) {
      	  container = (findAncestor(this.post, 'timelineUnitContainer') || findAncestor(this.post, 'userContentWrapper')).parentElement;
      	  this.cursor = container.getAttribute('data-cursor');
      	  washStyle.innerHTML += 'div[data-cursor="'+this.cursor+'"] { opacity: .15; height: 5em; }';
          filteredArray.push(container);
      	}
      }
    }
  }
  var controller = "
<input type='text' id='blockItTerms'/>X
";
  document.body.innerHTML+=controller;
  controller = document.getElementById('blockItBox');
  controller.style.position = "fixed";
  controller.style.bottom = "0",
  controller.style.left = "0";
  controller.style.lineHeight = "42px";
  controller.style.minWidth = "0";
  fwClear = document.getElementById('fw-clear');
  fwClear.style.padding = "0 1em 0 2em";
  fwClear.style.fontSize = "16px";
  fwClear.style.color = "#fff";

  document.getElementById('blockItTerms').addEventListener('change', function() {
    terms = document.getElementById('blockItTerms').value;
    terms=terms.split(',');
    blockIt(terms);
  });
  document.getElementById('fw-clear').addEventListener('click', function() {
    clearFiltered(filteredArray);
  });
  window.addEventListener('scroll', function() {
    blockIt(terms);
  });
})()
<|endoftext|>


<commit_before>var Factions={"categories":[
	{"name":"Guild","factions":[
		{"id":"1168","name":"Guild"}
	]},
	{"name":"Mists of Pandaria","factions":[
		{"id":"1375","name":"Dominance Offensive"},
		{"id":"1492","name":"Emperor Shaohao"},
		{"id":"1269","name":"Golden Lotus"},
		{"id":"1387","name":"Kirin Tor Offensive"},
		{"id":"1358","name":"Nat Pagle"},
		{"id":"1376","name":"Operation: Shieldwall"},
		{"id":"1271","name":"Order of the Cloud Serpent"},
		{"id":"1270","name":"Shado-Pan"},
		{"id":"1435","name":"Shado-Pan Assault"},
		{"id":"1216","name":"Shang Xi's Academy"},
		{"id":"1388","name":"Sunreaver Onslaught"},
		{"id":"1302","name":"The Anglers"},
		{"id":"1341","name":"The August Celestials"},
		{"id":"1359","name":"The Black Prince"},
		{"id":"1337","name":"The Klaxxi"},
		{"id":"1345","name":"The Lorewalkers"}

	]},
	{"name":"The Tillers","factions":[
		{"id":"1277","name":"Chee Chee"},
		{"id":"1275","name":"Ella"},
		{"id":"1283","name":"Farmer Fung"},
		{"id":"1282","name":"Fish Fellreed"},
		{"id":"1281","name":"Gina Mudclaw"},
		{"id":"1279","name":"Haohan Mudclaw"},
		{"id":"1273","name":"Jogu the Drunk"},
		{"id":"1276","name":"Old Hillpaw"},
		{"id":"1278","name":"Sho"},
		{"id":"1280","name":"Tina Mudclaw"},
		{"id":"1357","name":"Nomi"}
	]},
	{"name":"Cataclysm","factions":[
		{"id":"1204","name":"Avengers of Hyjal"},
		{"id":"1177","name":"Baradin's Wardens"},
		{"id":"1172","name":"Dragonmaw Clan"},
		{"id":"1158","name":"Guardians of Hyjal"},
		{"id":"1178","name":"Hellscream's Reach"},
		{"id":"1173","name":"Ramkahen"},
		{"id":"1135","name":"The Earthen Ring"},
		{"id":"1171","name":"Therazane"},
		{"id":"1174","name":"Wildhammer Clan"}
	]},
	{"name":"Alliance Vanguard","factions":[
		{"id":"1037","name":"Alliance Vanguard"},
		{"id":"1068","name":"Explorers' League"},
		{"id":"1094","name":"The Silver Covenant"},
		{"id":"1126","name":"The Frostborn"},
		{"id":"1050","name":"Valiance Expedition"}
	]},
	{"name":"Horde Expedition","factions":[
		{"id":"1052","name":"Horde Expedition"},
		{"id":"1067","name":"The Hand of Vengeance"},
		{"id":"1124","name":"The Sunreavers"},
		{"id":"1064","name":"The Taunka"},
		{"id":"1085","name":"Warsong Offensive"}
	]},
	{"name":"Northrend Instances","factions":[
		{"id":"1106","name":"Argent Crusade"},
		{"id":"1090","name":"Kirin Tor"},
		{"id":"1098","name":"Knights of the Ebon Blade"},
		{"id":"1091","name":"The Wyrmrest Accord"}
	]},
	{"name":"Northrend Other","factions":[
		{"id":"1073","name":"The Kalu'ak"},
		{"id":"1104","name":"Frenzyheart Tribe"},
		{"id":"1105","name":"The Oracles"},
		{"id":"1119","name":"The Sons of Hodir"},
		{"id":"1156","name":"The Ashen Verdict"}
	]},
	{"name":"Outland Instances","factions":[
		{"id":"942","name":"Cenarion Expedition"},
		{"id":"946","name":"Honor Hold"},
		{"id":"989","name":"Keepers of Time"},
		{"id":"1011","name":"Lower City"},
		{"id":"935","name":"The Sha'tar"},
		{"id":"947","name":"Thrallmar"}
	]},
	{"name":"Outland Raid","factions":[
		{"id":"1012","name":"Ashtongue Deathsworn"},
		{"id":"967","name":"The Violet Eye"},
		{"id":"990","name":"The Scale of the Sands"}
	]},
	{"name":"Outland Other","factions":[
		{"id":"978","name":"Kurenai"},
		{"id":"941","name":"The Mag'har"},
		{"id":"1015","name":"Netherwing"},
		{"id":"1038","name":"Ogri'la"},
		{"id":"1031","name":"Sha'tari Skyguard"},
		{"id":"1077","name":"Shattered Sun Offensive"},
		{"id":"970","name":"Sporeggar"},
		{"id":"932","name":"The Aldor"},
		{"id":"933","name":"The Consortium"},
		{"id":"934","name":"The Scryers"}
	]},
	{"name":"Horde","factions":[
		{"id":"1133","name":"Bilgewater Cartel"},
		{"id":"530","name":"Darkspear Trolls"},
		{"id":"76","name":"Orgrimmar"},
		{"id":"911","name":"Silvermoon City"},
		{"id":"81","name":"Thunder Bluff"},
		{"id":"68","name":"Undercity"}
	]},
	{"name":"Alliance","factions":[
		{"id":"69","name":"Darnassus"},
		{"id":"930","name":"Exodar"},
		{"id":"1134","name":"Gilneas"},
		{"id":"54","name":"Gnomeregan"},
		{"id":"47","name":"Ironforge"},
		{"id":"72","name":"Stormwind"}
	]},
	{"name":"Horde Forces","factions":[
		{"id":"729","name":"Frostwolf Clan"},
		{"id":"510","name":"The Defilers"},
		{"id":"889","name":"Warsong Outriders"}
	]},
	{"name":"Alliance Forces","factions":[
		{"id":"890","name":"Silverwing Sentinels"},
		{"id":"730","name":"Stormpike Guard"},
		{"id":"509","name":"The League of Arathor"}
	]},
	{"name":"Steamwheedle Cartel","factions":[
		{"id":"21","name":"Booty Bay"},
		{"id":"577","name":"Everlook"},
		{"id":"369","name":"Gadgetzan"},
		{"id":"470","name":"Ratchet"}
	]},
	{"name":"Azeroth Raid","factions":[
		{"id":"529","name":"Argent Dawn"},
		{"id":"910","name":"Brood of Nozdormu"},
		{"id":"609","name":"Cenarion Circle"},
		{"id":"749","name":"Hydraxian Waterlords"},
		{"id":"270","name":"Zandalar Tribe"}
	]},
	{"name":"Azeroth Other","factions":[
		{"id":"87","name":"Bloodsail Buccaneers"},
		{"id":"909","name":"Darkmoon Faire"},
		{"id":"349","name":"Ravenholdt"},
		{"id":"809","name":"Shen'dralar"},
		{"id":"70","name":"Syndicate"},
		{"id":"59","name":"Thorium Brotherhood"},
		{"id":"576","name":"Timbermaw Hold"},
		{"id":"922","name":"Tranquillien"},
		{"id":"589","name":"Wintersaber Trainers"}
	]}
]};
<commit_msg>Added Five missing factions<commit_after>var Factions={"categories":[
	{"name":"Guild","factions":[
		{"id":"1168","name":"Guild"}
	]},
	{"name":"Mists of Pandaria","factions":[
		{"id":"1375","name":"Dominance Offensive"},
		{"id":"1492","name":"Emperor Shaohao"},
		{"id":"1269","name":"Golden Lotus"},
		{"id":"1387","name":"Kirin Tor Offensive"},
		{"id":"1358","name":"Nat Pagle"},
		{"id":"1376","name":"Operation: Shieldwall"},
		{"id":"1271","name":"Order of the Cloud Serpent"},
		{"id":"1270","name":"Shado-Pan"},
		{"id":"1435","name":"Shado-Pan Assault"},
		{"id":"1216","name":"Shang Xi's Academy"},
		{"id":"1388","name":"Sunreaver Onslaught"},
		{"id":"1302","name":"The Anglers"},
		{"id":"1341","name":"The August Celestials"},
		{"id":"1359","name":"The Black Prince"},
		{"id":"1337","name":"The Klaxxi"},
		{"id":"1345","name":"The Lorewalkers"}

	]},
	{"name":"The Tillers","factions":[
		{"id":"1272","name":"The Tillers"},
		{"id":"1277","name":"Chee Chee"},
		{"id":"1275","name":"Ella"},
		{"id":"1283","name":"Farmer Fung"},
		{"id":"1282","name":"Fish Fellreed"},
		{"id":"1281","name":"Gina Mudclaw"},
		{"id":"1279","name":"Haohan Mudclaw"},
		{"id":"1273","name":"Jogu the Drunk"},
		{"id":"1357","name":"Nomi"},
		{"id":"1276","name":"Old Hillpaw"},
		{"id":"1278","name":"Sho"},
		{"id":"1280","name":"Tina Mudclaw"}
	]},
	{"name":"Cataclysm","factions":[
		{"id":"1204","name":"Avengers of Hyjal"},
		{"id":"1177","name":"Baradin's Wardens"},
		{"id":"1172","name":"Dragonmaw Clan"},
		{"id":"1158","name":"Guardians of Hyjal"},
		{"id":"1178","name":"Hellscream's Reach"},
		{"id":"1173","name":"Ramkahen"},
		{"id":"1135","name":"The Earthen Ring"},
		{"id":"1171","name":"Therazane"},
		{"id":"1174","name":"Wildhammer Clan"}
	]},
	{"name":"Alliance Vanguard","factions":[
		{"id":"1037","name":"Alliance Vanguard"},
		{"id":"1068","name":"Explorers' League"},
		{"id":"1094","name":"The Silver Covenant"},
		{"id":"1126","name":"The Frostborn"},
		{"id":"1050","name":"Valiance Expedition"}
	]},
	{"name":"Horde Expedition","factions":[
		{"id":"1052","name":"Horde Expedition"},
		{"id":"1067","name":"The Hand of Vengeance"},
		{"id":"1124","name":"The Sunreavers"},
		{"id":"1064","name":"The Taunka"},
		{"id":"1085","name":"Warsong Offensive"}
	]},
	{"name":"Northrend Instances","factions":[
		{"id":"1106","name":"Argent Crusade"},
		{"id":"1090","name":"Kirin Tor"},
		{"id":"1098","name":"Knights of the Ebon Blade"},
		{"id":"1091","name":"The Wyrmrest Accord"}
	]},
	{"name":"Northrend Other","factions":[
		{"id":"1156","name":"The Ashen Verdict"},
		{"id":"1104","name":"Frenzyheart Tribe"},
		{"id":"1073","name":"The Kalu'ak"},
		{"id":"1105","name":"The Oracles"},
		{"id":"1119","name":"The Sons of Hodir"}
	]},
	{"name":"Outland Instances","factions":[
		{"id":"942","name":"Cenarion Expedition"},
		{"id":"946","name":"Honor Hold"},
		{"id":"989","name":"Keepers of Time"},
		{"id":"1011","name":"Lower City"},
		{"id":"935","name":"The Sha'tar"},
		{"id":"947","name":"Thrallmar"}
	]},
	{"name":"Outland Raid","factions":[
		{"id":"1012","name":"Ashtongue Deathsworn"},
		{"id":"990","name":"The Scale of the Sands"},
		{"id":"967","name":"The Violet Eye"}
	]},
	{"name":"Outland Other","factions":[
		{"id":"978","name":"Kurenai"},
		{"id":"941","name":"The Mag'har"},
		{"id":"1015","name":"Netherwing"},
		{"id":"1038","name":"Ogri'la"},
		{"id":"1031","name":"Sha'tari Skyguard"},
		{"id":"1077","name":"Shattered Sun Offensive"},
		{"id":"970","name":"Sporeggar"},
		{"id":"932","name":"The Aldor"},
		{"id":"933","name":"The Consortium"},
		{"id":"934","name":"The Scryers"}
	]},
	{"name":"Horde","factions":[
		{"id":"1133","name":"Bilgewater Cartel"},
		{"id":"530","name":"Darkspear Trolls"},
		{"id":"76","name":"Orgrimmar"},
		{"id":"911","name":"Silvermoon City"},
		{"id":"81","name":"Thunder Bluff"},
		{"id":"68","name":"Undercity"}
	]},
	{"name":"Alliance","factions":[
		{"id":"69","name":"Darnassus"},
		{"id":"930","name":"Exodar"},
		{"id":"1134","name":"Gilneas"},
		{"id":"54","name":"Gnomeregan"},
		{"id":"47","name":"Ironforge"},
		{"id":"72","name":"Stormwind"}
	]},
	{"name":"Horde Forces","factions":[
		{"id":"1374","name":"Brawl'gar Arena"},
		{"id":"729","name":"Frostwolf Clan"},
		{"id":"510","name":"The Defilers"},
		{"id":"889","name":"Warsong Outriders"}
	]},
	{"name":"Alliance Forces","factions":[
		{"id":"1419","name":"Bizmo's Brawlpub"},
		{"id":"890","name":"Silverwing Sentinels"},
		{"id":"730","name":"Stormpike Guard"},
		{"id":"509","name":"The League of Arathor"}
	]},
	{"name":"Steamwheedle Cartel","factions":[
		{"id":"21","name":"Booty Bay"},
		{"id":"577","name":"Everlook"},
		{"id":"369","name":"Gadgetzan"},
		{"id":"470","name":"Ratchet"}
	]},
	{"name":"Azeroth Raid","factions":[
		{"id":"529","name":"Argent Dawn"},
		{"id":"910","name":"Brood of Nozdormu"},
		{"id":"609","name":"Cenarion Circle"},
		{"id":"749","name":"Hydraxian Waterlords"},
		{"id":"270","name":"Zandalar Tribe"}
	]},
	{"name":"Azeroth Other","factions":[
		{"id":"87","name":"Bloodsail Buccaneers"},
		{"id":"909","name":"Darkmoon Faire"},
		{"id":"92","name":"Gelkis Clan Centaur"},
		{"id":"93","name":"Magram Clan Centaur"},
		{"id":"349","name":"Ravenholdt"},
		{"id":"809","name":"Shen'dralar"},
		{"id":"70","name":"Syndicate"},
		{"id":"59","name":"Thorium Brotherhood"},
		{"id":"576","name":"Timbermaw Hold"},
		{"id":"922","name":"Tranquillien"},
		{"id":"589","name":"Wintersaber Trainers"}
	]}
]};
<|endoftext|>


<commit_before>//Aimed at Chrome (last 2 to 3 years), firefox (last 2 to 3 years), IE9+, Opera 10+, Safari 4+
//Some specific functions may require a newer browser
//The idea behind this library is not to provide cross-browser stuff, but to make a very light library with as little extra code to support older browsers
//As of now the only cross-browser code present is the dataset generation for IE9 and 10.

/* CORE */

function $(m) {
	return $.$(document, m);
}

$.$ = function(el, m) {
	if (m instanceof HTMLElement) {
		if (!m.dataset) {
			m.dataset = $.createDataSet(m);
		}
		return new $.CustomList([m]);
	} else if ((m instanceof Array) || (m instanceof HTMLCollection) || (m instanceof NodeList)) {
		return new $.CustomList(m);
	}
	var r = el.querySelectorAll(m);
	for (var i = 0; i < r.length; i++) {
		if (!r[i].dataset) {
			r[i].dataset = $.createDataSet(r[i]);
		}
	}
	return new $.CustomList(r);
}

//Alas, normal datasets are supported only in IE11+, so we still have some code for older browsers (it's rather lame that even in 2013-2015 we still have to write custom stuff for IE)
$.createDataSet = function(el) { //generate the dataset (just an object, not a string map)
	var r = {}
	for (var i = 0; i < el.attributes.length; i++) {
		if (el.attributes[i].name.substring(0, 5) == "data-") {
			var n = el.attributes[i].name.substring(5),
			m = n.match(/-(.)/);
			while (m != null) {
				n = n.replace(m[0], m[1].toUpperCase());
				m = n.match(/-(.)/);
			}
			r[n] = el.attributes[i].value;
		}
	}
	return r;
}

/**
 * @constructor
 */
$.CustomList = function(list) {
	for (var i = 0; i < list.length; i++) {
		this[i] = list[i];
	}
	this.length = list.length;
}

/* DEFAULT MANIPULATION FUNCTIONS */
//Probably something like Chrome 1+, Firefox 1+, IE9+, Opera 7+, Safari 1+

$.CustomList.prototype.get = function(p) { //Returns the property for the first item in the list (regardless of whether it is defined or not)
	if (this.length > 0) {
		return this[0][p];
	} else {
		return undefined;
	}
}

$.CustomList.prototype.getAttribute = function(p) { //Returns the attribute for the first item in the list (regardless of whether it is defined or not)
	if (this.length > 0) {
		return this[0].getAttribute(p);
	} else {
		return undefined;
	}
}

$.CustomList.prototype.set = function(p, v) {
	for (var i = 0; i < this.length; i++) {
		this[i][p] = v;
	}
	return this;
}

$.CustomList.prototype.append = function(p, v) {
	for (var i = 0; i < this.length; i++) {
		this[i][p] = this[i][p] + v;
	}
	return this;
}

$.CustomList.prototype.setStyle = function(s) {
	if ((s instanceof String) || (typeof s === "string")) {
		for (var i = 0; i < this.length; i++) {
			this[i].style.cssText += ";" + s;
		}
	} else {
		for (var i = 0; i < this.length; i++) {
			for (var p in s) {
				this[i].style[p] = s[p];
			}
		}
	}
	return this;
}

$.CustomList.prototype.setInnerHTML = function(s) {
	for (var i = 0; i < this.length; i++) {
		this[i].innerHTML = s;
	}
	return this;
}

$.CustomList.prototype.addEventListener = function() {
	for (var i = 0; i < this.length; i++) {
		this[i].addEventListener(arguments[0], arguments[1], arguments[2], arguments[3]);
	}
	return this;
}

$.CustomList.prototype.removeEventListener = function() {
	for (var i = 0; i < this.length; i++) {
		this[i].removeEventListener(arguments[0], arguments[1], arguments[2], arguments[3]);
	}
	return this;
}

$.remove = function(el) {
	if (el.parentNode) {
		el.parentNode.removeChild(el);
	}
}

$.CustomList.prototype.remove = function() {
	for (var i = 0; i < this.length; i++) {
		$.remove(this[i]);
	}

	return this;
}

$.hasClass = function(el, c) {
	return el.className.search(new RegExp('\\b'+c+'\\b', "g")) != -1;
}

$.CustomList.prototype.hasClass = function(c) {
	for (var i = 0; i < this.length; i++) {
		if ($.hasClass(this[i], c)) {
			return true;
		}
	}

	return false;
}

$.CustomList.prototype.allHaveClass = function(c) {
	for (var i = 0; i < this.length; i++) {
		if (!$.hasClass(this[i], c)) {
			return false;
		}
	}

	return true;
}

$.addClass = function(el, c) {
	if (el.className.search(new RegExp('\\b'+c+'\\b', "g")) == -1) {
		el.className += " "+c;
	}
}

$.CustomList.prototype.addClass = function(c) {
	for (var i = 0; i < this.length; i++) {
		$.addClass(this[i], c);
	}
	return this;
}

$.removeClass = function(el, c) {
	el.className = el.className.replace(new RegExp(' ?\\b'+c+'\\b', 'g'), '');
}

$.CustomList.prototype.removeClass = function(c) {
	for (var i=0; i < this.length; i++) {
		$.removeClass(this[i], c);
	}
	return this;
}

$.toggleClass = function(el, c) {
	if ($.hasClass(el, c)) {
		$.removeClass(el, c);
	} else {
		$.addClass(el, c);
	}
}

$.CustomList.prototype.toggleClass = function(c) {
	for (var i=0; i < this.length; i++) {
		$.toggleClass(this[i], c);
	}
	return this;
}

$.CustomList.prototype.run = function(f) {
	var args = Array.prototype.slice.call(arguments, 1), r;
	args.push(0);
	for (var i = 0; i < this.length; i++) {
		args[args.length-1] = i;
		r = f.apply(this[i], args);
	}
	return this;
}

$.CustomList.prototype.each = function(f) {
	var args = Array.prototype.slice.call(arguments, 1), r;
	for (var i = 0; i < this.length; i++) {
		if (f.apply(this[i], args) === false) {
			break;
		}
	}
	return this;
}

$.getText = function(el) {
	return el.innerText || (document.createTextNode(el.innerHTML.replace(/
/g, String.fromCharCode(13, 10)))).textContent;
}

$.CustomList.prototype.getText = function() {
	if (this.length > 0) {
		return $.getText(this[0]);
	} else {
		return undefined;
	}
}

/* REQUEST */
//Chrome 1+, Firefox 1+, IE7+, Opera, Safari 1.2+
//with FormData or HTMLFormElement: Chrome 6+, Firefox 4+, IE10+, Opera 12+, Safari?

$.toQueryString = function(obj) {
	var parts = [];
	for (var property in obj) {
		if (obj.hasOwnProperty(property)) {
			parts.push(encodeURIComponent(property) + '=' + encodeURIComponent(obj[property]));
		}
	}

	return parts.join('&');
}

$.Request = function(url, method, data, doneHandler, failedHandler, finalFailedHandler, callBeforeSend, uploadProgressHandler, progressHandler, timeout) {
	this.xhr = new XMLHttpRequest();

	if (typeof timeout === 'number') {
		this.xhr.timeout = timeout;
	}

	this.xhr.open(method, url, true);

	if (typeof data === 'object') {
		if ((!FormData) || !(data instanceof FormData)) {
			data = $.toQueryString(data);
			this.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		}
	} else if (data instanceof HTMLFormElement) {
		if (FormData) {
			data = new FormData(data);
		} else {
			console.error('I require FormData for this method.');
		}
	}

	var _this = this;
	this.xhr.onreadystatechange = function(e) {
		if (_this.xhr.readyState == 4) {
			if (_this.xhr.status == 200) {
				doneHandler(e, _this.xhr);
			} else if (typeof failedHandler === "function") {
				failedHandler(e, _this.xhr);
			} else if (failedHandler > 0) {
				_this.resend(url, method, data, doneHandler, failedHandler-1, finalFailedHandler, callBeforeSend, uploadProgressHandler, progressHandler, timeout);
			} else {
				finalFailedHandler(e, _this.xhr);
			}
		}
	}

	if (typeof uploadProgressHandler === 'function') {
		this.xhr.upload.addEventListener("progress", uploadProgressHandler);
	}

	if (typeof progressHandler === 'function') {
		this.xhr.addEventListener("progress", progressHandler);
	}

	if (typeof callBeforeSend === "function") {
		callBeforeSend(this.xhr, data);
	}
	this.xhr.send(data);
}

$.Request.prototype.abort = function() {
	this.xhr.abort();
}

$.Request.prototype.resend = function(url, method, data, doneHandler, failedHandler, finalFailedHandler, callBeforeSend, uploadProgressHandler, progressHandler, timeout) {
	this.xhr = new XMLHttpRequest();

	if (typeof timeout === 'number') {
		this.xhr.timeout = timeout;
	}

	this.xhr.open(method, url, true);

	var _this = this;
	this.xhr.onreadystatechange = function(e) {
		if (_this.xhr.readyState == 4) {
			if (_this.xhr.status == 200) {
				doneHandler(e, _this.xhr);
			} else if (typeof failedHandler === "function") {
				failedHandler(e, _this.xhr);
			} else if (failedHandler > 0) {
				_this.resend(url, method, data, doneHandler, failedHandler-1, finalFailedHandler, callBeforeSend, uploadProgressHandler, progressHandler, timeout);
			} else {
				finalFailedHandler(e, _this.xhr);
			}
		}
	}

	if (typeof uploadProgressHandler === 'function') {
		this.xhr.upload.addEventListener("progress", uploadProgressHandler);
	}

	if (typeof progressHandler === 'function') {
		this.xhr.addEventListener("progress", progressHandler);
	}

	if (typeof callBeforeSend === "function") {
		callBeforeSend(this.xhr, data);
	}
	this.xhr.send(data);
}
<commit_msg>Add setAttribute function.<commit_after>//Aimed at Chrome (last 2 to 3 years), firefox (last 2 to 3 years), IE9+, Opera 10+, Safari 4+
//Some specific functions may require a newer browser
//The idea behind this library is not to provide cross-browser stuff, but to make a very light library with as little extra code to support older browsers
//As of now the only cross-browser code present is the dataset generation for IE9 and 10.

/* CORE */

function $(m) {
	return $.$(document, m);
}

$.$ = function(el, m) {
	if (m instanceof HTMLElement) {
		if (!m.dataset) {
			m.dataset = $.createDataSet(m);
		}
		return new $.CustomList([m]);
	} else if ((m instanceof Array) || (m instanceof HTMLCollection) || (m instanceof NodeList)) {
		return new $.CustomList(m);
	}
	var r = el.querySelectorAll(m);
	for (var i = 0; i < r.length; i++) {
		if (!r[i].dataset) {
			r[i].dataset = $.createDataSet(r[i]);
		}
	}
	return new $.CustomList(r);
}

//Alas, normal datasets are supported only in IE11+, so we still have some code for older browsers (it's rather lame that even in 2013-2015 we still have to write custom stuff for IE)
$.createDataSet = function(el) { //generate the dataset (just an object, not a string map)
	var r = {}
	for (var i = 0; i < el.attributes.length; i++) {
		if (el.attributes[i].name.substring(0, 5) == "data-") {
			var n = el.attributes[i].name.substring(5),
			m = n.match(/-(.)/);
			while (m != null) {
				n = n.replace(m[0], m[1].toUpperCase());
				m = n.match(/-(.)/);
			}
			r[n] = el.attributes[i].value;
		}
	}
	return r;
}

/**
 * @constructor
 */
$.CustomList = function(list) {
	for (var i = 0; i < list.length; i++) {
		this[i] = list[i];
	}
	this.length = list.length;
}

/* DEFAULT MANIPULATION FUNCTIONS */
//Probably something like Chrome 1+, Firefox 1+, IE9+, Opera 7+, Safari 1+

$.CustomList.prototype.get = function(p) { //Returns the property for the first item in the list (regardless of whether it is defined or not)
	if (this.length > 0) {
		return this[0][p];
	} else {
		return undefined;
	}
}

$.CustomList.prototype.getAttribute = function(p) { //Returns the attribute for the first item in the list (regardless of whether it is defined or not)
	if (this.length > 0) {
		return this[0].getAttribute(p);
	} else {
		return undefined;
	}
}

$.CustomList.prototype.set = function(p, v) {
	for (var i = 0; i < this.length; i++) {
		this[i][p] = v;
	}
	return this;
}

$.CustomList.prototype.setAttribute = function(p, v) {
	for (var i = 0; i < this.length; i++) {
		this[i].setAttribute(p, v);
	}
	return this;
}

$.CustomList.prototype.append = function(p, v) {
	for (var i = 0; i < this.length; i++) {
		this[i][p] = this[i][p] + v;
	}
	return this;
}

$.CustomList.prototype.setStyle = function(s) {
	if ((s instanceof String) || (typeof s === "string")) {
		for (var i = 0; i < this.length; i++) {
			this[i].style.cssText += ";" + s;
		}
	} else {
		for (var i = 0; i < this.length; i++) {
			for (var p in s) {
				this[i].style[p] = s[p];
			}
		}
	}
	return this;
}

$.CustomList.prototype.setInnerHTML = function(s) {
	for (var i = 0; i < this.length; i++) {
		this[i].innerHTML = s;
	}
	return this;
}

$.CustomList.prototype.addEventListener = function() {
	for (var i = 0; i < this.length; i++) {
		this[i].addEventListener(arguments[0], arguments[1], arguments[2], arguments[3]);
	}
	return this;
}

$.CustomList.prototype.removeEventListener = function() {
	for (var i = 0; i < this.length; i++) {
		this[i].removeEventListener(arguments[0], arguments[1], arguments[2], arguments[3]);
	}
	return this;
}

$.remove = function(el) {
	if (el.parentNode) {
		el.parentNode.removeChild(el);
	}
}

$.CustomList.prototype.remove = function() {
	for (var i = 0; i < this.length; i++) {
		$.remove(this[i]);
	}

	return this;
}

$.hasClass = function(el, c) {
	return el.className.search(new RegExp('\\b'+c+'\\b', "g")) != -1;
}

$.CustomList.prototype.hasClass = function(c) {
	for (var i = 0; i < this.length; i++) {
		if ($.hasClass(this[i], c)) {
			return true;
		}
	}

	return false;
}

$.CustomList.prototype.allHaveClass = function(c) {
	for (var i = 0; i < this.length; i++) {
		if (!$.hasClass(this[i], c)) {
			return false;
		}
	}

	return true;
}

$.addClass = function(el, c) {
	if (el.className.search(new RegExp('\\b'+c+'\\b', "g")) == -1) {
		el.className += " "+c;
	}
}

$.CustomList.prototype.addClass = function(c) {
	for (var i = 0; i < this.length; i++) {
		$.addClass(this[i], c);
	}
	return this;
}

$.removeClass = function(el, c) {
	el.className = el.className.replace(new RegExp(' ?\\b'+c+'\\b', 'g'), '');
}

$.CustomList.prototype.removeClass = function(c) {
	for (var i=0; i < this.length; i++) {
		$.removeClass(this[i], c);
	}
	return this;
}

$.toggleClass = function(el, c) {
	if ($.hasClass(el, c)) {
		$.removeClass(el, c);
	} else {
		$.addClass(el, c);
	}
}

$.CustomList.prototype.toggleClass = function(c) {
	for (var i=0; i < this.length; i++) {
		$.toggleClass(this[i], c);
	}
	return this;
}

$.CustomList.prototype.run = function(f) {
	var args = Array.prototype.slice.call(arguments, 1), r;
	args.push(0);
	for (var i = 0; i < this.length; i++) {
		args[args.length-1] = i;
		r = f.apply(this[i], args);
	}
	return this;
}

$.CustomList.prototype.each = function(f) {
	var args = Array.prototype.slice.call(arguments, 1), r;
	for (var i = 0; i < this.length; i++) {
		if (f.apply(this[i], args) === false) {
			break;
		}
	}
	return this;
}

$.getText = function(el) {
	return el.innerText || (document.createTextNode(el.innerHTML.replace(/
/g, String.fromCharCode(13, 10)))).textContent;
}

$.CustomList.prototype.getText = function() {
	if (this.length > 0) {
		return $.getText(this[0]);
	} else {
		return undefined;
	}
}

/* REQUEST */
//Chrome 1+, Firefox 1+, IE7+, Opera, Safari 1.2+
//with FormData or HTMLFormElement: Chrome 6+, Firefox 4+, IE10+, Opera 12+, Safari?

$.toQueryString = function(obj) {
	var parts = [];
	for (var property in obj) {
		if (obj.hasOwnProperty(property)) {
			parts.push(encodeURIComponent(property) + '=' + encodeURIComponent(obj[property]));
		}
	}

	return parts.join('&');
}

$.Request = function(url, method, data, doneHandler, failedHandler, finalFailedHandler, callBeforeSend, uploadProgressHandler, progressHandler, timeout) {
	this.xhr = new XMLHttpRequest();

	if (typeof timeout === 'number') {
		this.xhr.timeout = timeout;
	}

	this.xhr.open(method, url, true);

	if (typeof data === 'object') {
		if ((!FormData) || !(data instanceof FormData)) {
			data = $.toQueryString(data);
			this.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		}
	} else if (data instanceof HTMLFormElement) {
		if (FormData) {
			data = new FormData(data);
		} else {
			console.error('I require FormData for this method.');
		}
	}

	var _this = this;
	this.xhr.onreadystatechange = function(e) {
		if (_this.xhr.readyState == 4) {
			if (_this.xhr.status == 200) {
				doneHandler(e, _this.xhr);
			} else if (typeof failedHandler === "function") {
				failedHandler(e, _this.xhr);
			} else if (failedHandler > 0) {
				_this.resend(url, method, data, doneHandler, failedHandler-1, finalFailedHandler, callBeforeSend, uploadProgressHandler, progressHandler, timeout);
			} else {
				finalFailedHandler(e, _this.xhr);
			}
		}
	}

	if (typeof uploadProgressHandler === 'function') {
		this.xhr.upload.addEventListener("progress", uploadProgressHandler);
	}

	if (typeof progressHandler === 'function') {
		this.xhr.addEventListener("progress", progressHandler);
	}

	if (typeof callBeforeSend === "function") {
		callBeforeSend(this.xhr, data);
	}
	this.xhr.send(data);
}

$.Request.prototype.abort = function() {
	this.xhr.abort();
}

$.Request.prototype.resend = function(url, method, data, doneHandler, failedHandler, finalFailedHandler, callBeforeSend, uploadProgressHandler, progressHandler, timeout) {
	this.xhr = new XMLHttpRequest();

	if (typeof timeout === 'number') {
		this.xhr.timeout = timeout;
	}

	this.xhr.open(method, url, true);

	var _this = this;
	this.xhr.onreadystatechange = function(e) {
		if (_this.xhr.readyState == 4) {
			if (_this.xhr.status == 200) {
				doneHandler(e, _this.xhr);
			} else if (typeof failedHandler === "function") {
				failedHandler(e, _this.xhr);
			} else if (failedHandler > 0) {
				_this.resend(url, method, data, doneHandler, failedHandler-1, finalFailedHandler, callBeforeSend, uploadProgressHandler, progressHandler, timeout);
			} else {
				finalFailedHandler(e, _this.xhr);
			}
		}
	}

	if (typeof uploadProgressHandler === 'function') {
		this.xhr.upload.addEventListener("progress", uploadProgressHandler);
	}

	if (typeof progressHandler === 'function') {
		this.xhr.addEventListener("progress", progressHandler);
	}

	if (typeof callBeforeSend === "function") {
		callBeforeSend(this.xhr, data);
	}
	this.xhr.send(data);
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2020-2022 Kenneth Tran and CAD Team
 * (https://github.com/Cookie-AutoDelete/Cookie-AutoDelete/graphs/contributors)
 * Licensed under MIT
 * (https://github.com/Cookie-AutoDelete/Cookie-AutoDelete/blob/3.X.X-Branch/LICENSE)
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
const fs = require('fs');
const path = require('path');
const archiver = require('archiver');

const BUILDS = 'builds';
const EXT = 'extension';
const EXTNAME = 'Cookie-AutoDelete_';
const MANIFEST = 'manifest.json';

const ROOTDIR = process.cwd();
const BUILDDIR = path.join(ROOTDIR, BUILDS);
const EXTDIR = path.join(ROOTDIR, EXT);

console.log(
  '\n\nUsing NodeJS Version %s on %s %s',
  process.version,
  process.platform,
  process.arch,
);
console.log('Current Root Directory is:  %s', ROOTDIR);

console.log('GITHUB_REF:  %s', process.env.GITHUB_REF);
console.log('TRAVIS_TAG:  %s', process.env.TRAVIS_TAG);
console.log('GITSHA    :  %s', process.env.GITSHA);

let versionTag = process.env.GITHUB_REF || process.env.TRAVIS_TAG || '';

if (versionTag.startsWith('refs/tags/')) {
  versionTag = versionTag.slice(10);
}

if (versionTag && !RegExp(/^v?\d+\.\d+\.\d+$/).test(versionTag)) {
  console.warn('Version [ %s ] is not in valid semver form.', versionTag);
  versionTag = '';
}

if (!versionTag) {
  console.log(
    'Neither GITHUB_REF nor TRAVIS_TAG contained a valid semver version.  Presuming non-publishing version.\nAdding Dev_ and using Date Format YYYYMMDD_HHMMSS as tag.',
  );
}

const sha = process.env.GITSHA ? `_${process.env.GITSHA.substr(0, 7)}` : '';

const TAG =
  (versionTag ||
    'Dev_' +
      new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60000)
        .toISOString()
        .replace(/T/, '_')
        .replace(/-|:|\..+/g, '')) +
  sha +
  '_';

console.log('TAG to append:  %s\n', TAG);

const CHROMEFILENAME = EXTNAME + TAG + 'Chrome';
const FIREFOXFILENAME = EXTNAME + TAG + 'Firefox';

function archiverZip(cb, filename) {
  if (typeof cb !== 'function') {
    console.error('callback is not a function!');
    return null;
  }
  const fileStream = fs.createWriteStream(
    path.join(BUILDDIR, filename + '.zip'),
  );

  const archive = archiver('zip', {
    zlib: { level: 9 }, // Sets the Compression Level.
  });

  // Listen for all archive data to be written
  // 'close' eent is fired only when a file descriptor is involved
  function fileOnClose() {
    console.log(archive.pointer() + ' total bytes');
    console.log(
      'archiver has been finalized and the output file descriptor has closed.',
    );
    cb(0);
  }

  // This event is fired when data source is drained no matter what was the data source.
  // Not part of archiver but from NodeJS Stream API.
  function fileOnEnd() {
    console.log('Data has been drained');
  }

  console.log('Creating an archive in: %s', fileStream.path);

  fileStream.on('close', fileOnClose);
  fileStream.on('end', fileOnEnd);

  // Good Practice to catch warnings (ie stat failures and other non-blocking errors)
  archive.on('warning', function (err) {
    if (err.code === 'ENOENT') {
      console.warn(
        'ARCHIVER WARNING %s: %s (%s)',
        err.code,
        err.message,
        err.data,
      );
    } else {
      throw err;
    }
  });

  // Good Practice to catch his error explicitly
  archive.on('error', function (err) {
    throw err;
  });

  // Pipe archive data to the file
  archive.pipe(fileStream);

  // Append files from Extension Folder.
  archive.directory(EXTDIR, false);

  archive.finalize();
}

function firefoxBuild(cb) {
  if (typeof cb !== 'function') {
    console.error('callback is not a function!');
    return null;
  }
  console.log('\nBuilding unsigned extension for Mozilla Firefox...');

  archiverZip(function (r) {
    if (r === 0) {
      // Copy ZIP to XPI
      console.log('Copying .ZIP to .XPI...');
      fs.copyFileSync(
        path.join(BUILDDIR, FIREFOXFILENAME + '.zip'),
        path.join(BUILDDIR, FIREFOXFILENAME + '.xpi'),
      );
      console.log('>> Copy Success!');
      // End of Mozilla Firefox build.
      console.log('Mozilla Firefox Build Complete!');
    } else {
      console.warn(
        'Archiver was not successful as it returned [%s]. Stopping the rest of the process.',
        r,
      );
    }
    cb(r);
  }, FIREFOXFILENAME);
}

function chromeBuild(cb) {
  if (typeof cb !== 'function') {
    console.error('callback is not a function!');
    return null;
  }
  // Copy manifest into memory to preserve it.
  console.log('\nGetting a copy of %s to memory...', MANIFEST);
  const mforig = fs.readFileSync(path.join(EXTDIR, MANIFEST));
  console.log('>> Done!');
  console.log('Prepping %s for Google Chrome...', MANIFEST);

  function delMFPerm(mf, perm) {
    let i = mf.permissions.indexOf(perm);
    console.log(
      '> Removing Perm: %s ... %s',
      perm,
      i === -1
        ? 'Not Found!'
        : mf.permissions.splice(i, 1).length === 1
        ? 'Done!'
        : 'An Easter Egg Error!',
    );
  }

  const mf = require(path.join(EXTDIR, MANIFEST));
  delMFPerm(mf, 'contextualIdentities');
  console.log(
    '> Removing [applications] section ... %s',
    delete mf.applications ? 'Done!' : 'Failed',
  );

  console.log('Overwriting %s for Google Chrome ...', MANIFEST);
  fs.writeFileSync(path.join(EXTDIR, MANIFEST), JSON.stringify(mf, null, 2));
  console.log('>> Done!');

  console.log('\nBuilding unsigned extension for Google Chrome...');

  archiverZip(function (r) {
    if (r === 0) {
      // continue
      // Revert modifications
      fs.writeFileSync(path.join(EXTDIR, MANIFEST), mforig);
      console.log('%s has been reverted back to original contents!', MANIFEST);

      // End of Google Chrome build.
      console.log('Google Chrome Build Complete!');
    } else {
      console.warn(
        'Archiver was not successful as it returned [%s]. Stopping the rest of the process.',
        r,
      );
    }
    cb(r);
  }, CHROMEFILENAME);
}

function mainBuild() {
  firefoxBuild((r) => {
    if (r === 0) {
      // Do Chrome Build
      chromeBuild((r) => {
        if (r === 0) {
          // EdgeChromium Build, for future.
          console.log('\n\n> All Done! <\n');
        } else {
          console.error(
            'Google Chrome Build did not complete successfully.  Stopping the rest of the Build.',
          );
          process.exitCode = 4;
        }
      });
    } else {
      console.error(
        'Firefox Build did not complete successfully.  Stopping the rest of the progress',
      );
      process.exitCode = 3;
    }
  });
}

function preCheck(cb) {
  if (typeof cb !== 'function') {
    console.error('callback is not a function!');
    return null;
  }
  console.log('Creating %s if it does not exists...', BUILDDIR);
  fs.mkdirSync(BUILDDIR, { recursive: true });

  console.log('Checking if %s folder exists...', EXTDIR);
  const extRes = fs.statSync(EXTDIR);
  if (!extRes) {
    console.error(
      '%s does NOT exist - Cannot build WebExtension.  Terminating.',
      EXTDIR,
    );
    cb(1);
  } else if (!extRes.isDirectory()) {
    console.error(
      '%s is found but is NOT a directory.  Cannot build WebExtension.  Terminating.',
      EXTDIR,
    );
    cb(2);
  } else {
    console.log('Yup.  Directory %s Exists!', EXTDIR);
    cb(0);
  }
}

// Start Point!
preCheck((r) => {
  if (r === 0) {
    mainBuild();
  } else {
    console.warn('PreCheck Failed! Terminating!');
    process.exitCode = r;
  }
});
<commit_msg>Replace deprecated String.prototype.substr() (#1319)<commit_after>/**
 * Copyright (c) 2020-2022 Kenneth Tran and CAD Team
 * (https://github.com/Cookie-AutoDelete/Cookie-AutoDelete/graphs/contributors)
 * Licensed under MIT
 * (https://github.com/Cookie-AutoDelete/Cookie-AutoDelete/blob/3.X.X-Branch/LICENSE)
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
const fs = require('fs');
const path = require('path');
const archiver = require('archiver');

const BUILDS = 'builds';
const EXT = 'extension';
const EXTNAME = 'Cookie-AutoDelete_';
const MANIFEST = 'manifest.json';

const ROOTDIR = process.cwd();
const BUILDDIR = path.join(ROOTDIR, BUILDS);
const EXTDIR = path.join(ROOTDIR, EXT);

console.log(
  '\n\nUsing NodeJS Version %s on %s %s',
  process.version,
  process.platform,
  process.arch,
);
console.log('Current Root Directory is:  %s', ROOTDIR);

console.log('GITHUB_REF:  %s', process.env.GITHUB_REF);
console.log('TRAVIS_TAG:  %s', process.env.TRAVIS_TAG);
console.log('GITSHA    :  %s', process.env.GITSHA);

let versionTag = process.env.GITHUB_REF || process.env.TRAVIS_TAG || '';

if (versionTag.startsWith('refs/tags/')) {
  versionTag = versionTag.slice(10);
}

if (versionTag && !RegExp(/^v?\d+\.\d+\.\d+$/).test(versionTag)) {
  console.warn('Version [ %s ] is not in valid semver form.', versionTag);
  versionTag = '';
}

if (!versionTag) {
  console.log(
    'Neither GITHUB_REF nor TRAVIS_TAG contained a valid semver version.  Presuming non-publishing version.\nAdding Dev_ and using Date Format YYYYMMDD_HHMMSS as tag.',
  );
}

const sha = process.env.GITSHA ? `_${process.env.GITSHA.slice(0, 7)}` : '';

const TAG =
  (versionTag ||
    'Dev_' +
      new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60000)
        .toISOString()
        .replace(/T/, '_')
        .replace(/-|:|\..+/g, '')) +
  sha +
  '_';

console.log('TAG to append:  %s\n', TAG);

const CHROMEFILENAME = EXTNAME + TAG + 'Chrome';
const FIREFOXFILENAME = EXTNAME + TAG + 'Firefox';

function archiverZip(cb, filename) {
  if (typeof cb !== 'function') {
    console.error('callback is not a function!');
    return null;
  }
  const fileStream = fs.createWriteStream(
    path.join(BUILDDIR, filename + '.zip'),
  );

  const archive = archiver('zip', {
    zlib: { level: 9 }, // Sets the Compression Level.
  });

  // Listen for all archive data to be written
  // 'close' eent is fired only when a file descriptor is involved
  function fileOnClose() {
    console.log(archive.pointer() + ' total bytes');
    console.log(
      'archiver has been finalized and the output file descriptor has closed.',
    );
    cb(0);
  }

  // This event is fired when data source is drained no matter what was the data source.
  // Not part of archiver but from NodeJS Stream API.
  function fileOnEnd() {
    console.log('Data has been drained');
  }

  console.log('Creating an archive in: %s', fileStream.path);

  fileStream.on('close', fileOnClose);
  fileStream.on('end', fileOnEnd);

  // Good Practice to catch warnings (ie stat failures and other non-blocking errors)
  archive.on('warning', function (err) {
    if (err.code === 'ENOENT') {
      console.warn(
        'ARCHIVER WARNING %s: %s (%s)',
        err.code,
        err.message,
        err.data,
      );
    } else {
      throw err;
    }
  });

  // Good Practice to catch his error explicitly
  archive.on('error', function (err) {
    throw err;
  });

  // Pipe archive data to the file
  archive.pipe(fileStream);

  // Append files from Extension Folder.
  archive.directory(EXTDIR, false);

  archive.finalize();
}

function firefoxBuild(cb) {
  if (typeof cb !== 'function') {
    console.error('callback is not a function!');
    return null;
  }
  console.log('\nBuilding unsigned extension for Mozilla Firefox...');

  archiverZip(function (r) {
    if (r === 0) {
      // Copy ZIP to XPI
      console.log('Copying .ZIP to .XPI...');
      fs.copyFileSync(
        path.join(BUILDDIR, FIREFOXFILENAME + '.zip'),
        path.join(BUILDDIR, FIREFOXFILENAME + '.xpi'),
      );
      console.log('>> Copy Success!');
      // End of Mozilla Firefox build.
      console.log('Mozilla Firefox Build Complete!');
    } else {
      console.warn(
        'Archiver was not successful as it returned [%s]. Stopping the rest of the process.',
        r,
      );
    }
    cb(r);
  }, FIREFOXFILENAME);
}

function chromeBuild(cb) {
  if (typeof cb !== 'function') {
    console.error('callback is not a function!');
    return null;
  }
  // Copy manifest into memory to preserve it.
  console.log('\nGetting a copy of %s to memory...', MANIFEST);
  const mforig = fs.readFileSync(path.join(EXTDIR, MANIFEST));
  console.log('>> Done!');
  console.log('Prepping %s for Google Chrome...', MANIFEST);

  function delMFPerm(mf, perm) {
    let i = mf.permissions.indexOf(perm);
    console.log(
      '> Removing Perm: %s ... %s',
      perm,
      i === -1
        ? 'Not Found!'
        : mf.permissions.splice(i, 1).length === 1
        ? 'Done!'
        : 'An Easter Egg Error!',
    );
  }

  const mf = require(path.join(EXTDIR, MANIFEST));
  delMFPerm(mf, 'contextualIdentities');
  console.log(
    '> Removing [applications] section ... %s',
    delete mf.applications ? 'Done!' : 'Failed',
  );

  console.log('Overwriting %s for Google Chrome ...', MANIFEST);
  fs.writeFileSync(path.join(EXTDIR, MANIFEST), JSON.stringify(mf, null, 2));
  console.log('>> Done!');

  console.log('\nBuilding unsigned extension for Google Chrome...');

  archiverZip(function (r) {
    if (r === 0) {
      // continue
      // Revert modifications
      fs.writeFileSync(path.join(EXTDIR, MANIFEST), mforig);
      console.log('%s has been reverted back to original contents!', MANIFEST);

      // End of Google Chrome build.
      console.log('Google Chrome Build Complete!');
    } else {
      console.warn(
        'Archiver was not successful as it returned [%s]. Stopping the rest of the process.',
        r,
      );
    }
    cb(r);
  }, CHROMEFILENAME);
}

function mainBuild() {
  firefoxBuild((r) => {
    if (r === 0) {
      // Do Chrome Build
      chromeBuild((r) => {
        if (r === 0) {
          // EdgeChromium Build, for future.
          console.log('\n\n> All Done! <\n');
        } else {
          console.error(
            'Google Chrome Build did not complete successfully.  Stopping the rest of the Build.',
          );
          process.exitCode = 4;
        }
      });
    } else {
      console.error(
        'Firefox Build did not complete successfully.  Stopping the rest of the progress',
      );
      process.exitCode = 3;
    }
  });
}

function preCheck(cb) {
  if (typeof cb !== 'function') {
    console.error('callback is not a function!');
    return null;
  }
  console.log('Creating %s if it does not exists...', BUILDDIR);
  fs.mkdirSync(BUILDDIR, { recursive: true });

  console.log('Checking if %s folder exists...', EXTDIR);
  const extRes = fs.statSync(EXTDIR);
  if (!extRes) {
    console.error(
      '%s does NOT exist - Cannot build WebExtension.  Terminating.',
      EXTDIR,
    );
    cb(1);
  } else if (!extRes.isDirectory()) {
    console.error(
      '%s is found but is NOT a directory.  Cannot build WebExtension.  Terminating.',
      EXTDIR,
    );
    cb(2);
  } else {
    console.log('Yup.  Directory %s Exists!', EXTDIR);
    cb(0);
  }
}

// Start Point!
preCheck((r) => {
  if (r === 0) {
    mainBuild();
  } else {
    console.warn('PreCheck Failed! Terminating!');
    process.exitCode = r;
  }
});
<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')
var gulp = require('gulp')
var concat = require('gulp-concat')
var slash = require('gulp-slash')
var uglify = require('gulp-uglify')

var htmlPath = __dirname+'/../views/layouts/editor.handlebars'
var htmlOutPath = __dirname+'/../views/layouts/editor-prod.handlebars'
var scriptName = 'editor-' + Date.now() + '.min.js'

function errorHandler(err) {
	console.error(err.message, err.lineNumber, err.stack)
	this.emit('end')
}

function bundleEditorScripts() {
	if (process.env.NODE_ENV !== 'production') {
		console.log('Not bundling editor (process.env.NODE_ENV is not `production`)')
		return;
	}

	console.log('Building editor bundle')
	// read input html
	var html = fs.readFileSync(htmlPath, { encoding: 'utf8' })

	// parse scripts to concatenate
	var re = /\s?<script type="text\/javascript" src="(.*)"><\/script>$/gim
	var scripts = html.match(re)
	scripts = scripts.map(function(script) {
		return path.resolve(__dirname, '..') + (/src="(.*)"/.exec(script)[1])
			.replace('/scripts/', '/browser/scripts/')
			.replace('/vendor/', '/browser/vendor/')
	})

	scripts.push(path.resolve(__dirname, '..') + '/browser/plugins/all.plugins.js')

	// concat scripts with gulp
	gulp.src(scripts)
	.pipe(slash())
	.pipe(uglify().on('error', errorHandler))
	.pipe(concat(scriptName))
	.pipe(gulp.dest(path.join(__dirname, '..', 'browser', 'scripts')))
	.on('error', errorHandler)

	// remove all scripts
	html = html.replace(
		/<script type="text\/javascript".*<\/script>/gim, '')

	// remove extra white space
	html = html.replace(/\s+/gim, ' ')

	// replace magic with the editor bundle
	html = html.replace('<!-- {{editor.min.js}} -->',
		'<script type="text/javascript" src="/scripts/'+scriptName+'"></script>')

	// write output
	fs.writeFileSync(htmlOutPath, html)
}

exports.bundleEditorScripts = bundleEditorScripts

if (require.main === module) {
	bundleEditorScripts()
}
<commit_msg>debugging<commit_after>var fs = require('fs')
var path = require('path')
var gulp = require('gulp')
var concat = require('gulp-concat')
var slash = require('gulp-slash')
var uglify = require('gulp-uglify')

var htmlPath = __dirname+'/../views/layouts/editor.handlebars'
var htmlOutPath = __dirname+'/../views/layouts/editor-prod.handlebars'
var scriptName = 'editor-' + Date.now() + '.min.js'

function errorHandler(err) {
	console.error(err.message, err.lineNumber, err.stack)
	this.emit('end')
}

function bundleEditorScripts() {
	if (process.env.NODE_ENV !== 'production') {
		console.log('Not bundling editor (process.env.NODE_ENV is not `production`)')
		return;
	}

	console.log('Building editor bundle', scriptName)
	// read input html
	var html = fs.readFileSync(htmlPath, { encoding: 'utf8' })

	// parse scripts to concatenate
	var re = /\s?<script type="text\/javascript" src="(.*)"><\/script>$/gim
	var scripts = html.match(re)
	scripts = scripts.map(function(script) {
		return path.resolve(__dirname, '..') + (/src="(.*)"/.exec(script)[1])
			.replace('/scripts/', '/browser/scripts/')
			.replace('/vendor/', '/browser/vendor/')
	})

	scripts.push(path.resolve(__dirname, '..') + '/browser/plugins/all.plugins.js')

	// concat scripts with gulp
	gulp.src(scripts)
	.pipe(slash())
	.pipe(uglify().on('error', errorHandler))
	.pipe(concat(scriptName))
	.pipe(gulp.dest(path.join(__dirname, '..', 'browser', 'scripts')))
	.on('error', errorHandler)

	// remove all scripts
	html = html.replace(
		/<script type="text\/javascript".*<\/script>/gim, '')

	// remove extra white space
	html = html.replace(/\s+/gim, ' ')

	// replace magic with the editor bundle
	html = html.replace('<!-- {{editor.min.js}} -->',
		'<script type="text/javascript" src="/scripts/'+scriptName+'"></script>')

	// write output
	fs.writeFileSync(htmlOutPath, html)
}

exports.bundleEditorScripts = bundleEditorScripts

if (require.main === module) {
	bundleEditorScripts()
}
<|endoftext|>


<commit_before>// Dependencies:
// jQuery
var ire_census = {};
(function() {
    this.API_URL = "http://censusdata.ire.org"
    this.GEOAPI_URL = "http://census.ire.org/geo/1.0"

    function apiRequest(path, callback, handler) {
        $.ajax(this.API_URL + path, {
            dataType: "jsonp",
            jsonpCallback: callback,
            success: handler
        });
    }

    this.table_comparator = function (table) {
        parts = table.match(/([A-Z]+)(\d+)([A-Z]+)?/);

        key = parts[1];
        num = parts[2];

        if (key[0] == 'P') {
            key = "A" + key; // sort P tables first as Census does
        }
        while (num.length < 3) {
            num = '0' + num;
        }

        key += num;

        if (parts[3]) {
            key += parts[3];
        }

        return key;
    }

    this.table_from_field = function(field_code) {
        parts = field_code.match(/^(H|P|HCT|PCT|PCO)(\d{3})(\D)?(\d{3})$/i);
        if (!parts) throw "Invalid field code."
        while (parts[2][0] == '0') parts[2] = parts[2].substr(1);
        return parts.slice(1,4).join('').toUpperCase();
    }

    this.build_bulk_data_url = function(state,sumlev,table,format) {
        if (!format) {
            format = 'csv';
        }
        if (table) {
            table = "." + table;
        } else {
            table = "";
        }
        return this.API_URL + "/" + state + "/all_" + sumlev + "_in_"+state+table+"." + format;
    }

    this.build_shapefile_url = function(state,sumlev) {
        for (var i = 0; i < SUMLEVS.length; i++) {
            if (SUMLEVS[i][0] == sumlev) {
                url_parts = [SUMLEVS[i][2][0],state,SUMLEVS[i][2][1]]
                return url_parts.join('');
            }
        }
        throw "Invalid summary level";
    }

    this.do_with_available_states = function(handler) {
        apiRequest("/states.jsonp", "states", handler);
    }

    this.do_with_labels = function(handler,options) {
        opts = { 'dataset': 'SF1'} // at this time there are no plans to include other datasets in the IRE app, so this may go away.
        $.extend(opts,options);
        apiRequest("/" + opts.dataset + "_labels.jsonp", "labels_" + opts.dataset, handler);
    }

    this.do_with_sf1_data = function(geoid, handler) {
        var state = geoid.substring(0, 2);
        apiRequest("/" + state + "/" + geoid + ".jsonp", "geoid_" + geoid, handler);
    }

    GEOGRAPHY_TYPES = [
        [/^\d{11}$/,'tracts'],
        [/^\d{10}$/,'county-subdivisions'],
        [/^\d{5}$/,'counties'],
        [/^\d{2}$/,'states'],
        [/^\d{7}$/,'places']
    ];

    // do_with_geodata: for a string representing a single location, fetch the JSON data (including GeoJSON)
    // from GEOAPI_URL and pass it to success_handler.
    // For now, if geoid begins with a slash, it will be treated as a complete type/geoid combo. This
    // leaves it fairly flexible to add more geographies in case sometimes lengths aren't distinctive.
    // But also for now, we can infer the geography type by the length of the geoID, so the value for
    // geoid may also simply be a string of 2-11 digits, or technically any pattern defined in GEOGRAPHY_TYPES.
    //
    // See http://census.ire.org/docs/boundary.html for more on the API, or to see what data
    // gets returned, look at http://census.ire.org/geo/1.0/boundary-set/places/1714000
    // TK: examples demonstrating how to put the shape which is returned on a map.
    this.do_with_geodata = function (geoid,success_handler) {
        if (geoid[0] != '/') {
            var matched = false;
            for (var i=0; i < GEOGRAPHY_TYPES.length; i++) {
                if (geoid.match(GEOGRAPHY_TYPES[i][0])) {
                    geoid = "/" + GEOGRAPHY_TYPES[i][1] + "/" + geoid;
                    matched = true;
                    break;
                }
            }
            if (!matched) {
                throw "Geoid does not match any known types. Check the length."
            }
        }
        if (geoid.substr(0,'/boundary-set'.length) != '/boundary-set') {
            geoid = '/boundary-set' + geoid;
        }
        $.ajax(this.GEOAPI_URL + geoid, {
            dataType: "jsonp",
            success: success_handler
        });
    }

    // given a point as [lat,lng] or as "lat,lng", call the contains function at GEOAPI_URL and pass the results
    // to success_handler. not rigged to handle paginated results, but for foreseeable future,
    // the contains query won't return enough for that to matter.
    this.do_with_contains_results = function(point,success_handler,options) {
        if ($.isArray(point)) {
            point = point.join(',');
        }
        var url = '/boundary/?contains=' + point;
        if (options && options.sets) {
            if ($.isArray(options.sets)) {
                url += "&sets=" + options.sets.join(',');
            } else {
                url += "&sets=" + options.sets;
            }
        }
        // 38.948337,-92.328032&sets=tracts,counties
        $.ajax(this.GEOAPI_URL + url, {
            dataType: "jsonp",
            success: success_handler
        });

    };

    // Given a JSON object of the typical structure returned from the do_with_sf1_data AJAX call,
    // return a simple field value. Just makes some things a little more concise.
    this.sf1val = function(sf1_json,field,year_or_cat) {
        var year_or_cat = year_or_cat || '2010';
        var table = this.table_from_field(field);
        return sf1_json.data[year_or_cat][table][field];
    }

    // Given a JSON object of the typical structure returned from the do_with_sf1_data AJAX call,
    // return a field value as a percentage of total population or housing units (as appropriate for the field)
    // if this is to "work" for 'delta' or 'pct_change' special handling should be added. For now it's naive and
    // thus probably wrong...
    this.sf1val_pct = function(sf1_json,field,year_or_cat) {
        var year_or_cat = year_or_cat || '2010';
        var val = parseFloat(this.sf1val(sf1_json,field,year_or_cat))
        var denom_field = (field.toUpperCase()[0] == 'H') ? "H001001" : "P001001";
        var denom_val = parseFloat(this.sf1val(sf1_json,denom_field,year_or_cat));
        return val / denom_val * 100;
    }

    this.table_name = function(label_data, table_code) {
        return label_data['tables'][table_code]['name'];
    }

    this.table_universe = function(label_data, table_code) {
        return label_data['tables'][table_code]['universe'];
    }

    this.table_size = function(label_data, table_code) {
        return label_data['tables'][table_code]['size'];
    }

    this.label_text = function(label_data, field_code) {
        var table_code = this.table_from_field(field_code);
        return label_data['tables'][table_code]['labels'][field_code]['text']
    }

    this.STATE_FIPS = {
        "Alabama": "01",
        "Alaska": "02",
        "Arizona": "04",
        "Arkansas": "05",
        "California": "06",
        "Colorado": "08",
        "Connecticut": "09",
        "Delaware": "10",
        "District of Columbia": "11",
        "Florida": "12",
        "Georgia": "13",
        "Hawaii": "15",
        "Idaho": "16",
        "Illinois": "17",
        "Indiana": "18",
        "Iowa": "19",
        "Kansas": "20",
        "Kentucky": "21",
        "Louisiana": "22",
        "Maine": "23",
        "Maryland": "24",
        "Massachusetts": "25",
        "Michigan": "26",
        "Minnesota": "27",
        "Mississippi": "28",
        "Missouri": "29",
        "Montana": "30",
        "Nebraska": "31",
        "Nevada": "32",
        "New Hampshire": "33",
        "New Jersey": "34",
        "New Mexico": "35",
        "New York": "36",
        "North Carolina": "37",
        "North Dakota": "38",
        "Ohio": "39",
        "Oklahoma": "40",
        "Oregon": "41",
        "Pennsylvania": "42",
        "Puerto Rico": "72",
        "Rhode Island": "44",
        "South Carolina": "45",
        "South Dakota": "46",
        "Tennessee": "47",
        "Texas": "48",
        "Utah": "49",
        "Vermont": "50",
        "Virginia": "51",
        "Washington": "53",
        "West Virginia": "54",
        "Wisconsin": "55",
        "Wyoming": "56"
    }

    this.get_state_fips = function(state) {
        return this.STATE_FIPS[state];
    }

    this.FIPS_STATE = {}

    for (name in this.STATE_FIPS) {
        var fips = this.get_state_fips(name);
        this.FIPS_STATE[fips] = name;
    }

    this.get_fips_state = function(fips) {
        return this.FIPS_STATE[fips];
    }

    SUMLEVS = [
        // tuples: (code, name, shapefile_template)
        ['040','State', ["http://www2.census.gov/geo/tiger/TIGER2010/STATE/2010/tl_2010_","_state10.zip"]],
        ['050','County', ["http://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_","_county10.zip"]],
        ['060','County Subdivision', ["http://www2.census.gov/geo/tiger/TIGER2010/COUSUB/2010/tl_2010_","_cousub10.zip"]],
        ['140','Census Tract', ["http://www2.census.gov/geo/tiger/TIGER2010/TRACT/2010/tl_2010_","_tract10.zip"]],
        ['160','Place', ["http://www2.census.gov/geo/tiger/TIGER2010/PLACE/2010/tl_2010_","_place10.zip"]]
    ]
}).apply(ire_census);
<commit_msg>js scoping again<commit_after>// Dependencies:
// jQuery
var ire_census = {};
(function() {
    this.API_URL = "http://censusdata.ire.org"
    this.GEOAPI_URL = "http://census.ire.org/geo/1.0"

    function apiRequest(path, callback, handler) {
        var api_url = this.API_URL;
        console.log("apiRequest: " + api_url);
        $.ajax(api_url + path, {
            dataType: "jsonp",
            jsonpCallback: callback,
            success: handler
        });
    }

    this.table_comparator = function (table) {
        parts = table.match(/([A-Z]+)(\d+)([A-Z]+)?/);

        key = parts[1];
        num = parts[2];

        if (key[0] == 'P') {
            key = "A" + key; // sort P tables first as Census does
        }
        while (num.length < 3) {
            num = '0' + num;
        }

        key += num;

        if (parts[3]) {
            key += parts[3];
        }

        return key;
    }

    this.table_from_field = function(field_code) {
        parts = field_code.match(/^(H|P|HCT|PCT|PCO)(\d{3})(\D)?(\d{3})$/i);
        if (!parts) throw "Invalid field code."
        while (parts[2][0] == '0') parts[2] = parts[2].substr(1);
        return parts.slice(1,4).join('').toUpperCase();
    }

    this.build_bulk_data_url = function(state,sumlev,table,format) {
        if (!format) {
            format = 'csv';
        }
        if (table) {
            table = "." + table;
        } else {
            table = "";
        }
        return this.API_URL + "/" + state + "/all_" + sumlev + "_in_"+state+table+"." + format;
    }

    this.build_shapefile_url = function(state,sumlev) {
        for (var i = 0; i < SUMLEVS.length; i++) {
            if (SUMLEVS[i][0] == sumlev) {
                url_parts = [SUMLEVS[i][2][0],state,SUMLEVS[i][2][1]]
                return url_parts.join('');
            }
        }
        throw "Invalid summary level";
    }

    this.do_with_available_states = function(handler) {
        apiRequest("/states.jsonp", "states", handler);
    }

    this.do_with_labels = function(handler,options) {
        opts = { 'dataset': 'SF1'} // at this time there are no plans to include other datasets in the IRE app, so this may go away.
        $.extend(opts,options);
        apiRequest("/" + opts.dataset + "_labels.jsonp", "labels_" + opts.dataset, handler);
    }

    this.do_with_sf1_data = function(geoid, handler) {
        var state = geoid.substring(0, 2);
        apiRequest("/" + state + "/" + geoid + ".jsonp", "geoid_" + geoid, handler);
    }

    GEOGRAPHY_TYPES = [
        [/^\d{11}$/,'tracts'],
        [/^\d{10}$/,'county-subdivisions'],
        [/^\d{5}$/,'counties'],
        [/^\d{2}$/,'states'],
        [/^\d{7}$/,'places']
    ];

    // do_with_geodata: for a string representing a single location, fetch the JSON data (including GeoJSON)
    // from GEOAPI_URL and pass it to success_handler.
    // For now, if geoid begins with a slash, it will be treated as a complete type/geoid combo. This
    // leaves it fairly flexible to add more geographies in case sometimes lengths aren't distinctive.
    // But also for now, we can infer the geography type by the length of the geoID, so the value for
    // geoid may also simply be a string of 2-11 digits, or technically any pattern defined in GEOGRAPHY_TYPES.
    //
    // See http://census.ire.org/docs/boundary.html for more on the API, or to see what data
    // gets returned, look at http://census.ire.org/geo/1.0/boundary-set/places/1714000
    // TK: examples demonstrating how to put the shape which is returned on a map.
    this.do_with_geodata = function (geoid,success_handler) {
        if (geoid[0] != '/') {
            var matched = false;
            for (var i=0; i < GEOGRAPHY_TYPES.length; i++) {
                if (geoid.match(GEOGRAPHY_TYPES[i][0])) {
                    geoid = "/" + GEOGRAPHY_TYPES[i][1] + "/" + geoid;
                    matched = true;
                    break;
                }
            }
            if (!matched) {
                throw "Geoid does not match any known types. Check the length."
            }
        }
        if (geoid.substr(0,'/boundary-set'.length) != '/boundary-set') {
            geoid = '/boundary-set' + geoid;
        }
        $.ajax(this.GEOAPI_URL + geoid, {
            dataType: "jsonp",
            success: success_handler
        });
    }

    // given a point as [lat,lng] or as "lat,lng", call the contains function at GEOAPI_URL and pass the results
    // to success_handler. not rigged to handle paginated results, but for foreseeable future,
    // the contains query won't return enough for that to matter.
    this.do_with_contains_results = function(point,success_handler,options) {
        if ($.isArray(point)) {
            point = point.join(',');
        }
        var url = '/boundary/?contains=' + point;
        if (options && options.sets) {
            if ($.isArray(options.sets)) {
                url += "&sets=" + options.sets.join(',');
            } else {
                url += "&sets=" + options.sets;
            }
        }
        // 38.948337,-92.328032&sets=tracts,counties
        $.ajax(this.GEOAPI_URL + url, {
            dataType: "jsonp",
            success: success_handler
        });

    };

    // Given a JSON object of the typical structure returned from the do_with_sf1_data AJAX call,
    // return a simple field value. Just makes some things a little more concise.
    this.sf1val = function(sf1_json,field,year_or_cat) {
        var year_or_cat = year_or_cat || '2010';
        var table = this.table_from_field(field);
        return sf1_json.data[year_or_cat][table][field];
    }

    // Given a JSON object of the typical structure returned from the do_with_sf1_data AJAX call,
    // return a field value as a percentage of total population or housing units (as appropriate for the field)
    // if this is to "work" for 'delta' or 'pct_change' special handling should be added. For now it's naive and
    // thus probably wrong...
    this.sf1val_pct = function(sf1_json,field,year_or_cat) {
        var year_or_cat = year_or_cat || '2010';
        var val = parseFloat(this.sf1val(sf1_json,field,year_or_cat))
        var denom_field = (field.toUpperCase()[0] == 'H') ? "H001001" : "P001001";
        var denom_val = parseFloat(this.sf1val(sf1_json,denom_field,year_or_cat));
        return val / denom_val * 100;
    }

    this.table_name = function(label_data, table_code) {
        return label_data['tables'][table_code]['name'];
    }

    this.table_universe = function(label_data, table_code) {
        return label_data['tables'][table_code]['universe'];
    }

    this.table_size = function(label_data, table_code) {
        return label_data['tables'][table_code]['size'];
    }

    this.label_text = function(label_data, field_code) {
        var table_code = this.table_from_field(field_code);
        return label_data['tables'][table_code]['labels'][field_code]['text']
    }

    this.STATE_FIPS = {
        "Alabama": "01",
        "Alaska": "02",
        "Arizona": "04",
        "Arkansas": "05",
        "California": "06",
        "Colorado": "08",
        "Connecticut": "09",
        "Delaware": "10",
        "District of Columbia": "11",
        "Florida": "12",
        "Georgia": "13",
        "Hawaii": "15",
        "Idaho": "16",
        "Illinois": "17",
        "Indiana": "18",
        "Iowa": "19",
        "Kansas": "20",
        "Kentucky": "21",
        "Louisiana": "22",
        "Maine": "23",
        "Maryland": "24",
        "Massachusetts": "25",
        "Michigan": "26",
        "Minnesota": "27",
        "Mississippi": "28",
        "Missouri": "29",
        "Montana": "30",
        "Nebraska": "31",
        "Nevada": "32",
        "New Hampshire": "33",
        "New Jersey": "34",
        "New Mexico": "35",
        "New York": "36",
        "North Carolina": "37",
        "North Dakota": "38",
        "Ohio": "39",
        "Oklahoma": "40",
        "Oregon": "41",
        "Pennsylvania": "42",
        "Puerto Rico": "72",
        "Rhode Island": "44",
        "South Carolina": "45",
        "South Dakota": "46",
        "Tennessee": "47",
        "Texas": "48",
        "Utah": "49",
        "Vermont": "50",
        "Virginia": "51",
        "Washington": "53",
        "West Virginia": "54",
        "Wisconsin": "55",
        "Wyoming": "56"
    }

    this.get_state_fips = function(state) {
        return this.STATE_FIPS[state];
    }

    this.FIPS_STATE = {}

    for (name in this.STATE_FIPS) {
        var fips = this.get_state_fips(name);
        this.FIPS_STATE[fips] = name;
    }

    this.get_fips_state = function(fips) {
        return this.FIPS_STATE[fips];
    }

    SUMLEVS = [
        // tuples: (code, name, shapefile_template)
        ['040','State', ["http://www2.census.gov/geo/tiger/TIGER2010/STATE/2010/tl_2010_","_state10.zip"]],
        ['050','County', ["http://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_","_county10.zip"]],
        ['060','County Subdivision', ["http://www2.census.gov/geo/tiger/TIGER2010/COUSUB/2010/tl_2010_","_cousub10.zip"]],
        ['140','Census Tract', ["http://www2.census.gov/geo/tiger/TIGER2010/TRACT/2010/tl_2010_","_tract10.zip"]],
        ['160','Place', ["http://www2.census.gov/geo/tiger/TIGER2010/PLACE/2010/tl_2010_","_place10.zip"]]
    ]
}).apply(ire_census);
<|endoftext|>


<commit_before>(function($){

  if (typeof _ == 'undefined')
    babel.Translations.load({}).install();

  $.fn.addAnchor = function(title) {
    title = title || _("Link here");
    return this.filter("*[id]").each(function() {
      $(" \u00B6").attr("href", "#" + this.id)
        .attr("title", title).appendTo(this);
    });
  }

  $.fn.checked = function(checked) {
    if (checked == undefined) { // getter
      if (!this.length) return false;
      return this.get(0).checked;
    } else { // setter
      return this.each(function() {
        this.checked = checked;
      });
    }
  }

  // Add a Select All checkbox to each thead in the table.
  $.fn.addSelectAllCheckboxes = function() {
    var $table = this;
    if ($("tr td.sel", $table).length > 0) {
      $("tr th.sel", $table).append(
        $('<input type="checkbox" name="toggle_group" />').attr({
          title: _("Toggle group")
        }).click(function() {
          $("tr td.sel input",
            $(this).closest("thead, tbody").next())
              .prop("checked", this.checked).change();
        })
      );
      $("tr td.sel", $table).click(function() {
        var $tbody = $(this).closest("tbody");
        var $checkboxes = $("tr td.sel input", $tbody);
        var num_selected = $checkboxes.filter(":checked").length;
        var none_selected = num_selected === 0;
        var all_selected = num_selected === $checkboxes.length;
        $("tr th.sel input", $tbody.prev())
          .prop({"checked": all_selected,
                 "indeterminate": !(none_selected || all_selected)});
      });
    }
  }

  // Conditionally disable the submit button. Returns a jQuery object.
  $.fn.disableSubmit = function(determinant) {
    determinant = $(determinant);
    var subject = $(this);
    var isDisabled;
    if (determinant.is("input:checkbox")) {
      isDisabled = function () {
          return determinant.filter(":checked").length === 0;
      }
    } else if (determinant.is("input:file")) {
      isDisabled = function () {
          return !determinant.val();
      }
    } else {
      return subject;
    }
    function toggleDisabled() {
      subject.prop("disabled", isDisabled);
      if (subject.prop("disabled")) {
        subject.attr("title", _("At least one item must be selected"))
      } else {
        subject.removeAttr("title");
      }
    }
    determinant.change(toggleDisabled);
    toggleDisabled();
    return subject;
  }

  $.fn.enable = function(enabled) {
    if (enabled == undefined) enabled = true;
    return this.each(function() {
      this.disabled = !enabled;
      var label = $(this).parents("label");
      if (!label.length && this.id) {
        label = $("label[for='" + this.id + "']");
      }
      if (!enabled) {
        label.addClass("disabled");
      } else {
        label.removeClass("disabled");
      }
    });
  }

  $.fn.getAbsolutePos = function() {
    return this.map(function() {
      var left = this.offsetLeft;
      var top = this.offsetTop;
      var parent = this.offsetParent;
      while (parent) {
        left += parent.offsetLeft;
        top += parent.offsetTop;
        parent = parent.offsetParent;
      }
      return {left: left, top: top};
    });
  }

  $.fn.scrollToTop = function() {
    return this.each(function() {
      scrollTo(0, $(this).getAbsolutePos()[0].top);
      return false;
    });
  }

  // Disable the form's submit action after the submit button is pressed by
  // replacing it with a handler that cancels the action. The handler is
  // removed when navigating away from the page so that the action will
  // be enabled when using the back button to return to the page.
  $.fn.disableOnSubmit = function() {
    this.click(function() {
      var form = $(this).closest("form");
      if (form.hasClass("trac-submit-is-disabled")) {
        form.bind("submit.prevent-submit", function() {
          return false;
        });
        $(window).on("unload", function() {
          form.unbind("submit.prevent-submit");
        });
      } else {
        form.addClass("trac-submit-is-disabled");
        $(window).on("unload", function() {
          form.removeClass("trac-submit-is-disabled");
        })
      }
    });
  }

  $.loadStyleSheet = function(href, type) {
    type = type || "text/css";
    $(document).ready(function() {
      var link;
      $("link[rel=stylesheet]").each(function() {
        if (this.getAttribute("href") === href) {
          if (this.disabled)
            this.disabled = false;
          link = this;
          return false;
        }
      });
      if (link !== undefined)
        return;
      if (document.createStyleSheet) { // MSIE
        document.createStyleSheet(href);
      } else {
        $("<link rel='stylesheet' type='" + type + "' href='" + href + "' />")
          .appendTo("head");
      }
    });
  };

  // {script.src: [listener1, listener2, ...]}
  var readyListeners = {};

  $.documentReady = function(listener) {
    var script = document.currentScript;
    if (script === undefined) {
      script = $("head script");
      script = script[script.length - 1];
    }
    if (script) {
      var href = script.getAttribute("src");
      if (!(href in readyListeners))
        readyListeners[href] = [];
      var listeners = readyListeners[href];
      listeners.push(listener);
    }
    $(document).ready(listener);
  };

  $.loadScript = function(href, type, charset) {
    var script;
    $("head script").each(function() {
      if (this.getAttribute("src") === href) {
        script = this;
        return false;
      }
    });
    if (script !== undefined) {
      // Call registered ready listeners
      $.each(readyListeners[href] || [], function(idx, listener) {
        listener.call(document, $);
      });
    } else {
      // Don't use $("


<commit_before>var _ = require('lodash');

module.exports = transform;

function transform(req, res, next) {
    var fields = null;

    if (req.query.distinct) {
        fields = req.query.distinct.split(',');
        res.transform = distinct;
    }

    next();

    function distinct(data) {
        return _(data)
            .map(_.partialRight(_.pick, fields))
            .uniqWith(_.isEqual)
            .value();
    }
}<commit_msg>Restricted the distinct transform to a single field due to performance issues.<commit_after>var _ = require('lodash');

module.exports = transform;

function transform(req, res, next) {
    var field = req.query.distinct;

    if (field) {
        res.transform = distinct;
    }

    next();

    function distinct(data) {
        return _(data)
            .map(field)
            .uniqWith(_.isEqual)
            .value();
    }
}<|endoftext|>