<commit_before>import Ember from 'ember';

const {
  A,
  Service,
  Evented,
  RSVP
} = Ember;

const { Promise } = RSVP;

// from https://cordova.apache.org/docs/en/4.0.0/cordova_events_events.md.html
const CORDOVA_EVENTS = new A([
  'deviceready',
  'pause',
  'resume',
  'backbutton',
  'menubutton',
  'searchbutton',
  'startcallbutton',
  'endcallbutton',
  'volumedownbutton',
  'volumeupbutton',
  'batterycritical',
  'batterylow',
  'batterystatus',
  'online',
  'offline'
]);

export default Service.extend(Evented, {
  _listeners: null,
  _ready: null,
  _readyHasTriggered: false,

  init() {
    this._super();

    this._listeners = [];
    this._ready = RSVP.defer();

    this.setupListeners();
    this.setupReady();
  },

  willDestroy() {
    this._super();
    this.teardownListeners();

    if (this._ready) {
      this._ready.reject();
      this._ready = null;
    }
  },

  ready() {
    return this._readyHasTriggered ? Promise.resolve() : this._ready.promise;
  },

  setupListeners() {
    CORDOVA_EVENTS.forEach(name => {
      const listener = {
        name,
        method: e => { this.trigger(name, e); }
      };

      this._listeners.push(listener);
      document.addEventListener(listener.name, listener.method, true);
    });
  },

  setupReady() {
    document.addEventListener('deviceready', () => {
      this._readyHasTriggered = true;
      this._ready.resolve();
      this._ready = null;
    });
  },

  teardownListeners() {
    this._listeners.forEach(listener => {
      document.removeEventListener(listener.name, listener.method, true);
    });
    document.removeEventListener('deviceready');
  }
});
<commit_msg>Revert "attach deviceready to document"<commit_after>import Ember from 'ember';

const {
  A,
  Service,
  Evented,
  RSVP
} = Ember;

const { Promise } = RSVP;

// from https://cordova.apache.org/docs/en/4.0.0/cordova_events_events.md.html
const CORDOVA_EVENTS = new A([
  'deviceready',
  'pause',
  'resume',
  'backbutton',
  'menubutton',
  'searchbutton',
  'startcallbutton',
  'endcallbutton',
  'volumedownbutton',
  'volumeupbutton',
  'batterycritical',
  'batterylow',
  'batterystatus',
  'online',
  'offline'
]);

export default Service.extend(Evented, {
  _listeners: null,
  _ready: null,
  _readyHasTriggered: false,

  init() {
    this._super();

    this._listeners = [];
    this._ready = RSVP.defer();

    this.setupListeners();
    this.setupReady();
  },

  willDestroy() {
    this._super();
    this.teardownListeners();

    if (this._ready) {
      this._ready.reject();
      this._ready = null;
    }
  },

  ready() {
    return this._readyHasTriggered ? Promise.resolve() : this._ready.promise;
  },

  setupListeners() {
    CORDOVA_EVENTS.forEach(name => {
      const listener = {
        name,
        method: e => { this.trigger(name, e); }
      };

      this._listeners.push(listener);
      document.addEventListener(listener.name, listener.method, true);
    });
  },

  setupReady() {
    this.on('deviceready', () => {
      this._readyHasTriggered = true;
      this._ready.resolve();
      this._ready = null;
    });
  },

  teardownListeners() {
    this._listeners.forEach(listener => {
      document.removeEventListener(listener.name, listener.method, true);
    });
  }
});
<|endoftext|>


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

var GIVe = (function (give) {
  'use strict'

  /**
   * Object representing a BED track data object,
   * see `GIVe.TrackDataObject` for details.
   * @typedef {object} BedTrackData
   * @class give.BedTrackData
   *
   * @constructor
   * @param {TrackObjectBase} parent - The track object parent
   */
  class BedTrackData extends give.TrackDataObject {
    /**
     * _dataHandler - This should be the detailed implementation about how to
     *    handle the responses from server
     *
     *    When implementing this method, use `this.getData` to get the `GiveTree`
     *    object storing all necessary data corresponding to the correct
     *    chromosome. Then use `.insert` to insert the new data entries.
     *
     *    See documentation for `TrackDataObject` for references to
     *    `this.getData`, and `GIVe.GiveTree` for references to `.insert`.
     *
     * @memberof TrackDataObjectBase.prototype
     * @param  {object} response - Responses from remote servers.
     *   The object should contain chromosomal region strings as its
     *   property names, and an array of data entries as the property value.
     *   For example:
     *   ```
     *   {
     *     'chr10:1-1000000': [
     *       <response entry>,
     *       ...
     *     ]
     *   }
     *   ```
     *   See `this._chromEntryFromResponse` for details of `<response entry>`.
     * @param  {Array<ChromRegionLiteral>} queryRegions - Query regions,
     *   including potential resolutions
     */
    _dataHandler (res, regions) {
      // this is to handle data within response
      // return data should be already sorted by chrom and start
      let resChromEntryFunc = (geneArray, geneNameMap, resChromEntry) => {
        let newGene = new give.GeneObject(
          new give.TranscriptObject(resChromEntry.geneBed,
            this.parent.refObj,
            resChromEntry.attr
          )
        )
        if (this.parent.typeTrunk.indexOf('gene') > -1) {
          // is some gene oriented type
          // check if it overlaps with existing gene(s)
          // because the gene list is sorted by start,
          //    whenever it doesn't overlap with the current gene
          //    it will become a new gene entry.
          if (!geneNameMap.hasOwnProperty(newGene.name) ||
            !geneNameMap[newGene.name].merge(newGene)
          ) {
            geneArray.push(newGene)
            geneNameMap[newGene.name] = newGene
          }
        } else {
          geneArray.push(newGene)
        }
      }

      for (let chrom in res) {
        let regionsInChrom = regions.filter(region => (region.chr === chrom))
        if (regionsInChrom.length > 0 && res.hasOwnProperty(chrom) &&
          Array.isArray(res[chrom])
        ) {
          let geneNameMap = {}
          let geneArray = []
          res[chrom].forEach(
            entry => resChromEntryFunc(geneArray, geneNameMap, entry)
          )
          // then populate the B+ Tree with geneArray
          this.getData(chrom, true).insert(
            geneArray.sort(give.ChromRegion.compare), regionsInChrom)
        }
      }
    }

    _fileHandler (res, regions) {
      // placeholder to read local file content
      // query is the current window (may involve buffering, can be implemented in prepareCustomQuery)
      // data will be passed via firing a 'response' event with {detail: data}
      // and the response will be handled by this.responseHandler(e, detail)

      // BED file implementation:
      //    brutal force going through the file to find regions that intersect the query region
      //    return the lines filtered
      //    currently using FileReader.readAsText(), may change into better adaptations for bigger files
      //      like in http://matthewmeye.rs/blog/post/html5-line-reader/
      //      or    http://stackoverflow.com/questions/24647563/reading-line-by-line-file-in-javascript-on-client-side

      let result = {}
      let lines = res.split(/\r\n|\r|\n/g)
      lines.forEach(line => {
        let transcript = new give.TranscriptObject(line)
        if (regions.some(region => transcript.overlaps(region))) {
          // needs to push this line to result
          if (!result.hasOwnProperty(transcript.chr)) {
            result[transcript.chr] = []
          }
          result[transcript.chr].push({geneBed: line})
        }
      })
      return this._dataHandler(result, regions)
    }
  }

  give.BedTrackData = BedTrackData

  return give
})(GIVe || {})
<commit_msg>Update bedTrackData.js<commit_after>/**
 * @license
 * Copyright 2017 GIVe Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var GIVe = (function (give) {
  'use strict'

  /**
   * Object representing a BED track data object,
   * see `GIVe.TrackDataObject` for details.
   * @typedef {object} BedTrackData
   * @class give.BedTrackData
   *
   * @constructor
   * @param {TrackObjectBase} parent - The track object parent
   */
  class BedTrackData extends give.TrackDataObject {
    /**
     * _dataHandler - This should be the detailed implementation about how to
     *    handle the responses from server
     *
     *    When implementing this method, use `this.getData` to get the `GiveTree`
     *    object storing all necessary data corresponding to the correct
     *    chromosome. Then use `.insert` to insert the new data entries.
     *
     *    See documentation for `TrackDataObject` for references to
     *    `this.getData`, and `GIVe.GiveTree` for references to `.insert`.
     *
     * @memberof TrackDataObjectBase.prototype
     * @param  {object} response - Responses from remote servers.
     *   The object should contain chromosomal region strings as its
     *   property names, and an array of data entries as the property value.
     *   For example:
     *   ```
     *   {
     *     'chr10:1-1000000': [
     *       <response entry>,
     *       ...
     *     ]
     *   }
     *   ```
     *   See `this._chromEntryFromResponse` for details of `<response entry>`.
     * @param  {Array<ChromRegionLiteral>} queryRegions - Query regions,
     *   including potential resolutions
     */
    _dataHandler (res, regions) {
      // this is to handle data within response
      // return data should be already sorted by chrom and start
      let resChromEntryFunc = (geneArray, geneNameMap, resChromEntry) => {
        let newGene = new give.GeneObject(
          new give.TranscriptObject(resChromEntry.geneBed,
            this.parent.refObj,
            resChromEntry.attr
          )
        )
        if (this.parent.typeTrunk.indexOf('gene') > -1) {
          // is some gene oriented type
          // check if it overlaps with existing gene(s)
          // because the gene list is sorted by start,
          //    whenever it doesn't overlap with the current gene
          //    it will become a new gene entry.
          if (!geneNameMap.has(newGene.name)) {
            geneNameMap.set(newGene.name, [newGene])
          } else {
            // try to see if it is mergable
            let sameNameArray = geneNameMap.get(newGene.name)
            let needToInsert = true
            for (let i = 0; i < sameNameArray.length; i++) {
              if (newGene.merge(sameNameArray[i])) {
                // then replace sameNameArray[i] with newGene
                if (needToInsert) {
                  sameNameArray[i] = newGene
                  needToInsert = false
                } else {
                  sameNameArray.splice(i, 1)
                  i--
                }
              }
            }
            if (needToInsert) {
              sameNameArray.push(newGene)
            }
            sameNameArray.sort(give.ChromRegion.compare)
          }
        } else {
          geneArray.push(newGene)
        }
      }

      for (let chrom in res) {
        let regionsInChrom = regions.filter(region => (region.chr === chrom))
        if (regionsInChrom.length > 0 && res.hasOwnProperty(chrom) &&
          Array.isArray(res[chrom])
        ) {
          let geneNameMap = new Map()
          let geneArray = []
          res[chrom].forEach(
            entry => resChromEntryFunc(geneArray, geneNameMap, entry)
          )
          if (this.parent.typeTrunk.indexOf('gene') > -1) {
            geneArray = [...geneNameMap.values()].reduce(
              (gArray, currArray) => gArray.concat(currArray), [])
          }
          // then populate the B+ Tree with geneArray
          this.getData(chrom, true).insert(
            geneArray.sort(give.ChromRegion.compare), regionsInChrom)
        }
      }
    }

    _fileHandler (res, regions) {
      // placeholder to read local file content
      // query is the current window (may involve buffering, can be implemented in prepareCustomQuery)
      // data will be passed via firing a 'response' event with {detail: data}
      // and the response will be handled by this.responseHandler(e, detail)

      // BED file implementation:
      //    brutal force going through the file to find regions that intersect the query region
      //    return the lines filtered
      //    currently using FileReader.readAsText(), may change into better adaptations for bigger files
      //      like in http://matthewmeye.rs/blog/post/html5-line-reader/
      //      or    http://stackoverflow.com/questions/24647563/reading-line-by-line-file-in-javascript-on-client-side

      let result = {}
      let lines = res.split(/\r\n|\r|\n/g)
      lines.forEach(line => {
        let transcript = new give.TranscriptObject(line)
        if (regions.some(region => transcript.overlaps(region))) {
          // needs to push this line to result
          if (!result.hasOwnProperty(transcript.chr)) {
            result[transcript.chr] = []
          }
          result[transcript.chr].push({geneBed: line})
        }
      })
      return this._dataHandler(result, regions)
    }
  }

  give.BedTrackData = BedTrackData

  return give
})(GIVe || {})
<|endoftext|>


<commit_before>function createSite(url, abbreviation, callback) {
	var site = {};

	site.url = url;

	if (abbreviation) {
		site.abbreviation = abbreviation;
	} else {
		site.abbreviation = getHostname(url);
	}

	site.abbreviation = makeAbbreviation(site.abbreviation);

	setSiteColor(site, function(site, error) {
		callback(site, error);
	});
}

function deleteSite(url, callback) {
	getSites(function(sites) {
		for (var i = 0; i < sites.length; i++) {
			if (sites[i].url == url) {
				sites.splice(i, 1);
				break;
			}
		}

		saveSites(sites, callback);
	})
}

function saveSite(site, callback) {
	getSites(function(sites) {
		if (sites) {
			var found = false;

			for (var i = 0; i < sites.length; i++) {
				if (sites[i].url == site.url) {
					sites[i] = site;

					found = true;
					break;
				}
			}

			if (!found) {
				sites.push(site);
			}
		} else {
			sites = [];
			sites.push(site);
		}

		saveSites(sites, callback);
	});
}

function saveSites(sites, callback) {
	chrome.storage.sync.set({"sites": sites}, callback);
}

function getSites(callback) {
	chrome.storage.sync.get('sites', function(items) {
		sites = items['sites'];

		if (sites == undefined || sites == null) {
			return callback(null);
		} else {
			if (sites.length == 0) {
				return callback(null);
			}
		}

		return callback(sites);
	});
}

function setSiteColor(site, callback) {
	getFaviconColor(site.url, function(color) {
		var error = false;

		if (!color) {
			error = true;

			color = [0, 0, 0, 0];
		}

		site.color = {
			'red': color[0],
			'green': color[1],
			'blue': color[2],
			'alpha': color[3]
		};

		site.lastUpdated = Date.now();

		return callback(site, error);
	});
}

function siteNeedsColorUpdate(site) {
	const TIME_BEFORE_UPDATE = 1000 * 60 * 60;

	var elapsedTime = Date.now() - site.lastUpdated;

	return (!site.lastUpdated || elapsedTime >= TIME_BEFORE_UPDATE);
}

function makeAbbreviation(string) {
	return string.substring(0, 1).toUpperCase() + string.substring(1, 2).toLowerCase();
}

function isWhiteOrTransparent(color) {
	const TOLERANCE = 20;

	if (color[3] != 255)
		return true;

	return 255 - color[0] <= TOLERANCE
		&& 255 - color[1] <= TOLERANCE
		&& 255 - color[2] <= TOLERANCE;
}

function getMajorityColor(imageData, ignoredColor) {
	var majorityCandidate = null;
	var retainCount = 1;
	var age = 1;
	var sumRGB = [0, 0, 0, 0];

	for (var i = 0; i < imageData.data.length; i += 4) {
		var pixel = [imageData.data[i],
		imageData.data[i + 1],
		imageData.data[i + 2],
		imageData.data[i + 3]];

		if (ignoredColor != undefined && pixelsAreSimilar(ignoredColor, pixel))
			continue;

		if (isWhiteOrTransparent(pixel))
			continue;

		if (majorityCandidate == null) {
			majorityCandidate = pixel;
			for (var j = 0; j < sumRGB.length; j++) {
				sumRGB[j] = pixel[j];
			}
		} else {

			if (pixelsAreSimilar(majorityCandidate, pixel)) {
				retainCount++;

				age++;
				for (var j = 0; j < pixel.length; j++) {
					sumRGB[j] += pixel[j];
				}
			} else {
				retainCount--;
			}

			if (retainCount == 0) {
				majorityCandidate = pixel;
				retainCount = 1;
				age = 1;

				for (var j = 0; j < sumRGB.length; j++) {
					sumRGB[j] = pixel[j];
				}
			}
		}
	}

	for (var j = 0; j < sumRGB.length; j++) {
		sumRGB[j] = Math.round(sumRGB[j] / age);
	}

	sumRGB = correctLightnessIfNeeded(sumRGB);

	return sumRGB;
}

function getFaviconColor(url, callback) {
	url = urlRemoveFile(url);

	var image = new Image();

	image.onerror = function() {
		console.error("Loading favicon from " + image.src + " failed for " + url);

		callback(null);
	}

	image.onload = function() {
		console.log("Using favicon url " + image.src + " for " + url);

		var context = $("canvas")[0].getContext('2d');
		context.clearRect(0, 0, $("canvas")[0].width, $("canvas")[0].height);
		context.drawImage(image, 0, 0);
		var imageData = context.getImageData(0, 0, image.width, image.height);

		var majorityCandidates = [null, null];
		majorityCandidates[0] = getMajorityColor(imageData);
		majorityCandidates[1] = getMajorityColor(imageData, majorityCandidates[0]);

		if (majorityCandidates[1] == null) {
			callback(majorityCandidates[0]);
		} else if (rgbToHsl(majorityCandidates[0])[1] > rgbToHsl(majorityCandidates[1])[1]) {
			callback(majorityCandidates[0]);
		} else {
			callback(majorityCandidates[1]);
		}
	}

	faviconSearchForDeclared(url, function(path) {
		if (path) {
			image.src = path;
		} else {
			faviconSearchCurrent(url, function(path) {
				image.src = path;
			}, function() {
				faviconSearchRoot(url, function(path) {
					image.src = path;
				}, function() {
					console.error("Could not find any icons for url - " + url);

					callback(null);
				})
			});
		}
	}, function() {
		console.error("Could not load url – " + url);

		callback(null);
	});
}

function faviconSearchRoot(url, success, error) {
	// Search for the favicon in the root of the site.
	var domain = getDomain(url);
	var path = domain + '/favicon.ico';

	$.get(path).success(function(data, textStatus, jqXHR) {
		if (isContentImage(jqXHR)) {
			return success(path);
		} else {
			return error();
		}
	}).error(error);
}

function faviconSearchCurrent(url, success, error) {
	var path = url + '/favicon.ico';

	$.get(path).success(function(data, textStatus, jqXHR) {
		// Search the existing directory
		if (isContentImage(jqXHR)) {
			return success(path);
		} else {
			return error();
		}
	}).error(error);
}

function faviconSearchForDeclared(url, success, error) {
	$.get(url).success(function(data) {
		// Search for explicitly declared icon hrefs
		var links = [];

		var results;
		var regex;

		regex = /<link (.*) ?\/?>/gim;
		while ((results = regex.exec(data)) !== null) {
			links.push(results[1]);
		}

		var hrefs = {};
		for (var i = 0; i < links.length; i++) {
			var relations = /rel="([\w -]*)"/.exec(links[i]);

			// If there is no relation, it's probably not an icon
			if (relations) {
				relations = relations[1].split(' ');

				var href = /href="([^ ]*)"/.exec(links[i])[1];

				for (var j = 0; j < relations.length; j++) {
					if (relations[j] != 'icon') { // && relations[j] != 'apple-touch-icon') {
						continue;
					}

					if (!hrefs[relations[j]]) {
						hrefs[relations[j]] = [];
					}

					hrefs[relations[j]].push(href);
				}
			}
		}

		var iconPath;
		if (hrefs['apple-touch-icon']) {
			iconPath = hrefs['apple-touch-icon'][0];
		} else if (hrefs['icon']) {
			iconPath = hrefs['icon'][0];
		}

		if (iconPath) {
			if (iconPath.substring(0, 2) == '//') {
				iconPath = 'http:' + iconPath;
			} else if (iconPath.substring(0, 1) == '/') {
				iconPath = 'http://' + getHostname(url) + iconPath;
			} else if (iconPath.substring(0, 4) != 'http') {
				if (url.substring(url.length - 1) != '/') {
					iconPath = url + '/' + iconPath;
				} else {
					iconPath = url + iconPath;
				}
			}

			$.get(iconPath).success(function(data, textStatus, jqXHR) {
				if (isContentImage(jqXHR)) {
					return success(iconPath);
				} else {
					return error();
				}
			}).error(error);
		} else {
			return success(null);
		}
	}).error(error);
}

function isContentImage(jqXHR) {
	var contentType = jqXHR.getResponseHeader('content-type');

	if (!contentType) {
		return false;
	}

	return contentType.indexOf('image') != -1;
}

function urlRemoveFile(url) {
	for (var i = url.length; i >= 0; i--) {
		if (url[i] == '/') {
			return url.slice(0, i + 1);
		}
	}

	return url;
}

function pixelsAreSimilar(a, b) {
	const TOLERANCE = 0.01;

	var aHSL = rgbToHsl(a);
	var bHSL = rgbToHsl(b);

	return Math.abs(aHSL[0] - bHSL[0]) <= TOLERANCE;
}

/**
 * Source: http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
 * Converts an RGB color value to HSL. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and l in the set [0, 1].
 *
 * @param   Number  r       The red color value
 * @param   Number  g       The green color value
 * @param   Number  b       The blue color value
 * @return  Array           The HSL representation
 */
function rgbToHsl(rgb){
	var r = rgb[0] / 255;
	var g = rgb[1] / 255;
	var b = rgb[2] / 255;

	var max = Math.max(r, g, b), min = Math.min(r, g, b);
	var h, s, l = (max + min) / 2;

	if (max == min){
	    h = s = 0; // achromatic
	} else {
	    var d = max - min;
	    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

	    switch(max) {
	        case r: h = (g - b) / d + (g < b ? 6 : 0); break;
	        case g: h = (b - r) / d + 2; break;
	        case b: h = (r - g) / d + 4; break;
	    }

	    h /= 6;
	}

	return [h, s, l];
}

/**
 * Converts an HSL color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes h, s, and l are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   Number  h       The hue
 * @param   Number  s       The saturation
 * @param   Number  l       The lightness
 * @return  Array           The RGB representation
 */
function hslToRgb(hsl){
	var h = hsl[0], s = hsl[1], l = hsl[2];
    var r, g, b;

    if(s == 0){
        r = g = b = l; // achromatic
    }else{
        function hue2rgb(p, q, t){
            if(t < 0) t += 1;
            if(t > 1) t -= 1;
            if(t < 1/6) return p + (q - p) * 6 * t;
            if(t < 1/2) return q;
            if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
            return p;
        }

        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        var p = 2 * l - q;
        r = hue2rgb(p, q, h + 1/3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1/3);
    }

    return [r * 255, g * 255, b * 255];
}

function safeAlphaHslToRgb(hsl) {
	var rgb = hslToRgb(hsl);
	var safeRgb = [0, 0, 0, 255]
	for (var i = 0; i < hsl.length; i++) {
		safeRgb[i] = Math.floor(rgb[i]);
	}
	return safeRgb;
}

function averagePixels(a, b, ratio) {
	var weight;
	ratio++;
	if (ratio <= 0) {
		return null;
	} else {
		weight = 1 - (1 / ratio);
	}

	var avg = [];
	for (var i = 0; i < a.length; i++) {
		avg[i] = Math.round( (weight * a[i]) + ((1 - weight) * b[i]) );
	}

	return avg;
}

function correctLightnessIfNeeded(rgb) {
	const MAX_BRIGHTNESS = 0.8;

	var hsl = rgbToHsl(rgb);
	if (hsl[2] > MAX_BRIGHTNESS) {
		hsl[2] = MAX_BRIGHTNESS;
		rgb = safeAlphaHslToRgb(hsl);
	}

	return rgb;
}<commit_msg>Fix #2.<commit_after>function createSite(url, abbreviation, callback) {
	var site = {};

	site.url = url;

	if (abbreviation) {
		site.abbreviation = abbreviation;
	} else {
		site.abbreviation = getHostname(url);
	}

	site.abbreviation = makeAbbreviation(site.abbreviation);

	setSiteColor(site, function(site, error) {
		callback(site, error);
	});
}

function deleteSite(url, callback) {
	getSites(function(sites) {
		for (var i = 0; i < sites.length; i++) {
			if (sites[i].url == url) {
				sites.splice(i, 1);
				break;
			}
		}

		saveSites(sites, callback);
	})
}

function saveSite(site, callback) {
	getSites(function(sites) {
		if (sites) {
			var found = false;

			for (var i = 0; i < sites.length; i++) {
				if (sites[i].url == site.url) {
					sites[i] = site;

					found = true;
					break;
				}
			}

			if (!found) {
				sites.push(site);
			}
		} else {
			sites = [];
			sites.push(site);
		}

		saveSites(sites, callback);
	});
}

function saveSites(sites, callback) {
	chrome.storage.sync.set({"sites": sites}, callback);
}

function getSites(callback) {
	chrome.storage.sync.get('sites', function(items) {
		sites = items['sites'];

		if (sites == undefined || sites == null) {
			return callback(null);
		} else {
			if (sites.length == 0) {
				return callback(null);
			}
		}

		return callback(sites);
	});
}

function setSiteColor(site, callback) {
	getFaviconColor(site.url, function(color) {
		var error = false;

		if (!color) {
			error = true;

			color = [0, 0, 0, 0];
		}

		site.color = {
			'red': color[0],
			'green': color[1],
			'blue': color[2],
			'alpha': color[3]
		};

		site.lastUpdated = Date.now();

		return callback(site, error);
	});
}

function siteNeedsColorUpdate(site) {
	const TIME_BEFORE_UPDATE = 1000 * 60 * 60;

	var elapsedTime = Date.now() - site.lastUpdated;

	return (!site.lastUpdated || elapsedTime >= TIME_BEFORE_UPDATE);
}

function makeAbbreviation(string) {
	return string.substring(0, 1).toUpperCase() + string.substring(1, 2).toLowerCase();
}

function isWhiteOrTransparent(color) {
	const TOLERANCE = 20;

	if (color[3] != 255)
		return true;

	return 255 - color[0] <= TOLERANCE
		&& 255 - color[1] <= TOLERANCE
		&& 255 - color[2] <= TOLERANCE;
}

function getMajorityColor(imageData, ignoredColor) {
	var majorityCandidate = null;
	var retainCount = 1;
	var age = 1;
	var sumRGB = [0, 0, 0, 0];

	for (var i = 0; i < imageData.data.length; i += 4) {
		var pixel = [imageData.data[i],
		imageData.data[i + 1],
		imageData.data[i + 2],
		imageData.data[i + 3]];

		if (ignoredColor != undefined && pixelsAreSimilar(ignoredColor, pixel))
			continue;

		if (isWhiteOrTransparent(pixel))
			continue;

		if (majorityCandidate == null) {
			majorityCandidate = pixel;
			for (var j = 0; j < sumRGB.length; j++) {
				sumRGB[j] = pixel[j];
			}
		} else {

			if (pixelsAreSimilar(majorityCandidate, pixel)) {
				retainCount++;

				age++;
				for (var j = 0; j < pixel.length; j++) {
					sumRGB[j] += pixel[j];
				}
			} else {
				retainCount--;
			}

			if (retainCount == 0) {
				majorityCandidate = pixel;
				retainCount = 1;
				age = 1;

				for (var j = 0; j < sumRGB.length; j++) {
					sumRGB[j] = pixel[j];
				}
			}
		}
	}

	for (var j = 0; j < sumRGB.length; j++) {
		sumRGB[j] = Math.round(sumRGB[j] / age);
	}

	sumRGB = correctLightnessIfNeeded(sumRGB);

	return sumRGB;
}

function getFaviconColor(url, callback) {
	url = urlRemoveFile(url);

	var image = new Image();

	image.onerror = function() {
		console.error("Loading favicon from " + image.src + " failed for " + url);

		callback(null);
	}

	image.onload = function() {
		console.log("Using favicon url " + image.src + " for " + url);

		var context = $("canvas")[0].getContext('2d');
		context.clearRect(0, 0, $("canvas")[0].width, $("canvas")[0].height);
		context.drawImage(image, 0, 0);
		var imageData = context.getImageData(0, 0, image.width, image.height);

		var majorityCandidates = [null, null];
		majorityCandidates[0] = getMajorityColor(imageData);
		majorityCandidates[1] = getMajorityColor(imageData, majorityCandidates[0]);

		if (majorityCandidates[1] == null) {
			callback(majorityCandidates[0]);
		} else if (rgbToHsl(majorityCandidates[0])[1] > rgbToHsl(majorityCandidates[1])[1]) {
			callback(majorityCandidates[0]);
		} else {
			callback(majorityCandidates[1]);
		}
	}

	faviconSearchForDeclared(url, function(path) {
		if (path) {
			image.src = path;
		} else {
			faviconSearchCurrent(url, function(path) {
				image.src = path;
			}, function() {
				faviconSearchRoot(url, function(path) {
					image.src = path;
				}, function() {
					console.error("Could not find any icons for url - " + url);

					callback(null);
				})
			});
		}
	}, function() {
		console.error("Could not load url – " + url);

		callback(null);
	});
}

function faviconSearchRoot(url, success, error) {
	// Search for the favicon in the root of the site.
	var domain = getDomain(url);
	var path = domain + '/favicon.ico';

	$.get(path).success(function(data, textStatus, jqXHR) {
		if (isContentImage(jqXHR)) {
			return success(path);
		} else {
			return error();
		}
	}).error(error);
}

function faviconSearchCurrent(url, success, error) {
	var path = url + '/favicon.ico';

	$.get(path).success(function(data, textStatus, jqXHR) {
		// Search the existing directory
		if (isContentImage(jqXHR)) {
			return success(path);
		} else {
			return error();
		}
	}).error(error);
}

function faviconSearchForDeclared(url, success, error) {
	$.get(url).success(function(data) {
		// Search for explicitly declared icon hrefs
		var links = [];

		var results;
		var regex;

		regex = /<link (.*) ?\/?>/gim;
		while ((results = regex.exec(data)) !== null) {
			links.push(results[1]);
		}

		var hrefs = {};
		for (var i = 0; i < links.length; i++) {
			var relations = /rel="([\w -]*)"/.exec(links[i]);

			// If there is no relation, it's probably not an icon
			if (relations) {
				relations = relations[1].split(' ');

				var href = /href="([^ ]*)"/.exec(links[i])[1];

				for (var j = 0; j < relations.length; j++) {
					if (relations[j] != 'icon') { // && relations[j] != 'apple-touch-icon') {
						continue;
					}

					if (!hrefs[relations[j]]) {
						hrefs[relations[j]] = [];
					}

					hrefs[relations[j]].push(href);
				}
			}
		}

		var iconPath;
		if (hrefs['apple-touch-icon']) {
			iconPath = hrefs['apple-touch-icon'][0];
		} else if (hrefs['icon']) {
			iconPath = hrefs['icon'][0];
		}

		if (iconPath) {
			if (iconPath.substring(0, 2) == '//') {
				iconPath = 'http:' + iconPath;
			} else if (iconPath.substring(0, 1) == '/') {
				iconPath = 'http://' + getHostname(url) + iconPath;
			} else if (iconPath.substring(0, 4) != 'http') {
				if (url.substring(url.length - 1) != '/') {
					iconPath = url + '/' + iconPath;
				} else {
					iconPath = url + iconPath;
				}
			}

			$.get(iconPath).success(function(data, textStatus, jqXHR) {
				if (isContentImage(jqXHR)) {
					return success(iconPath);
				} else {
					return error();
				}
			}).error(error);
		} else {
			return success(null);
		}
	}).error(error);
}

function isContentImage(jqXHR) {
	var contentType = jqXHR.getResponseHeader('content-type');

	if (!contentType) {
		return true;
	}

	return contentType.indexOf('image') != -1;
}

function urlRemoveFile(url) {
	for (var i = url.length; i >= 0; i--) {
		if (url[i] == '/') {
			return url.slice(0, i + 1);
		}
	}

	return url;
}

function pixelsAreSimilar(a, b) {
	const TOLERANCE = 0.01;

	var aHSL = rgbToHsl(a);
	var bHSL = rgbToHsl(b);

	return Math.abs(aHSL[0] - bHSL[0]) <= TOLERANCE;
}

/**
 * Source: http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
 * Converts an RGB color value to HSL. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and l in the set [0, 1].
 *
 * @param   Number  r       The red color value
 * @param   Number  g       The green color value
 * @param   Number  b       The blue color value
 * @return  Array           The HSL representation
 */
function rgbToHsl(rgb){
	var r = rgb[0] / 255;
	var g = rgb[1] / 255;
	var b = rgb[2] / 255;

	var max = Math.max(r, g, b), min = Math.min(r, g, b);
	var h, s, l = (max + min) / 2;

	if (max == min){
	    h = s = 0; // achromatic
	} else {
	    var d = max - min;
	    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

	    switch(max) {
	        case r: h = (g - b) / d + (g < b ? 6 : 0); break;
	        case g: h = (b - r) / d + 2; break;
	        case b: h = (r - g) / d + 4; break;
	    }

	    h /= 6;
	}

	return [h, s, l];
}

/**
 * Converts an HSL color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes h, s, and l are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   Number  h       The hue
 * @param   Number  s       The saturation
 * @param   Number  l       The lightness
 * @return  Array           The RGB representation
 */
function hslToRgb(hsl){
	var h = hsl[0], s = hsl[1], l = hsl[2];
    var r, g, b;

    if(s == 0){
        r = g = b = l; // achromatic
    }else{
        function hue2rgb(p, q, t){
            if(t < 0) t += 1;
            if(t > 1) t -= 1;
            if(t < 1/6) return p + (q - p) * 6 * t;
            if(t < 1/2) return q;
            if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
            return p;
        }

        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        var p = 2 * l - q;
        r = hue2rgb(p, q, h + 1/3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1/3);
    }

    return [r * 255, g * 255, b * 255];
}

function safeAlphaHslToRgb(hsl) {
	var rgb = hslToRgb(hsl);
	var safeRgb = [0, 0, 0, 255]
	for (var i = 0; i < hsl.length; i++) {
		safeRgb[i] = Math.floor(rgb[i]);
	}
	return safeRgb;
}

function averagePixels(a, b, ratio) {
	var weight;
	ratio++;
	if (ratio <= 0) {
		return null;
	} else {
		weight = 1 - (1 / ratio);
	}

	var avg = [];
	for (var i = 0; i < a.length; i++) {
		avg[i] = Math.round( (weight * a[i]) + ((1 - weight) * b[i]) );
	}

	return avg;
}

function correctLightnessIfNeeded(rgb) {
	const MAX_BRIGHTNESS = 0.8;

	var hsl = rgbToHsl(rgb);
	if (hsl[2] > MAX_BRIGHTNESS) {
		hsl[2] = MAX_BRIGHTNESS;
		rgb = safeAlphaHslToRgb(hsl);
	}

	return rgb;
}<|endoftext|>


<commit_before>import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import StoreContextProvider,{Context} from './context-provider';

function ProductMediaSlider(){

  /* Component */

  const { productMediaSliderState, productMediaSliderDispatch } = React.useContext(Context);
  const [ product, setProduct ] = useState(window.product);
  const productMainSlide = product.embed_code !== null ? product.embed_code : product.image_small;
  const galleryArray = [ productMainSlide, ... window.galleryPicturesJson ];
  const [ gallery, setGallery ] = useState(galleryArray);
  const parentContainerElement = document.getElementById('product-title-div');
  console.log(parentContainerElement);
  const [ containerWidth, setContainerWidth ] = useState();
  const [ sliderWidth, setSliderWidth ] = useState('');
  const [ currentSlide, setCurrentSlide ] = useState(0)
  const [ loading, setLoading ] = useState(true);

  React.useEffect(() => {
    window.addEventListener("resize", updateDimensions);
    window.addEventListener("orientationchange", updateDimensions);
    // setLoading(false);
  },[])

  // update dimensions
  function updateDimensions(){
    const newContainerWidth = parentContainerElement.width();
    setContainerWidth(newContainerWidth)
    setSliderWidth(containerWidth * gallery.length);
  }

  /* Render */

  console.log(containerWidth);
  console.log(sliderWidth);

  let slidesDisplay;
  if (loading === false){
    slidesDisplay = gallery.map((s,index) => (
      <SlideItem
        key={index}
        slideIndex={index}
        slideUrl={s}
      />
    ));
  }

  return (

      {slidesDisplay}

  )
}

function SlideItem(props){0
  const [ mediaType, setMediaType ] = useState(props.slideUrl.indexOf(' -1 ? "embed" : "image");
  let slideContentDisplay;
  if (mediaType === "embed"){
    slideContentDisplay = props.slideUrl;
  } else if (mediaType === "image"){
    slideContentDisplay =
  } else {
    console.log('whot');
  }
  return(

      {slideContentDisplay}

  )
}

function ProductMediaSliderContainer(){
  return (
    <StoreContextProvider>
      <ProductMediaSlider/>
    </StoreContextProvider>
  );
}

const rootElement = document.getElementById("product-media-slider-container");
ReactDOM.render(<ProductMediaSliderContainer />, rootElement);<commit_msg>pms test<commit_after>import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import StoreContextProvider,{Context} from './context-provider';

function ProductMediaSlider(){

  /* Component */

  const { productMediaSliderState, productMediaSliderDispatch } = React.useContext(Context);
  const [ product, setProduct ] = useState(window.product);
  const productMainSlide = product.embed_code !== null ? product.embed_code : product.image_small;
  const galleryArray = [ productMainSlide, ... window.galleryPicturesJson ];
  const [ gallery, setGallery ] = useState(galleryArray);
  const parentContainerElement = document.getElementById('product-title-div');
  const [ containerWidth, setContainerWidth ] = useState();
  const [ sliderWidth, setSliderWidth ] = useState('');
  const [ currentSlide, setCurrentSlide ] = useState(0)
  const [ loading, setLoading ] = useState(true);

  console.log(parentContainerElement);

  React.useEffect(() => {
    window.addEventListener("resize", updateDimensions);
    window.addEventListener("orientationchange", updateDimensions);
    // setLoading(false);
  },[])

  // update dimensions
  function updateDimensions(){
    const newContainerWidth = parentContainerElement.width();
    setContainerWidth(newContainerWidth)
    setSliderWidth(containerWidth * gallery.length);
  }

  /* Render */

  console.log(containerWidth);
  console.log(sliderWidth);

  let slidesDisplay;
  if (loading === false){
    slidesDisplay = gallery.map((s,index) => (
      <SlideItem
        key={index}
        slideIndex={index}
        slideUrl={s}
      />
    ));
  }

  return (

      {slidesDisplay}

  )
}

function SlideItem(props){0
  const [ mediaType, setMediaType ] = useState(props.slideUrl.indexOf(' -1 ? "embed" : "image");
  let slideContentDisplay;
  if (mediaType === "embed"){
    slideContentDisplay = props.slideUrl;
  } else if (mediaType === "image"){
    slideContentDisplay =
  } else {
    console.log('whot');
  }
  return(

      {slideContentDisplay}

  )
}

function ProductMediaSliderContainer(){
  return (
    <StoreContextProvider>
      <ProductMediaSlider/>
    </StoreContextProvider>
  );
}

const rootElement = document.getElementById("product-media-slider-container");
ReactDOM.render(<ProductMediaSliderContainer />, rootElement);<|endoftext|>


<commit_before>

thoughtram

            Menu

Training

Code Review

Casts

Blog

<commit_msg>changes header redirect to local main page<commit_after>

thoughtram

            Menu

Training

Code Review

Casts

Blog

<|endoftext|>


<commit_before>var firstnamePrefixes = [
    "an", "bar", "ben", "ber",
    "ca", "char", "chris", "deb", "don", "doro",
    "ed", "el", "ga", "ge", "hel",
    "ja", "jan", "jay", "je", "jen", "jess", "jo",
    "ka", "ke", "ken", "lar", "lau", "lin",
    "ma", "mar", "max",
    "nan", "pan",
    "ro", "sa", "san", "sha", "ste", "su",
    "theo", "tho", "timo",
    "vic", "xan" ];
var firstnameSuffixes = [
	"bara", "beth", "bert", "bin", "bold", "by", "cy",
    "der", "dra", "dora",
    "en", "era", "fred", "frida",
	"gard", "gret", "grid",
	"fina", "fine", "iam", "ica", "ifer", "ine",
    "la", "lios", "lotte",
	"man", "mas", "na", "nald", "nard", "neth", "nie", "ny",
    "ra", "ren", "ria", "ric", "ron", "rol", "ry",
	"san", "seph", "son",
    "thea", "theus", "thro", "thy", "tina", "tine", "toph", "topher", "ton", "tony", "tra", "trus",
    "vid", "ven", "ward", "well", "win", "wina", "der", "ya" ];
var firstnameAny = [
	"carl", "da", "min", "pe", "ron", "ter", "tor", "will",
	"wolf"];

var firstnamePrefixCounts = [
	new WeightedValue(1, 100),
	new WeightedValue(2, 25)
]

var conjections = [
	new WeightedValue(" ", 100),
	new WeightedValue(" of ", 5)
];

var lastnamePrefixes = [
    "big", "black", "breeding", "brown", "burly", "burn",
    "crooked", "cuddle", "curly",
    "dark", "double", "drink", "dwarven",
    "earth",
    "fast", "feeding", "fine",
    "golden",
    "happy", "hard", "high", "hot", "humming", "hunting",
    "leading", "lucky",
    "mac", "mad", "mocking",
    "old", "over",
    "proud",
    "quick",
    "rich", "roll", "round",
    "silvery", "small", "soft", "spider", "stark", "swift",
    "tall", "throwing", "tiny",
    "über", "un", "under",
    "wiggle", "wooly"
];
var lastnameSuffixes = [
    "balls", "bearer", "bells", "belly", "blaze", "breast", "breed", "butcher",
    "climber", "crank",
    "down", "drinker", "dwarf",
    "face", "feet", "foe", "food", "fiend", "friend",
    "hunter",
    "ikowsky",
    "jester", "joker", "joy", "judge",
    "leader", "leaf", "less", "lich", "luck", "ly",
    "menace",
    "ness",
    "pony",
    "realm", "ride", "rise",
    "shoe", "smith", "spinner", "strength", "swift",
    "ton", "toss",
    "wife", "woman"
];
var lastnameAny = [
    "arm",
    "back", "ball", "barrel", "bass", "bear", "beard", "bed", "beer", "bell", "bird", "blood", "boy", "brood", "bunny",
    "chicken", "child", "claw", "con", "cow", "crow",
    "dagger", "devil", "dog", "dork", "drop",
    "fire", "flesh", "foot", "forest", "fox", "fraud", "frog",
    "giant", "girl", "gold", "greed",
    "hammer", "hand", "head", "heart", "hill", "horse", "house", "hut",
    "jaw",
    "king",
    "land", "lead", "leather", "lust",
    "man", "meat", "milk", "mood", "mountain", "mouse", "mouth",
    "neck", "nest", "noose",
    "paw", "pig", "ploy", "power", "pride", "prince",
    "rage", "rascal", "rock", "rogue", "ruse", "rush",
    "scare", "sheep", "silver", "smurf", "snake", "snow", "sow", "spark", "spring", "star", "stone", "storm", "strong", "sun", "sword",
    "time", "tower", "tooth", "tree", "trick",
    "viper",
    "water", "weasel", "whisper", "wild", "wind", "wolf", "wood", "word", "wrath"
];

var lastnamePrefixCounts = [
	new WeightedValue(1, 100),
	new WeightedValue(2, 20)
];

var COMPOSITE_LASTNAME_CHANCE = 0;
<commit_msg>added some more name parts<commit_after>var firstnamePrefixes = [
    "an", "bar", "ben", "ber",
    "ca", "char", "chris", "deb", "don", "doro",
    "ed", "el", "ga", "ge", "hel",
    "ja", "jan", "jay", "je", "jen", "jess", "jo",
    "ka", "ke", "ken", "lar", "lau", "lin",
    "ma", "mar", "max",
    "nan", "pan",
    "sa", "san", "sha", "ste", "su",
    "theo", "tho", "timo",
    "vic", "xan" ];
var firstnameSuffixes = [
	"bara", "beth", "bert", "bin", "bold", "by", "cy",
    "der", "dra", "dora",
    "en", "era", "fred", "frida",
	"gard", "gret", "grid",
	"fina", "fine", "iam", "ica", "ifer", "ine",
    "la", "lios", "lotte",
	"man", "mas", "na", "nald", "nard", "neth", "nie", "ny",
    "ra", "ren", "ria", "ric", "ron", "rol", "ry",
	"san", "seph", "son",
    "thea", "theus", "thro", "thy", "tina", "tine", "toph", "topher", "ton", "tony", "tra", "trus",
    "vid", "ven", "ward", "well", "win", "wina", "der", "ya" ];
var firstnameAny = [
	"carl", "da", "mi", "min", "no", "pe", "ro", "ron", "ter", "to", "tor", "will",
	"wolf"];

var firstnamePrefixCounts = [
	new WeightedValue(1, 100),
	new WeightedValue(2, 25)
]

var conjections = [
	new WeightedValue(" ", 100),
	new WeightedValue(" of ", 5)
];

var lastnamePrefixes = [
    "big", "black", "breeding", "brown", "burly", "burn",
    "crooked", "cuddle", "curly",
    "dark", "double", "drink", "dwarven",
    "earth",
    "fast", "feeding", "fine",
    "golden",
    "happy", "hard", "high", "hot", "humming", "hunting",
    "leading", "lucky",
    "mac", "mad", "mocking",
    "old", "over",
    "proud",
    "quick",
    "rich", "roll", "round",
    "silvery", "small", "soft", "spider", "stark", "swift",
    "tall", "throwing", "tiny",
    "über", "un", "under",
    "wiggle", "wooly"
];
var lastnameSuffixes = [
    "balls", "bearer", "bells", "belly", "blaze", "breast", "breed", "butcher",
    "climber", "crank",
    "down", "drinker", "dwarf",
    "face", "feet", "foe", "food", "fiend", "friend",
    "hunter",
    "ikowsky",
    "jester", "joker", "joy", "judge",
    "leader", "leaf", "less", "lich", "luck", "ly",
    "menace",
    "ness",
    "pony",
    "realm", "ride", "rise",
    "shoe", "smith", "spinner", "strength", "swift",
    "ton", "toss",
    "wife", "woman"
];
var lastnameAny = [
    "arm",
    "back", "ball", "barrel", "bass", "bear", "beard", "bed", "beer", "bell", "bird", "blood", "boy", "brood", "bunny",
    "chicken", "child", "claw", "colt", "con", "cow", "crow",
    "dagger", "devil", "dog", "dork", "drop",
    "fire", "flesh", "foot", "forest", "fox", "fraud", "frog",
    "giant", "girl", "gold", "greed",
    "hammer", "hand", "head", "heart", "hill", "horse", "house", "hut",
    "jaw",
    "king",
    "land", "lead", "leather", "lust",
    "man", "meat", "milk", "mood", "mountain", "mouse", "mouth",
    "neck", "nerd", "nest", "noose",
    "paw", "pig", "ploy", "power", "pride", "prince",
    "rage", "rascal", "rock", "rogue", "ruse", "rush",
    "scare", "sheep", "silver", "smurf", "snake", "snow", "sow", "spark", "spring", "star", "stone", "storm", "strong", "sun", "sword",
    "time", "tower", "tooth", "tree", "trick",
    "viper",
    "water", "weasel", "whisper", "wild", "wind", "wolf", "wood", "word", "wrath"
];

var lastnamePrefixCounts = [
	new WeightedValue(1, 100),
	new WeightedValue(2, 20)
];

var COMPOSITE_LASTNAME_CHANCE = 0;
<|endoftext|>


<commit_before>// ==UserScript==
// @name         LDR - Bold Headings
// @namespace    http://iwamot.com/
// @version      0.0.1
// @description  見出しと思われる部分を見出しっぽくします
// @author       IWAMOTO Takashi <hello@iwamot.com> http://iwamot.com/
// @match        http://reader.livedoor.com/reader/*
// @grant        GM_addStyle
// @homepage     https://github.com/iwamot/ldr-bold-headings
// @updateURL    https://github.com/iwamot/ldr-bold-headings/raw/master/ldr-bold-headings.user.js
// ==/UserScript==

(function(w) {
  GM_addStyle('div.LDRBH {font-weight: bold !important; font-size: 1.1em !important; margin-top: 2.2em !important; margin-bottom: 1.1em !important}');

  w.register_hook('after_printfeed', function(feed) {
    feed.items.forEach(function(item) {
      (function(divId) {
        if (!document.getElementById(divId)) {
          var self = arguments.callee;
          setTimeout(function(){self(divId);}, 500);
          return;
        }

        var nodesSnapshot = document.evaluate('//div[@id="' + divId + '"]/div/text()[string-length(normalize-space()) > 0]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        for (var i = 0, j = nodesSnapshot.snapshotLength; i < j; i++) {
          var textNode = nodesSnapshot.snapshotItem(i);
          var nextSibling = textNode.nextSibling;
          if (!nextSibling || !isBlockElement(nextSibling)) continue;

          var div = document.createElement('div');
          div.className = 'LDRBH';
          var text = document.createTextNode(textNode.data);
          div.appendChild(text);
          textNode.parentNode.replaceChild(div, textNode);
        }
      })('item_body_' + item.id);
    });
  });

  function isBlockElement(node) {
    switch (node.tagName.toLowerCase()) {
    case 'p':
    case 'div':
    case 'table':
    case 'dl':
    case 'ul':
    case 'ol':
    case 'form':
    case 'address':
    case 'blockquote':
    case 'fieldset':
    case 'pre':
      return true;
    default:
      return false;
    }
  }
})(this.unsafeWindow);
<commit_msg>アンカーが含まれる見出しに対応<commit_after>// ==UserScript==
// @name         LDR - Bold Headings
// @namespace    http://iwamot.com/
// @version      0.0.2
// @description  見出しと思われる部分を見出しっぽくします
// @author       IWAMOTO Takashi <hello@iwamot.com> http://iwamot.com/
// @match        http://reader.livedoor.com/reader/*
// @grant        GM_addStyle
// @homepage     https://github.com/iwamot/ldr-bold-headings
// @updateURL    https://github.com/iwamot/ldr-bold-headings/raw/master/ldr-bold-headings.user.js
// ==/UserScript==

(function(w) {
  GM_addStyle('div.LDRBH {font-weight: bold !important; font-size: 1.1em !important; margin-top: 2.2em !important; margin-bottom: 1.1em !important}');

  w.register_hook('after_printfeed', function(feed) {
    feed.items.forEach(function(item) {
      (function(divId) {
        if (!document.getElementById(divId)) {
          var self = arguments.callee;
          setTimeout(function(){self(divId);}, 500);
          return;
        }

        var nodesSnapshot = document.evaluate('//div[@id="' + divId + '"]/div/node()', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

        var inlineNodes = [];
        for (var i = 0, j = nodesSnapshot.snapshotLength; i < j; i++) {
          var node = nodesSnapshot.snapshotItem(i);
          if (node.nodeType == 3 || !isBlockElement(node)) {
            inlineNodes.push(node);
            continue;
          }

          if (inlineNodes.length > 0) {
            var div = document.createElement('div');
            div.className = 'LDRBH';
            inlineNodes.forEach(function(node) {div.appendChild(node.cloneNode(true));});
            inlineNodes[0].parentNode.insertBefore(div, inlineNodes[0]);
            inlineNodes.forEach(function(node) {node.parentNode.removeChild(node);});
            inlineNodes = [];
          }
        }
      })('item_body_' + item.id);
    });
  });

  function isBlockElement(node) {
    switch (node.tagName.toLowerCase()) {
    case 'p':
    case 'div':
    case 'table':
    case 'dl':
    case 'ul':
    case 'ol':
    case 'form':
    case 'address':
    case 'blockquote':
    case 'fieldset':
    case 'pre':
      return true;
    default:
      return false;
    }
  }
})(this.unsafeWindow);
<|endoftext|>


<commit_before>L.Polyline.Measure = L.Draw.Polyline.extend({
    addHooks: function() {
        L.Draw.Polyline.prototype.addHooks.call(this);
        if (this._map) {
            this._markerGroup = new L.LayerGroup();
            this._map.addLayer(this._markerGroup);

            this._markers = [];
            this._map.on('click', this._onClick, this);
            this._startShape();
        }
    },

    removeHooks: function () {
        L.Draw.Polyline.prototype.removeHooks.call(this);

        this._clearHideErrorTimeout();

        //!\ Still useful when control is disabled before any drawing (refactor needed?)
        this._map.off('mousemove', this._onMouseMove);
        this._clearGuides();
        this._container.style.cursor = '';

        this._removeShape();

        this._map.removeLayer(this._markerGroup);
        delete this._markerGroup;
        delete this._markers;

        this._map.off('click', this._onClick);
    },

    _startShape: function() {
        this._drawing = true;
        this._poly = new L.Polyline([], this.options.shapeOptions);

        this._container.style.cursor = 'crosshair';

        this._updateTooltip();
        this._map.on('mousemove', this._onMouseMove, this);
    },

    _finishShape: function () {
        this._drawing = false;

        this._cleanUpShape();
        this._clearGuides();

        this._updateTooltip();

        this._map.off('mousemove', this._onMouseMove, this);
        this._container.style.cursor = '';
    },

    _removeShape: function() {
        if (!this._poly)
            return;
        this._map.removeLayer(this._poly);
        delete this._poly;
        this._markers.splice(0);
        this._markerGroup.clearLayers();
    },

    _onClick: function(e) {
        if (!this._drawing) {
            this._removeShape();
            this._startShape();
            return;
        }

        L.Draw.Polyline.prototype._onClick.call(this, e);
    },

    _getTooltipText: function() {
        var labelText = L.Draw.Polyline.prototype._getTooltipText.call(this);
        if (!this._drawing) {
            labelText.text = '';
        }
        return labelText;
    }
});

L.Control.MeasureControl = L.Control.extend({

    statics: {
        TITLE: 'Measure distances'
    },
    options: {
        position: 'topleft',
        handler: {}
    },

    toggle: function() {
        if (this.handler.enabled()) {
            this.handler.disable.call(this.handler);
        } else {
            this.handler.enable.call(this.handler);
        }
    },

    onAdd: function(map) {
        var className = 'leaflet-control-draw';

        this._container = L.DomUtil.create('div', 'leaflet-bar');

        this.handler = new L.Polyline.Measure(map, this.options.handler);

        this.handler.on('enabled', function () {
            L.DomUtil.addClass(this._container, 'enabled');
        }, this);

        this.handler.on('disabled', function () {
            L.DomUtil.removeClass(this._container, 'enabled');
        }, this);

        var link = L.DomUtil.create('a', className+'-measure', this._container);
        link.href = '#';
        link.title = L.Control.MeasureControl.TITLE;

        L.DomEvent
            .addListener(link, 'click', L.DomEvent.stopPropagation)
            .addListener(link, 'click', L.DomEvent.preventDefault)
            .addListener(link, 'click', this.toggle, this);

        return this._container;
    }
});

L.Map.mergeOptions({
    measureControl: false
});

L.Map.addInitHook(function () {
    if (this.options.measureControl) {
        this.measureControl = L.Control.measureControl().addTo(this);
    }
});

L.Control.measureControl = function (options) {
    return new L.Control.MeasureControl(options);
};

<commit_msg>Remove cleanup code already done in parent class (fixes #3)<commit_after>L.Polyline.Measure = L.Draw.Polyline.extend({
    addHooks: function() {
        L.Draw.Polyline.prototype.addHooks.call(this);
        if (this._map) {
            this._markerGroup = new L.LayerGroup();
            this._map.addLayer(this._markerGroup);

            this._markers = [];
            this._map.on('click', this._onClick, this);
            this._startShape();
        }
    },

    removeHooks: function () {
        L.Draw.Polyline.prototype.removeHooks.call(this);

        this._clearHideErrorTimeout();

        //!\ Still useful when control is disabled before any drawing (refactor needed?)
        this._map.off('mousemove', this._onMouseMove);
        this._clearGuides();
        this._container.style.cursor = '';

        this._removeShape();

        this._map.off('click', this._onClick);
    },

    _startShape: function() {
        this._drawing = true;
        this._poly = new L.Polyline([], this.options.shapeOptions);

        this._container.style.cursor = 'crosshair';

        this._updateTooltip();
        this._map.on('mousemove', this._onMouseMove, this);
    },

    _finishShape: function () {
        this._drawing = false;

        this._cleanUpShape();
        this._clearGuides();

        this._updateTooltip();

        this._map.off('mousemove', this._onMouseMove, this);
        this._container.style.cursor = '';
    },

    _removeShape: function() {
        if (!this._poly)
            return;
        this._map.removeLayer(this._poly);
        delete this._poly;
        this._markers.splice(0);
        this._markerGroup.clearLayers();
    },

    _onClick: function(e) {
        if (!this._drawing) {
            this._removeShape();
            this._startShape();
            return;
        }

        L.Draw.Polyline.prototype._onClick.call(this, e);
    },

    _getTooltipText: function() {
        var labelText = L.Draw.Polyline.prototype._getTooltipText.call(this);
        if (!this._drawing) {
            labelText.text = '';
        }
        return labelText;
    }
});

L.Control.MeasureControl = L.Control.extend({

    statics: {
        TITLE: 'Measure distances'
    },
    options: {
        position: 'topleft',
        handler: {}
    },

    toggle: function() {
        if (this.handler.enabled()) {
            this.handler.disable.call(this.handler);
        } else {
            this.handler.enable.call(this.handler);
        }
    },

    onAdd: function(map) {
        var className = 'leaflet-control-draw';

        this._container = L.DomUtil.create('div', 'leaflet-bar');

        this.handler = new L.Polyline.Measure(map, this.options.handler);

        this.handler.on('enabled', function () {
            L.DomUtil.addClass(this._container, 'enabled');
        }, this);

        this.handler.on('disabled', function () {
            L.DomUtil.removeClass(this._container, 'enabled');
        }, this);

        var link = L.DomUtil.create('a', className+'-measure', this._container);
        link.href = '#';
        link.title = L.Control.MeasureControl.TITLE;

        L.DomEvent
            .addListener(link, 'click', L.DomEvent.stopPropagation)
            .addListener(link, 'click', L.DomEvent.preventDefault)
            .addListener(link, 'click', this.toggle, this);

        return this._container;
    }
});

L.Map.mergeOptions({
    measureControl: false
});

L.Map.addInitHook(function () {
    if (this.options.measureControl) {
        this.measureControl = L.Control.measureControl().addTo(this);
    }
});

L.Control.measureControl = function (options) {
    return new L.Control.MeasureControl(options);
};

<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { Container, Row, Col, Button } from 'reactstrap'
import Item from './Item'
import i18n from '/imports/both/i18n/en'
import ContributorsSection from '../ContributorsSection'
import './styles.scss'

const HowToHelpI18N = i18n.Home.how_to_help_section

class HowToHelpSection extends Component {
  render (props) {
    const {
      title,
      content
    } = HowToHelpI18N

    const {
      items
    } = content

    return (

        <Container>
          <Row className="items">
            <Col>

{title}

              {items.map((item, i) => (
                <Row key={i}>
                  <Item item={item} />
                  {(i === 1) ? <Button className='sign-and-post' tag={Link} to='/?new=1'>Post</Button> : null}
                </Row>
              ))}
            </Col>
            <Col>

<ContributorsSection />

            </Col>
          </Row>
        </Container>

    )
  }
}

export default HowToHelpSection
<commit_msg>Linking homepage user logged in button to i18n<commit_after>import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { Container, Row, Col, Button } from 'reactstrap'
import Item from './Item'
import i18n from '/imports/both/i18n/en'
import ContributorsSection from '../ContributorsSection'
import './styles.scss'

const HowToHelpI18N = i18n.Home.how_to_help_section
const { Home } = i18n

class HowToHelpSection extends Component {
 render (props) {
   const {
     title,
     content
   } = HowToHelpI18N

   const {
     items
   } = content

   const isLoggedIn = !!this.props.user

   return (

       <Container>
         <Row className="items">
           <Col>

{title}

             {items.map((item, i) => (
               <Row key={i}>
                 <Item item={item} />
                 {(i === 1) ? <Button className='sign-and-post' tag={Link} to='/?new=1'>{isLoggedIn ? Home.post.button: Home.post.button_loggedIn}</Button> : null}
               </Row>
             ))}
           </Col>
           <Col>

<ContributorsSection />

           </Col>
         </Row>
       </Container>

   )
 }
}

export default HowToHelpSection
<|endoftext|>


<commit_before>import FormHandler from './form';

const DonationForm = new FormHandler({
  rangesAttach: $('.carousel__slide--range .carousel__radios'),
  amountsAttach: $('.carousel__slide--amount .carousel__radios'),
  outerContainer: $('#carousel-outer'),
  innerContainer: $('#carousel-inner'),
  carouselSlides: $('[class*=carousel__slide]'),
  prevButton: $('#prev'),
  nextButton: $('#next'),
  submitButton: $('#submit'),
  manualInput: $('#amount-input'),
  form: $('.carousel__form'),
  errorMessage: $('#error-message'),
  frequenciesRadios: '.carousel__slide--frequency .carousel__radio',
  rangesRadios: '.carousel__slide--range .carousel__radio',
  amountsRadios: '.carousel__slide--amount .carousel__radio',
  defaultFrequenciesIndex: 1,
  defaultRangesIndex: 1,
  defaultAmountsIndex: 1,
  startSlide: 0,
  animationLength: 400,
  frequenciesToRanges: [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
  ],
  rangesToAmounts: [
    [17, 18, 19, 20],
    [21, 22, 23, 24],
    [25, 26, 27, 28],
    [29, 30, 31, 32]
  ]
});

DonationForm.doInitialEvents();
DonationForm.initCarousel();
DonationForm.bindAllEvents();
<commit_msg>remove nonexistent method call<commit_after>import FormHandler from './form';

(function resetForm() {
  document.forms[0].reset();
})();

const DonationForm = new FormHandler({
  rangesAttach: $('.carousel__slide--range .carousel__fieldset'),
  amountsAttach: $('.carousel__slide--amount .carousel__radios'),
  outerContainer: $('#carousel-outer'),
  innerContainer: $('#carousel-inner'),
  carouselSlides: $('[class*=carousel__slide]'),
  prevButton: $('#prev'),
  nextButton: $('#next'),
  submitButton: $('#submit'),
  manualInput: $('#manual-input'),
  form: $('.carousel__form'),
  errorMessage: $('#error-message'),
  frequenciesRadios: '.carousel__slide--frequency .carousel__radio',
  rangesRadios: '.carousel__slide--range .carousel__radio',
  amountsRadios: '.carousel__slide--amount .carousel__radio',
  defaultFrequenciesIndex: 1,
  defaultRangesIndex: 1,
  defaultAmountsIndex: 1,
  startSlide: 0,
  startFrequency: 'monthly',
  animationLength: 400,
  frequenciesToRanges: {
    once: ['$35-$100', '$101-$500', '$501-$999', '$1,000-$5,000'],
    monthly: ['$5-$34', '$35-$64', '$65-$83', '$84-$417'],
    yearly: ['$35-$100', '$101-$500', '$501-$999', '$1,000-$5,000']
  },

  rangesToAmounts: {
    once: [
      [35, 55, 75, 100],
      [101, 150, 300, 500],
      [501, 650, 850, 999],
      [1000, 2500, 4500, 5000]
    ],

    monthly: [
      [5, 15, 25, 34],
      [35, 45, 55, 64],
      [65, 75, 80, 83],
      [84, 146, 209, 417]
    ],

    yearly: [
      [35, 55, 75, 100],
      [101, 150, 300, 500],
      [501, 650, 850, 999],
      [1000, 2500, 4500, 5000]
    ]
  }
});

DonationForm.initCarousel();
DonationForm.bindAllEvents();
<|endoftext|>


<commit_before>'use strict';

// Modules
const _ = require('lodash');
const async = require('async');
const config = require('../../input/config');
const fs = require('fs');
const Organization = require('../Organization');
const path = require('path');
const Submissions = require('../Submissions');

// Modifications
Organization.prototype.requestSubmission = function requestSubmission (params) {
    let eligible = params.free ? this.eligible.free : this.eligible[params.from.sources[0]];
    let lostIndexes = [];
    let submission = _.find(eligible, (submission, index) => {
        if (!params.given[submission.hash]) {
            return true;
        } else {
            lostIndexes.push(index);
            return false;
        }
    });

    if (lostIndexes.length > 0) {
        _.pullAt(eligible, lostIndexes);
    }

    return submission;
}

Organization.prototype.giveSubmission = function giveSubmission (params) {
    let submission = params.submission;
    params.given[submission.hash] = submission;
    params.to.received.push(submission);
    this.given.push(submission);
}

Organization.prototype.takeFreeSubmission = function takeFreeSubmission (params) {
    let submission = params.submission;
    params.given[submission.hash] = submission;
    this.received.push(submission);
    this.freeCount++;
}

// Class
module.exports = class YouGetWhatYouGive {

    constructor(params) {
        this.callback = params.callback;
        this.highestSwapCount = +process.argv[4] || 0;
        this.organizations = params.organizations;
        this.submissions = params.submissions;

        console.log(`Swap count to beat is ${this.highestSwapCount}`);

        async.timesSeries(+process.argv[3], (n, next) => {
            console.log(`Starting algorithm iteration ${n + 1} of ${process.argv[3]} total`);

            this.start(next);
        });
    }

    start(next) {
        async.series([
            // Resetting instance variables
            (next) => {
                this.given = {};

                next();
            },

            // Modifying organization and submissions objects
            (next) => {
                _.each(this.organizations, (organization) => {
                    organization.eligible = {};
                    organization.freeCount = 0;
                    organization.given = [];
                    organization.received = [];
                    organization.sacrificing = false;
                    organization.sourced = [];
                });

                _.each(this.submissions.hashes, (submission) => {
                    // Used to determine rarity of submission
                    submission.eligible = [];
                });

                next();
            },

            // Assigning submissions to organizations
            (next) => {
                console.log('Assigning submissions to organizations');
                let sourceMap = {};

                _.each(this.organizations, (organization) => {
                    _.each(organization.sources, (source) => {
                        sourceMap[source] = organization;
                    });
                });

                _.each(this.submissions.hashes, (submission) => {
                    submission.sourceObjects = [];

                    _.each(_.keys(submission.sources), (source) => {
                        let organization = sourceMap[source];
                        if (organization) {
                            organization.sourced.push(submission);
                            submission.sourceObjects.push(organization);
                        }
                    });
                });

                next();
            },

            // Finding eligible hashes for each organization
            (next) => {
                console.log('Finding eligible hashes for each organization');
                // Creating eligibity arrays
                _.each(this.organizations, (organization) => {
                    organization.eligible.free = [];

                    _.each(this.organizations, (otherOrganization) => {
                        if (organization === otherOrganization) {
                            return;
                        }

                        organization.eligible[otherOrganization.sources[0]] = [];
                    });
                });

                // Assigning eligiblity to submissions
                _.each(this.submissions.hashes, (submission) => {
                    _.each(this.organizations, (organization) => {
                        // Skip suppressed hashes
                        if (organization.hashes[submission.hash]) {
                            return;
                        }

                        // Used to determine rarity of submission
                        submission.eligible.push(organization);
                    });
                });

                next();
            },

            // Sort submissions by eligibility
            // Most common to most rare
            (next) => {
                this.submissions.hashes.sort((a, b) => a.eligible.length - b.eligible.length);

                next();
            },

            // Repayments
            (next) => {
                console.log('Repayments');
                _.each(config.sourcesToRepay, (sourceObj) => {
                    let repayedCount = 0;

                    let organization = _.find(this.organizations, (organization) => {
                        return sourceObj.source === organization.sources[0];
                    });

                    console.log('Repaying ' + sourceObj.name);

                    // Source unsourced submissions, from the recipient's suppression list
                    _.each(this.submissions.hashes, (submission) => {
                        if (
                            organization.hashes[submission.hash]
                            &&
                            submission.sourceObjects.length === 0
                        ) {
                            organization.sourced.push(submission);
                            submission.sourceObjects.push(organization);
                            repayedCount++;
                        }

                        if (sourceObj.amount <= repayedCount) {
                            return false;
                        }
                    });

                    console.log(`Repayed ${repayedCount} to ${organization.name}`);
                });

                next();
            },

            // Destroy remaining unsourced submissions
            (next) => {
                console.log('Destroying unsourced submissions');
                let indexesToRemove = [];

                _.each(this.submissions.hashes, (submission, index) => {
                    if (submission.sourceObjects.length === 0) {
                        indexesToRemove.push(index);
                    }
                });

                console.log(`Destroying ${indexesToRemove.length} unsourced submissions`);

                _.pullAt(this.submissions.hashes, indexesToRemove);

                next();
            },

            // Honorable sacrifice
            (next) => {
                console.log('Honorable sacrifice');
                let sacrificers = _.filter(
                    this.organizations,
                    (organization) => _.includes(config.sourcesToSacrifice, organization.sources[0])
                );

                _.each(sacrificers, (sacrificer) => {
                    console.log(sacrificer.name);
                    sacrificer.sacrificing = true;

                    // Remove all references to sourceObjects
                    let count = 0;

                    _.each(this.submissions.hashes, (submission, index) => {
                        if (_.includes(submission.sourceObjects, sacrificer)) {
                            _.pull(submission.sourceObjects, sacrificer);
                            count++;
                        }

                    });

                    console.log(`Removed a source from ${count} submissions.`);
                });

                next();
            },

            // Assigning eligiblity to organizations
            (next) => {
                console.log('Assigning eligiblity to organizations');
                _.each(this.submissions.hashes, (submission) => {
                    let isFree = submission.sourceObjects.length === 0;

                    _.each(submission.eligible, (organization) => {
                        if (isFree) {
                            organization.eligible.free.push(submission);
                        } else {
                            _.each(submission.sourceObjects, (otherOrganization) => {
                                if (organization === otherOrganization) {
                                    return;
                                }

                                organization.eligible[otherOrganization.sources[0]].push(submission);
                            });
                        }
                    });
                });

                next();
            },

            // Swap V2
            (next) => {
                this.swap(next);
            },

            // Distributing free submissions
            (next) => {
                this.distributeUnsourcedSubmissions(next);
            },

            // Save, if swap count is higher than a previous iteration
            (next) => {
                let count = this.getSwapCount();
                if (this.highestSwapCount < count) {
                    console.log(`:D The new count (${count}) is larger than the existing count (${this.highestSwapCount}).`);
                    this.highestSwapCount = count;
                } else {
                    console.log(`¯\\_(ツ)_/¯ The new count (${count}) is not larger than the existing count (${this.highestSwapCount}).`);
                    next();
                    return;
                }

                console.log('Saving hashes for each organization');
                _.each(this.organizations, (organization) => {
                    if (organization.sacrificing) {
                        return;
                    }

                    let data = '';

                    _.each(organization.received, (submission) => {
                        data += submission.hash + '\n';
                    });

                    fs.writeFileSync(path.join(__dirname, `../../output/hashes-${organization.sources[0]}.csv`), data);
                });

                let summary = this.getSummary();
                fs.writeFileSync(path.join(__dirname, `../../output/summary.csv`), summary);

                console.log('-------');
                console.log(summary);
                console.log('-------');

                next();
            },
        ], next);
    }

    swap(next) {
        console.log('Starting swap!');
        async.forever((next) => {
            let success = false;

            let owedOrganizations = this.getSortedListOfOwedOrganizations();
            let givingOrganizations = this.getListOfGivingOrganizations();

            _.each(owedOrganizations, (owedOrganization) => {
                // Find the most common submission
                let mostCommonSubmission;
                let mostCommonSubmissionOwner;
                _.each(givingOrganizations, (givingOrganization) => {
                    let submission = owedOrganization.requestSubmission({
                        from: givingOrganization,
                        given: this.given,
                    });

                    if (
                        submission
                        &&
                        (
                            !mostCommonSubmission
                            ||
                            mostCommonSubmission.eligible.length > submission.eligible.length
                        )
                    ) {
                        mostCommonSubmission = submission;
                        mostCommonSubmissionOwner = givingOrganization;
                    }
                });

                if (mostCommonSubmission) {
                    mostCommonSubmissionOwner.giveSubmission({
                        given: this.given,
                        submission: mostCommonSubmission,
                        to: owedOrganization,
                    });

                    success = true;
                }

                // If there was a match, break the loop
                if (success) {
                    return false;
                }
            });

            next(!success);
        }, () => {
            console.log('Trading has halted');
            next();
        });
    }

    distributeUnsourcedSubmissions(next) {
        console.log('Distributing free submissions');
        let validOrganizations = _.filter(this.organizations, (organization) => !organization.sacrificing);

        async.forever((next) => {
            // Check if every organization has bounced
            if (_.isEmpty(validOrganizations)) {
                next(1);
                return;
            }

            // Find the organization who has taken the least free submissions
            let organization = _.min(validOrganizations, organization => organization.received.length / organization.sourced.length);

            // Stop when an organization has been repayed
            if (organization.received.length >= organization.sourced.length) {
                console.log(organization.name + ' is bowing out.');
                _.pull(validOrganizations, organization);
                next();
                return;
            }

            let submission = organization.requestSubmission({
                free: true,
                given: this.given,
            });

            if (!submission) {
                console.log(organization.name + ' is bowing out.');
                _.pull(validOrganizations, organization);
                next();
                return;
            }

            organization.takeFreeSubmission({
                given: this.given,
                submission: submission,
            });

            next();
        }, (err) => {
            next();
        });
    }

    getSwapCount() {
        return _.sum(this.organizations, (organization) => {
            if (organization.sacrificing) {
                return 0;
            }

            return organization.received.length;
        });
    }

    getSummary() {
        let summary = 'Organization,Owed,Received From Swap,Received From Sacrifice,Received Total\n';
        _.each(this.organizations, (organization) => {
            if (organization.sacrificing) {
                return;
            }

            let keyCount = organization.received.length;
            summary += `${organization.name},${organization.sourced.length},${keyCount - organization.freeCount},${organization.freeCount},${keyCount}\n`;
        });

        return summary;
    }

    getListOfGivingOrganizations() {
        return _.filter(this.organizations, (organization) => {
            if (organization.sacrificing) {
                return false;
            }

            return organization.given.length <= organization.received.length;
        });
    }

    getSortedListOfOwedOrganizations() {
        return _.filter(this.organizations, (organization) => {
            if (organization.sacrificing) {
                return false;
            }

            return (
                organization.given.length >= organization.received.length
            );
        }).sort((a, b) => {
            // Sort those who have given more than they've received first
            let scoreA = a.given.length - a.received.length;
            let scoreB = b.given.length - b.received.length;

            // Sort those who have more unpayed sourced actions first
            if (scoreA === scoreB) {
                scoreA = a.sourced.length - a.received.length;
                scoreB = b.sourced.length - b.received.length;
            }

            return scoreB - scoreA;
        });
    }

}
<commit_msg>Simplifying<commit_after>'use strict';

// Modules
const _ = require('lodash');
const async = require('async');
const config = require('../../input/config');
const fs = require('fs');
const Organization = require('../Organization');
const path = require('path');
const Submissions = require('../Submissions');

// Modifications
Organization.prototype.requestSubmission = function requestSubmission (params) {
    let eligible = params.free ? this.eligible.free : this.eligible[params.from.sources[0]];
    let lostIndexes = [];
    let submission = _.find(eligible, (submission, index) => {
        if (!params.given[submission.hash]) {
            return true;
        } else {
            lostIndexes.push(index);
            return false;
        }
    });

    if (lostIndexes.length > 0) {
        _.pullAt(eligible, lostIndexes);
    }

    return submission;
}

Organization.prototype.giveSubmission = function giveSubmission (params) {
    let submission = params.submission;
    params.given[submission.hash] = submission;
    params.to.received.push(submission);
    this.given.push(submission);
}

Organization.prototype.takeFreeSubmission = function takeFreeSubmission (params) {
    let submission = params.submission;
    params.given[submission.hash] = submission;
    this.received.push(submission);
    this.freeCount++;
}

// Class
module.exports = class YouGetWhatYouGive {

    constructor(params) {
        this.callback = params.callback;
        this.organizations = params.organizations;
        this.submissions = params.submissions;
        this.start();
    }

    start(next) {
        async.series([
            // Resetting instance variables
            (next) => {
                this.given = {};

                next();
            },

            // Modifying organization and submissions objects
            (next) => {
                _.each(this.organizations, (organization) => {
                    organization.eligible = {};
                    organization.freeCount = 0;
                    organization.given = [];
                    organization.received = [];
                    organization.sacrificing = false;
                    organization.sourced = [];
                });

                _.each(this.submissions.hashes, (submission) => {
                    // Used to determine rarity of submission
                    submission.eligible = [];
                });

                next();
            },

            // Assigning submissions to organizations
            (next) => {
                console.log('Assigning submissions to organizations');
                let sourceMap = {};

                _.each(this.organizations, (organization) => {
                    _.each(organization.sources, (source) => {
                        sourceMap[source] = organization;
                    });
                });

                _.each(this.submissions.hashes, (submission) => {
                    submission.sourceObjects = [];

                    _.each(_.keys(submission.sources), (source) => {
                        let organization = sourceMap[source];
                        if (organization) {
                            organization.sourced.push(submission);
                            submission.sourceObjects.push(organization);
                        }
                    });
                });

                next();
            },

            // Finding eligible hashes for each organization
            (next) => {
                console.log('Finding eligible hashes for each organization');
                // Creating eligibity arrays
                _.each(this.organizations, (organization) => {
                    organization.eligible.free = [];

                    _.each(this.organizations, (otherOrganization) => {
                        if (organization === otherOrganization) {
                            return;
                        }

                        organization.eligible[otherOrganization.sources[0]] = [];
                    });
                });

                // Assigning eligiblity to submissions
                _.each(this.submissions.hashes, (submission) => {
                    _.each(this.organizations, (organization) => {
                        // Skip suppressed hashes
                        if (organization.hashes[submission.hash]) {
                            return;
                        }

                        // Used to determine rarity of submission
                        submission.eligible.push(organization);
                    });
                });

                next();
            },

            // Sort submissions by eligibility
            // Most common to most rare
            (next) => {
                this.submissions.hashes.sort((a, b) => a.eligible.length - b.eligible.length);

                next();
            },

            // Repayments
            (next) => {
                _.each(config.sourcesToRepay, (sourceObj) => {
                    let repayedCount = 0;

                    let organization = _.find(this.organizations, (organization) => {
                        return sourceObj.source === organization.sources[0];
                    });

                    // Source unsourced submissions, from the recipient's suppression list
                    _.each(this.submissions.hashes, (submission) => {
                        if (
                            organization.hashes[submission.hash]
                            &&
                            submission.sourceObjects.length === 0
                        ) {
                            organization.sourced.push(submission);
                            submission.sourceObjects.push(organization);
                            repayedCount++;
                        }

                        if (sourceObj.amount <= repayedCount) {
                            return false;
                        }
                    });

                    console.log(`Repayed ${repayedCount} to ${organization.name}`);
                });

                next();
            },

            // Destroy remaining unsourced submissions
            (next) => {
                if (!config.destroyUnsourcedSubmissions) {
                    next();
                    return;
                }

                let indexesToRemove = [];

                _.each(this.submissions.hashes, (submission, index) => {
                    if (submission.sourceObjects.length === 0) {
                        indexesToRemove.push(index);
                    }
                });

                console.log(`Destroying ${indexesToRemove.length} unsourced submissions`);

                _.pullAt(this.submissions.hashes, indexesToRemove);

                next();
            },

            // Honorable sacrifice
            (next) => {
                let sacrificers = _.filter(
                    this.organizations,
                    (organization) => _.includes(config.sourcesToSacrifice, organization.sources[0])
                );

                if (sacrificers.length === 0) {
                    next();
                    return;
                }

                _.each(sacrificers, (sacrificer) => {
                    sacrificer.sacrificing = true;

                    // Remove all references to sourceObjects
                    let count = 0;

                    _.each(this.submissions.hashes, (submission, index) => {
                        if (_.includes(submission.sourceObjects, sacrificer)) {
                            _.pull(submission.sourceObjects, sacrificer);
                            count++;
                        }

                    });

                    console.log(`${sacrificer.name} sacrificed a source from ${count} submissions.`);
                });

                next();
            },

            // Assigning eligiblity to organizations
            (next) => {
                console.log('Assigning eligiblity to organizations');
                _.each(this.submissions.hashes, (submission) => {
                    let isFree = submission.sourceObjects.length === 0;

                    _.each(submission.eligible, (organization) => {
                        if (isFree) {
                            organization.eligible.free.push(submission);
                        } else {
                            _.each(submission.sourceObjects, (otherOrganization) => {
                                if (organization === otherOrganization) {
                                    return;
                                }

                                organization.eligible[otherOrganization.sources[0]].push(submission);
                            });
                        }
                    });
                });

                next();
            },

            // Swap V2
            (next) => {
                this.swap(next);
            },

            // Distributing free submissions
            (next) => {
                this.distributeUnsourcedSubmissions(next);
            },

            // Save
            (next) => {
                let count = this.getSwapCount();
                console.log(`${count} names were swapped!`);

                console.log('Saving hashes for each organization');
                _.each(this.organizations, (organization) => {
                    if (organization.sacrificing) {
                        return;
                    }

                    let data = '';

                    _.each(organization.received, (submission) => {
                        data += submission.hash + '\n';
                    });

                    fs.writeFileSync(path.join(__dirname, `../../output/hashes-${organization.sources[0]}.csv`), data);
                });

                let summary = this.getSummary();
                fs.writeFileSync(path.join(__dirname, `../../output/summary.csv`), summary);

                next();
            },
        ], next);
    }

    swap(next) {
        console.log('Starting swap');
        async.forever((next) => {
            let success = false;

            let owedOrganizations = this.getSortedListOfOwedOrganizations();
            let givingOrganizations = this.getListOfGivingOrganizations();

            _.each(owedOrganizations, (owedOrganization) => {
                // Find the most common submission
                let mostCommonSubmission;
                let mostCommonSubmissionOwner;
                _.each(givingOrganizations, (givingOrganization) => {
                    let submission = owedOrganization.requestSubmission({
                        from: givingOrganization,
                        given: this.given,
                    });

                    if (
                        submission
                        &&
                        (
                            !mostCommonSubmission
                            ||
                            mostCommonSubmission.eligible.length > submission.eligible.length
                        )
                    ) {
                        mostCommonSubmission = submission;
                        mostCommonSubmissionOwner = givingOrganization;
                    }
                });

                if (mostCommonSubmission) {
                    mostCommonSubmissionOwner.giveSubmission({
                        given: this.given,
                        submission: mostCommonSubmission,
                        to: owedOrganization,
                    });

                    success = true;
                }

                // If there was a match, break the loop
                if (success) {
                    return false;
                }
            });

            next(!success);
        }, () => {
            console.log('Trading has completed');
            next();
        });
    }

    distributeUnsourcedSubmissions(next) {
        console.log('Distributing unsourced submissions');
        let validOrganizations = _.filter(this.organizations, (organization) => !organization.sacrificing);

        async.forever((next) => {
            // Check if every organization has bounced
            if (_.isEmpty(validOrganizations)) {
                next(1);
                return;
            }

            // Find the organization who has taken the least free submissions
            let organization = _.min(validOrganizations, organization => organization.received.length / organization.sourced.length);

            // Stop when an organization has been repayed
            if (organization.received.length >= organization.sourced.length) {
                _.pull(validOrganizations, organization);
                next();
                return;
            }

            let submission = organization.requestSubmission({
                free: true,
                given: this.given,
            });

            if (!submission) {
                _.pull(validOrganizations, organization);
                next();
                return;
            }

            organization.takeFreeSubmission({
                given: this.given,
                submission: submission,
            });

            next();
        }, (err) => {
            next();
        });
    }

    getSwapCount() {
        return _.sum(this.organizations, (organization) => {
            if (organization.sacrificing) {
                return 0;
            }

            return organization.received.length;
        });
    }

    getSummary() {
        let summary = 'Organization,Owed,Received From Swap,Received From Sacrifice,Received Total\n';
        _.each(this.organizations, (organization) => {
            if (organization.sacrificing) {
                return;
            }

            let keyCount = organization.received.length;
            summary += `${organization.name},${organization.sourced.length},${keyCount - organization.freeCount},${organization.freeCount},${keyCount}\n`;
        });

        return summary;
    }

    getListOfGivingOrganizations() {
        return _.filter(this.organizations, (organization) => {
            if (organization.sacrificing) {
                return false;
            }

            return organization.given.length <= organization.received.length;
        });
    }

    getSortedListOfOwedOrganizations() {
        return _.filter(this.organizations, (organization) => {
            if (organization.sacrificing) {
                return false;
            }

            return (
                organization.given.length >= organization.received.length
            );
        }).sort((a, b) => {
            // Sort those who have given more than they've received first
            let scoreA = a.given.length - a.received.length;
            let scoreB = b.given.length - b.received.length;

            // Sort those who have more unpayed sourced actions first
            if (scoreA === scoreB) {
                scoreA = a.sourced.length - a.received.length;
                scoreB = b.sourced.length - b.received.length;
            }

            return scoreB - scoreA;
        });
    }

}
<|endoftext|>