<commit_before>/*
 * CAMXES.JS POSTPROCESSOR
 * Created by Ilmen (ilmen.pokebip <at> gmail.com) on 2013-08-16.
 * Last change: 2016-09-06.
 *
 * Entry point: camxes_postprocessing(input, mode)
 * Arguments:
 *    -- input: [array] camxes' parse tree output
 *    -- mode:  [number] output mode flag
 *         If mode > 7, displaying spaces is enabled and mode's value is
 *         truncated so mode <= 7. Then, depending on the value of mode,
 *         the following options are set:
 *         0 = Raw output (no change)
 *         1 = Condensed
 *         2 = Prettified
 *         3 = Prettified + selma'o
 *         4 = Prettified + selma'o + bridi parts
 *         5 = Prettified - famyma'o
 *         6 = Prettified - famyma'o + selma'o
 *         7 = Prettified - famyma'o + selma'o + bridi parts
 *
 * Return value:
 *       [string] postprocessed version of camxes' output
 */

/*
 * Function list:
 *   -- camxes_postprocessing(text, mode)
 *   -- new_postprocessor(input, no_morpho, with_selmaho, with_terminator)
 *   -- prune_unwanted_nodes(tree, is_wanted_node)
 *   -- prefix_wordclass(tree, replacements)
 *   -- remove_morphology(pt)
 *   -- is_target_node(n)
 *   -- join_expr(n)
 *   -- among(v, s)
 *   -- is_selmaho(v)
 *   -- prettify_brackets(str)
 *   -- str_print_uint(val, charset)
 *   -- str_replace(str, pos, len, sub)
 *   -- chr_check(chr, list)
 *   -- is_string(v)
 *   -- is_array(v)
 */

if (typeof alert !== 'function')
    alert = console.log; // For Node.js

/*
 * Version of transition between the older string processing and the newer
 * parse tree processing.
 * The below function's content is temporary and allows choosing which of the
 * two postprocessor (the older, the newer or even both) to use.
 * If the new postprocessor proves satisfactory, the older postprocessor's code
 * will be entirely removed.
 */
function camxes_postprocessing(input, mode) {
    if (!is_array(input))
        return "Postprocessor error: invalid input type for the first argument. "
             + "It should be of type 'array', but the argument given is of type '" + typeof input + "'."
             + (is_string(input) ? "\n\nThe new postprocessor doesn't allow anymore string inputs. "
             + "Please check the parse tree produced by the parser hasn't been converted to string "
             + "before being passed to the postprocessor." : "");
    var with_spaces = mode & 8;
    var without_morphology = !(mode & 16);
    mode = mode % 8;
    var with_selmaho = (mode != 2 && mode != 5);
    var with_nodes_labels = (mode == 4 || mode == 7);
    var without_terminator = (mode >= 5);
    if (without_morphology)
        input = remove_morphology(input); // Deleting morphology nodes.
    var output;
    if (mode <= 1) {
        output = JSON.stringify(input, undefined, mode == 0 ? 2 : 0);
    } else {
        input = new_postprocessor(input, without_morphology, with_spaces,
                                  with_selmaho, !without_terminator);
        output = JSON.stringify(input);
        output = output.replace(/\"/gm, "");
        output = output.replace(/,/gm, " ");
    }
    // Replacing "spaces" with "_":
    output = output.replace(/([ \[\],])(initial_)?spaces(?=[ \[\],])/gm, "$1_");
    // Bracket prettification:
    output = prettify_brackets(output);
	return output;
}

// ====== NEW POSTPROCESSOR ====== //

function new_postprocessor(input, no_morpho, with_spaces, with_selmaho, with_terminator) {
    var filter;
    var wanted_nodes = with_spaces ? ["initial_spaces", "dot_star"] : ["dot_star"];
    if (no_morpho) {
        filter = function (v,b) { return (with_selmaho ?
                  among(v, wanted_nodes.concat(["cmevla", "gismu", "lujvo", "fuhivla"]))
                  || (is_selmaho(v) && (with_terminator || !b))
                  : among(v, wanted_nodes)
                  || (is_selmaho(v) && b && with_terminator)); };
    } else {
        filter = function (v,b) { return among(v, wanted_nodes) ||
                  (with_selmaho ? (is_selmaho(v) && (with_terminator || !b))
                  : is_selmaho(v) && b && with_terminator); };
    }
    input = prune_unwanted_nodes(input, filter);
    if (input === null) return [];
    if (with_selmaho && no_morpho) {
        var replacements = [["cmene", "C"], ["cmevla", "C"], ["gismu", "G"],
                            ["lujvo", "L"], ["fuhivla", "Z"]];
        input = prefix_wordclass(input, replacements);
        if (is_string(input)) input = [input];
    }
    return input;
}

function prune_unwanted_nodes(tree, is_wanted_node) {
    if (is_string(tree)) return tree;
    if (!is_array(tree)) throw "ERR";
    if (tree.length == 0) return null;
    var no_label = is_array(tree[0]);
    var k = 0;
    var i = no_label ? 0 : 1;
    while (i < tree.length) {
        tree[i] = prune_unwanted_nodes(tree[i], is_wanted_node);
        if (tree[i]) {
            k++;
            i++;
        } else tree.splice(i, 1);
    }
    if (!no_label) {
        if (!is_wanted_node(tree[0], tree.length == 1)) tree.splice(0, 1);
        else k++;
    }
    if (k == 1) return tree[0];
    else return (k > 0) ? tree : null;
}

function prefix_wordclass(tree, replacements) {
    if (tree.length == 2 && is_string(tree[0]) && is_string(tree[1])) {
        var i = 0;
        while (i < replacements.length) {
            if (tree[0] == replacements[i][0]) {
                tree[0] = replacements[i][1];
                break;
            }
            i++;
        }
        return tree[0] + ':' + tree[1];
    }
    var i = 0;
    while (i < tree.length) {
        if (is_array(tree[i]))
            tree[i] = prefix_wordclass(tree[i], replacements);
        i++;
    }
    return tree;
}

// ====== MORPHOLOGY REMOVAL ====== //

/*
 * remove_morphology(parse_tree)
 *
 * This function takes a parse tree, and joins the expressions of the following
 * nodes:
 * "cmevla", "gismu_2", "lujvo", "fuhivla", "spaces"
 * as well as any selmaho node (e.g. "KOhA").
 *
 * (This is essentially a copy of process_parse_tree.js.)
 */

function remove_morphology(pt) {
    if (pt.length < 1) return [];
    var i;
    /* Sometimes nodes have no label and have instead an array as their first
       element. */
    if (is_array(pt[0])) i = 0;
    else { // The first element is a label (node name).
        // Let's check if this node is a candidate for our pruning.
        if (is_target_node(pt)) {
            /* We join recursively all the terminal elements (letters) in this
             * node and its child nodes, and put the resulting string in the #1
             * slot of the array; afterwards we delete all the remaining elements
             * (their terminal values have been concatenated into pt[1]). */
            pt[1] = join_expr(pt);
            // If pt[1] contains an empty string, let's delete it as well:
            pt.splice((pt[1] == "") ? 1 : 2);
            return pt;
        }
        i = 1;
    }
    /* If we've reached here, then this node is not a target for pruning, so let's
       do recursion into its child nodes. */
    while (i < pt.length) {
        remove_morphology(pt[i]);
        i++;
    }
    return pt;
}

/* Checks whether the argument node is a target for pruning. */
function is_target_node(n) {
    return (among(n[0], ["cmevla", "gismu", "lujvo", "fuhivla", "initial_spaces", "ga_clause", "gu_clause"])
            || is_selmaho(n[0]));
}

/* This function returns the string resulting from the recursive concatenation of
 * all the leaf elements of the parse tree argument (except node names). */
function join_expr(n) {
    if (n.length < 1) return "";
    var s = "";
    var i = is_array(n[0]) ? 0 : 1;
    while (i < n.length) {
        s += is_string(n[i]) ? n[i] : join_expr(n[i]);
        i++;
    }
    return s;
}

function among(v, s) {
    var i = 0;
    while (i < s.length) if (s[i++] == v) return true;
    return false;
}

function is_selmaho(v) {
    if (!is_string(v)) return false;
    return (0 == v.search(/^[IUBCDFGJKLMNPRSTVXZ]?([AEIOUY]|(AI|EI|OI|AU))(h([AEIOUY]|(AI|EI|OI|AU)))*$/g));
}

/* ================== */
/* ===  Routines  === */
/* ================== */

function prettify_brackets(str) {
	var open_brackets = ["(", "[", "{", "<"];
	var close_brackets = [")", "]", "}", ">"];
	var brackets_number = 4;
//	var numset = ['0','1','2','3','4','5','6','7','8','9'];
	var numset = ['\u2070','\u00b9','\u00b2','\u00b3','\u2074',
	              '\u2075','\u2076','\u2077','\u2078','\u2079'];
	var i = 0;
	var floor = 0;
	while (i < str.length) {
		if (str[i] == '[') {
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, open_brackets[n] + num);
			floor++;
		} else if (str[i] == ']') {
			floor--;
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, num + close_brackets[n]);
		}
		i++;
	}
	return str;
}

function str_print_uint(val, charset) {
	// 'charset' must be a character array.
	var radix = charset.length;
	var str = "";
	val -= val % 1;  // No float allowed
	while (val >= 1) {
		str = charset[val % radix] + str;
		val /= radix;
		val -= val % 1;
	}
	return str;
}

function str_replace(str, pos, len, sub) {
	if (pos < str.length) {
		if (pos + len >= str.length) len -= pos + len - str.length;
		return str.substring(0, pos) + sub + str.substring(pos + len);
	} else return str;
}

function chr_check(chr, list) {
	var i = 0;
	if (!is_string(list)) return false;
	do if (chr == list[i]) return true; while (i++ < list.length);
	return false;
} // Currently unused.

function is_string(v) {
    // return $.type(v) === "string";
    return Object.prototype.toString.call(v) === '[object String]';
}

function is_array(v) {
    // return $.type(v) === "array";
    return Object.prototype.toString.call(v) === '[object Array]';
}

if (typeof module !== 'undefined')
    module.exports.postprocessing = camxes_postprocessing;

<commit_msg>camxes_postproc: If the input is a string, try applying JSON.parse() to it for getting back an array. This will allow compatibility with older interfaces to the JS Camxes.<commit_after>/*
 * CAMXES.JS POSTPROCESSOR
 * Created by Ilmen (ilmen.pokebip <at> gmail.com) on 2013-08-16.
 * Last change: 2016-09-06.
 *
 * Entry point: camxes_postprocessing(input, mode)
 * Arguments:
 *    -- input: [array] camxes' parse tree output
 *    -- mode:  [number] output mode flag
 *         If mode > 7, displaying spaces is enabled and mode's value is
 *         truncated so mode <= 7. Then, depending on the value of mode,
 *         the following options are set:
 *         0 = Raw output (no change)
 *         1 = Condensed
 *         2 = Prettified
 *         3 = Prettified + selma'o
 *         4 = Prettified + selma'o + bridi parts
 *         5 = Prettified - famyma'o
 *         6 = Prettified - famyma'o + selma'o
 *         7 = Prettified - famyma'o + selma'o + bridi parts
 *
 * Return value:
 *       [string] postprocessed version of camxes' output
 */

/*
 * Function list:
 *   -- camxes_postprocessing(text, mode)
 *   -- new_postprocessor(input, no_morpho, with_selmaho, with_terminator)
 *   -- prune_unwanted_nodes(tree, is_wanted_node)
 *   -- prefix_wordclass(tree, replacements)
 *   -- remove_morphology(pt)
 *   -- is_target_node(n)
 *   -- join_expr(n)
 *   -- among(v, s)
 *   -- is_selmaho(v)
 *   -- prettify_brackets(str)
 *   -- str_print_uint(val, charset)
 *   -- str_replace(str, pos, len, sub)
 *   -- chr_check(chr, list)
 *   -- is_string(v)
 *   -- is_array(v)
 */

if (typeof alert !== 'function')
    alert = console.log; // For Node.js

/*
 * Version of transition between the older string processing and the newer
 * parse tree processing.
 * The below function's content is temporary and allows choosing which of the
 * two postprocessor (the older, the newer or even both) to use.
 * If the new postprocessor proves satisfactory, the older postprocessor's code
 * will be entirely removed.
 */
function camxes_postprocessing(input, mode) {
    if (is_string(input)) input = JSON.parse(input);
    if (!is_array(input))
        return "Postprocessor error: invalid input type for the first argument. "
             + "It should be of type 'array', but the argument given is of type '" + typeof input + "'."
             + (is_string(input) ? "\n\nThe new postprocessor doesn't allow anymore string inputs. "
             + "Please check the parse tree produced by the parser hasn't been converted to string "
             + "before being passed to the postprocessor." : "");
    var with_spaces = mode & 8;
    var without_morphology = !(mode & 16);
    mode = mode % 8;
    var with_selmaho = (mode != 2 && mode != 5);
    var with_nodes_labels = (mode == 4 || mode == 7);
    var without_terminator = (mode >= 5);
    if (without_morphology)
        input = remove_morphology(input); // Deleting morphology nodes.
    var output;
    if (mode <= 1) {
        output = JSON.stringify(input, undefined, mode == 0 ? 2 : 0);
    } else {
        input = new_postprocessor(input, without_morphology, with_spaces,
                                  with_selmaho, !without_terminator);
        output = JSON.stringify(input);
        output = output.replace(/\"/gm, "");
        output = output.replace(/,/gm, " ");
    }
    // Replacing "spaces" with "_":
    output = output.replace(/([ \[\],])(initial_)?spaces(?=[ \[\],])/gm, "$1_");
    // Bracket prettification:
    output = prettify_brackets(output);
	return output;
}

// ====== NEW POSTPROCESSOR ====== //

function new_postprocessor(input, no_morpho, with_spaces, with_selmaho, with_terminator) {
    var filter;
    var wanted_nodes = with_spaces ? ["initial_spaces", "dot_star"] : ["dot_star"];
    if (no_morpho) {
        filter = function (v,b) { return (with_selmaho ?
                  among(v, wanted_nodes.concat(["cmevla", "gismu", "lujvo", "fuhivla"]))
                  || (is_selmaho(v) && (with_terminator || !b))
                  : among(v, wanted_nodes)
                  || (is_selmaho(v) && b && with_terminator)); };
    } else {
        filter = function (v,b) { return among(v, wanted_nodes) ||
                  (with_selmaho ? (is_selmaho(v) && (with_terminator || !b))
                  : is_selmaho(v) && b && with_terminator); };
    }
    input = prune_unwanted_nodes(input, filter);
    if (input === null) return [];
    if (with_selmaho && no_morpho) {
        var replacements = [["cmene", "C"], ["cmevla", "C"], ["gismu", "G"],
                            ["lujvo", "L"], ["fuhivla", "Z"]];
        input = prefix_wordclass(input, replacements);
        if (is_string(input)) input = [input];
    }
    return input;
}

function prune_unwanted_nodes(tree, is_wanted_node) {
    if (is_string(tree)) return tree;
    if (!is_array(tree)) throw "ERR";
    if (tree.length == 0) return null;
    var no_label = is_array(tree[0]);
    var k = 0;
    var i = no_label ? 0 : 1;
    while (i < tree.length) {
        tree[i] = prune_unwanted_nodes(tree[i], is_wanted_node);
        if (tree[i]) {
            k++;
            i++;
        } else tree.splice(i, 1);
    }
    if (!no_label) {
        if (!is_wanted_node(tree[0], tree.length == 1)) tree.splice(0, 1);
        else k++;
    }
    if (k == 1) return tree[0];
    else return (k > 0) ? tree : null;
}

function prefix_wordclass(tree, replacements) {
    if (tree.length == 2 && is_string(tree[0]) && is_string(tree[1])) {
        var i = 0;
        while (i < replacements.length) {
            if (tree[0] == replacements[i][0]) {
                tree[0] = replacements[i][1];
                break;
            }
            i++;
        }
        return tree[0] + ':' + tree[1];
    }
    var i = 0;
    while (i < tree.length) {
        if (is_array(tree[i]))
            tree[i] = prefix_wordclass(tree[i], replacements);
        i++;
    }
    return tree;
}

// ====== MORPHOLOGY REMOVAL ====== //

/*
 * remove_morphology(parse_tree)
 *
 * This function takes a parse tree, and joins the expressions of the following
 * nodes:
 * "cmevla", "gismu_2", "lujvo", "fuhivla", "spaces"
 * as well as any selmaho node (e.g. "KOhA").
 *
 * (This is essentially a copy of process_parse_tree.js.)
 */

function remove_morphology(pt) {
    if (pt.length < 1) return [];
    var i;
    /* Sometimes nodes have no label and have instead an array as their first
       element. */
    if (is_array(pt[0])) i = 0;
    else { // The first element is a label (node name).
        // Let's check if this node is a candidate for our pruning.
        if (is_target_node(pt)) {
            /* We join recursively all the terminal elements (letters) in this
             * node and its child nodes, and put the resulting string in the #1
             * slot of the array; afterwards we delete all the remaining elements
             * (their terminal values have been concatenated into pt[1]). */
            pt[1] = join_expr(pt);
            // If pt[1] contains an empty string, let's delete it as well:
            pt.splice((pt[1] == "") ? 1 : 2);
            return pt;
        }
        i = 1;
    }
    /* If we've reached here, then this node is not a target for pruning, so let's
       do recursion into its child nodes. */
    while (i < pt.length) {
        remove_morphology(pt[i]);
        i++;
    }
    return pt;
}

/* Checks whether the argument node is a target for pruning. */
function is_target_node(n) {
    return (among(n[0], ["cmevla", "gismu", "lujvo", "fuhivla", "initial_spaces", "ga_clause", "gu_clause"])
            || is_selmaho(n[0]));
}

/* This function returns the string resulting from the recursive concatenation of
 * all the leaf elements of the parse tree argument (except node names). */
function join_expr(n) {
    if (n.length < 1) return "";
    var s = "";
    var i = is_array(n[0]) ? 0 : 1;
    while (i < n.length) {
        s += is_string(n[i]) ? n[i] : join_expr(n[i]);
        i++;
    }
    return s;
}

function among(v, s) {
    var i = 0;
    while (i < s.length) if (s[i++] == v) return true;
    return false;
}

function is_selmaho(v) {
    if (!is_string(v)) return false;
    return (0 == v.search(/^[IUBCDFGJKLMNPRSTVXZ]?([AEIOUY]|(AI|EI|OI|AU))(h([AEIOUY]|(AI|EI|OI|AU)))*$/g));
}

/* ================== */
/* ===  Routines  === */
/* ================== */

function prettify_brackets(str) {
	var open_brackets = ["(", "[", "{", "<"];
	var close_brackets = [")", "]", "}", ">"];
	var brackets_number = 4;
//	var numset = ['0','1','2','3','4','5','6','7','8','9'];
	var numset = ['\u2070','\u00b9','\u00b2','\u00b3','\u2074',
	              '\u2075','\u2076','\u2077','\u2078','\u2079'];
	var i = 0;
	var floor = 0;
	while (i < str.length) {
		if (str[i] == '[') {
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, open_brackets[n] + num);
			floor++;
		} else if (str[i] == ']') {
			floor--;
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, num + close_brackets[n]);
		}
		i++;
	}
	return str;
}

function str_print_uint(val, charset) {
	// 'charset' must be a character array.
	var radix = charset.length;
	var str = "";
	val -= val % 1;  // No float allowed
	while (val >= 1) {
		str = charset[val % radix] + str;
		val /= radix;
		val -= val % 1;
	}
	return str;
}

function str_replace(str, pos, len, sub) {
	if (pos < str.length) {
		if (pos + len >= str.length) len -= pos + len - str.length;
		return str.substring(0, pos) + sub + str.substring(pos + len);
	} else return str;
}

function chr_check(chr, list) {
	var i = 0;
	if (!is_string(list)) return false;
	do if (chr == list[i]) return true; while (i++ < list.length);
	return false;
} // Currently unused.

function is_string(v) {
    // return $.type(v) === "string";
    return Object.prototype.toString.call(v) === '[object String]';
}

function is_array(v) {
    // return $.type(v) === "array";
    return Object.prototype.toString.call(v) === '[object Array]';
}

if (typeof module !== 'undefined')
    module.exports.postprocessing = camxes_postprocessing;

<|endoftext|>


<commit_before>var assert = require("assert"),
    should = require('should'),
    child_process = require('child_process');

describe('CLI', function () {
  describe('#help', function () {
    it('should return help instructions', function (done) {

      var command = 'sass-lint -h';

      child_process.exec(command, function(err, stdout, stderr) {
        if (err) return done(err);
        assert(stdout.indexOf('Usage') > 0);
        done(null);
      });

    });
  });

  describe('#version', function () {
    it('should return a version', function (done) {

      var command = 'sass-lint -V';

      child_process.exec(command, function(err, stdout, stderr) {
        if (err) return done(err);
        stdout.should.match(/^[0-9]+.[0-9]+(.[0-9]+)?/);
        done(null);
      });

    });
  });
});
<commit_msg>Use single quotes on require<commit_after>var assert = require('assert'),
    should = require('should'),
    child_process = require('child_process');

describe('CLI', function () {
  describe('#help', function () {
    it('should return help instructions', function (done) {

      var command = 'sass-lint -h';

      child_process.exec(command, function(err, stdout, stderr) {
        if (err) return done(err);
        assert(stdout.indexOf('Usage') > 0);
        done(null);
      });

    });
  });

  describe('#version', function () {
    it('should return a version', function (done) {

      var command = 'sass-lint -V';

      child_process.exec(command, function(err, stdout, stderr) {
        if (err) return done(err);
        stdout.should.match(/^[0-9]+.[0-9]+(.[0-9]+)?/);
        done(null);
      });

    });
  });
});
<|endoftext|>


<commit_before>'use strict';

// Submission ID, S7755084
// Common Name, Black-bellied Whistling-Duck
// Scientific Name, Dendrocygna autumnalis
// Taxonomic Order, 215
// Count, X
// State/Province, US-TX
// County, Cameron
// Location, Brownsville
// Latitude, 25.911388
// Longitude, -97.4904876
// Date, 04-17-2004
// Time,
// Protocol, eBird - Casual Observation
// Duration (Min),
// All Obs Reported,
// Distance Traveled (km),
// Area Covered (ha),
// Number of Observers,
// Breeding Code,
// Species Comments,
// Checklist Comments

var SightingList = function (inRows, inPhotos) {
	this.rows = [];
	this._uniqueValuesCache = {};
	this.rowsByYear = {};
	this.rowsByMonth = { '01': [], '02': [], '03': [], '04': [], '05': [], '06': [], '07': [], '08': [], '09': [], '10': [], '11': [], '12': [] };
	this._speciesByDate = {};
	this._earliestRowByCommonName = null;
	this.earliestDateObject = null;
	this.latestDateObject = null;
	this.dates = [];
	this.dateObjects = [];
	this.photos = inPhotos;

	if (inRows) {
		if (inRows instanceof Array) {
			this.addRows(inRows);
		} else {
			throw new Error('not an array');
		}
	}
};

SightingList.prototype.initialize = function(inData) {
	this.rows = inData.rows;
	this._uniqueValuesCache = inData._uniqueValuesCache;
	this.rowsByYear = inData.rowsByYear;
	this.rowsByMonth = inData.rowsByMonth;
	this._speciesByDate = inData.speciesByDate;
	this._earliestRowByCommonName = inData._earliestRowByCommonName;
	this.earliestDateObject = inData.earliestDateObject;
	this.latestDateObject = inData.latestDateObject;
	this.dates = inData.dates;
	// TODO: this is not a list of date objects!
	this.dateObjects = inData.dateObjects;
	this.photos = inData.photos;
};

SightingList.prototype.setGlobalIDs = function() {
	for (var index = 0; index < this.rows.length; index++) {
		var sighting = this.rows[index];
		sighting.id = index;
	}
};

SightingList.prototype.addRows = function(inRows) {
	for (var index = 0; index < inRows.length; index++) {
		var sighting = inRows[index];

		if (sighting['Date']) {
			// Parse the date
			var pieces = sighting['Date'].split('-');

			// order the pieces in a sensible way
			var fixedDateString = [pieces[0], '/', pieces[1], '/', pieces[2]].join('');

			// create and save the new dat
			var newDate = new Date(fixedDateString);
			sighting['DateObject'] = newDate;

			if (this.dates.indexOf(sighting['Date']) < 0) {
				this.dates.push(sighting['Date']);
				this.dateObjects.push(newDate);
			}

			if (this.earliestDateObject == null || newDate < this.earliestDateObject) {
				this.earliestDateObject = newDate;
			}

			if (this.latestDateObject == null || newDate > this.latestDateObject) {
				this.latestDateObject = newDate;
			}

			if (! this.rowsByYear[pieces[2]]) {
				this.rowsByYear[pieces[2]] = [];
			}
			this.rowsByYear[pieces[2]].push(sighting);

			if (! this.rowsByMonth[pieces[0]]) {
				this.rowsByMonth[pieces[0]] = [];
			}
			this.rowsByMonth[pieces[0]].push(sighting);

		} else {
			console.log('ERROR SIGHTING HAS NO DATE', index, JSON.stringify(sighting));
		}
	}

	this.rows = this.rows.concat(inRows);

	this.dateObjects.sort(function(a, b) { return b - a; });

	// TODO: this is probably unnecessary sort!
	this.rows.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });
};

SightingList.prototype.earliestDateObject = function() {
	return this.earliestDateObject;
};

SightingList.prototype.latestDateObject = function() {
	return this.latestDateObject;
};

SightingList.prototype.filter = function(filterFunc) {
	return this.rows.filter(filterFunc);
};

SightingList.prototype.length = function() {
	return this.rows.length;
};

SightingList.prototype.byYear = function() {
	return this.rowsByYear;
};

SightingList.prototype.byMonth = function() {
	return [
		this.rowsByMonth['01'],
		this.rowsByMonth['02'],
		this.rowsByMonth['03'],
		this.rowsByMonth['04'],
		this.rowsByMonth['05'],
		this.rowsByMonth['06'],
		this.rowsByMonth['07'],
		this.rowsByMonth['08'],
		this.rowsByMonth['09'],
		this.rowsByMonth['10'],
		this.rowsByMonth['11'],
		this.rowsByMonth['12'],
	];
};

SightingList.prototype.createIndex = function() {
	var tmpIndex = lunr(function () {
	    this.field('location');
	    this.field('common');
	    this.field('county');
	    this.field('trip');
	    this.field('scientific');
	    this.ref('id');
	});

	for (var index = 0; index < this.rows.length; index++) {
		var aValue = this.rows[index];

		tmpIndex.add({
			location: aValue['Location'],
			county: aValue['County'],
			common: aValue['Common Name'],
			trip: gCustomDayNames[aValue['Date']],
			scientific: aValue['Scientific Name'],
			id: index,
		});
	}

	return tmpIndex;
};

SightingList.prototype.getUniqueValues = function(fieldName) {
	if (this._uniqueValuesCache[fieldName]) {
		console.log('returning cached unique values for', fieldName);
	} else {
		console.log('computing unique values for', fieldName);
		var tmpValues = [];
		for (var index = 0; index < this.rows.length; index++) {
			var aValue = this.rows[index][fieldName];
			if (tmpValues.indexOf(aValue) < 0) {
				tmpValues.push(aValue);
			}
		}
		this._uniqueValuesCache[fieldName] = tmpValues;
	}

	return this._uniqueValuesCache[fieldName];
};

SightingList.prototype.getLocationHierarchy = function() {
	var provinces = {};

	for (var index = 0; index < this.rows.length; index++) {
		var aSighting = this.rows[index];
		var province = aSighting['State/Province'];
		var county = aSighting['County'];
		var location = aSighting['Location'];

		if (! provinces[province]) {
			provinces[province] = {};
		}

		if (! provinces[province][county]) {
			provinces[province][county] = [];
		}

		if (provinces[province][county].indexOf(location) < 0) {
			provinces[province][county].push(location);
		}
	}

	return provinces;
};

SightingList.prototype.getSpeciesByDate = function() {
	console.log('computing speciesByDate');

	for (var index = 0; index < this.rows.length; index++) {
		var sighting = this.rows[index];

		if (! this._speciesByDate[sighting['Date']]) {
			this._speciesByDate[sighting['Date']] = {
				commonNames: [],
				dateObject: sighting['DateObject'],
			};
		}
		if (this._speciesByDate[sighting['Date']].commonNames.indexOf(sighting['Common Name']) < 0) {
			this._speciesByDate[sighting['Date']].commonNames.push(sighting['Common Name']);
		}
	};

	return this._speciesByDate;
};

SightingList.prototype.getEarliestByCommonName = function() {
	console.log('computing earliestByCommonName');

	this._earliestRowByCommonName = {};

	for (var index = 0; index < this.rows.length; index++) {
		var sighting = this.rows[index];

		if (gOmittedCommonNames.indexOf(sighting['Common Name']) < 0) {
			if (! this._earliestRowByCommonName[sighting['Common Name']]) {
				this._earliestRowByCommonName[sighting['Common Name']] = sighting;
			} else if (sighting.DateObject < this._earliestRowByCommonName[sighting['Common Name']].DateObject) {
				this._earliestRowByCommonName[sighting['Common Name']] = sighting;
			}
		} else {
			console.log('omit', sighting['Common Name']);
		}
	};

	return this._earliestRowByCommonName;
};

if (typeof module != 'undefined') {
	module.exports = SightingList;
}
<commit_msg>fix date objects<commit_after>'use strict';

// Submission ID, S7755084
// Common Name, Black-bellied Whistling-Duck
// Scientific Name, Dendrocygna autumnalis
// Taxonomic Order, 215
// Count, X
// State/Province, US-TX
// County, Cameron
// Location, Brownsville
// Latitude, 25.911388
// Longitude, -97.4904876
// Date, 04-17-2004
// Time,
// Protocol, eBird - Casual Observation
// Duration (Min),
// All Obs Reported,
// Distance Traveled (km),
// Area Covered (ha),
// Number of Observers,
// Breeding Code,
// Species Comments,
// Checklist Comments

var SightingList = function (inRows, inPhotos) {
	this.rows = [];
	this._uniqueValuesCache = {};
	this.rowsByYear = {};
	this.rowsByMonth = { '01': [], '02': [], '03': [], '04': [], '05': [], '06': [], '07': [], '08': [], '09': [], '10': [], '11': [], '12': [] };
	this._speciesByDate = {};
	this._earliestRowByCommonName = null;
	this.earliestDateObject = null;
	this.latestDateObject = null;
	this.dates = [];
	this.dateObjects = [];
	this.photos = inPhotos;

	if (inRows) {
		if (inRows instanceof Array) {
			this.addRows(inRows);
		} else {
			throw new Error('not an array');
		}
	}
};

SightingList.prototype.initialize = function(inData) {
	this.rows = inData.rows;
	this._uniqueValuesCache = inData._uniqueValuesCache;
	this.rowsByYear = inData.rowsByYear;
	this.rowsByMonth = inData.rowsByMonth;
	this._speciesByDate = inData.speciesByDate;
	this._earliestRowByCommonName = inData._earliestRowByCommonName;
	this.earliestDateObject = new Date(inData.earliestDateObject);
	this.latestDateObject = new Date(inData.latestDateObject);
	this.dates = inData.dates;
	this.dateObjects = inData.dateObjects;
	this.photos = inData.photos;

	// fix the dates
	for (var index = 0; index < this.dateObjects.length; index++) {
		this.dateObjects[index] = new Date(this.dateObjects[index]);
	}
};

SightingList.prototype.setGlobalIDs = function() {
	for (var index = 0; index < this.rows.length; index++) {
		var sighting = this.rows[index];
		sighting.id = index;
	}
};

SightingList.prototype.addRows = function(inRows) {
	for (var index = 0; index < inRows.length; index++) {
		var sighting = inRows[index];

		if (sighting['Date']) {
			// Parse the date
			var pieces = sighting['Date'].split('-');

			// order the pieces in a sensible way
			var fixedDateString = [pieces[0], '/', pieces[1], '/', pieces[2]].join('');

			// create and save the new dat
			var newDate = new Date(fixedDateString);
			sighting['DateObject'] = newDate;

			if (this.dates.indexOf(sighting['Date']) < 0) {
				this.dates.push(sighting['Date']);
				this.dateObjects.push(newDate);
			}

			if (this.earliestDateObject == null || newDate < this.earliestDateObject) {
				this.earliestDateObject = newDate;
			}

			if (this.latestDateObject == null || newDate > this.latestDateObject) {
				this.latestDateObject = newDate;
			}

			if (! this.rowsByYear[pieces[2]]) {
				this.rowsByYear[pieces[2]] = [];
			}
			this.rowsByYear[pieces[2]].push(sighting);

			if (! this.rowsByMonth[pieces[0]]) {
				this.rowsByMonth[pieces[0]] = [];
			}
			this.rowsByMonth[pieces[0]].push(sighting);

		} else {
			console.log('ERROR SIGHTING HAS NO DATE', index, JSON.stringify(sighting));
		}
	}

	this.rows = this.rows.concat(inRows);

	this.dateObjects.sort(function(a, b) { return b - a; });

	// TODO: this is probably unnecessary sort!
	this.rows.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });
};

SightingList.prototype.earliestDateObject = function() {
	return this.earliestDateObject;
};

SightingList.prototype.latestDateObject = function() {
	return this.latestDateObject;
};

SightingList.prototype.filter = function(filterFunc) {
	return this.rows.filter(filterFunc);
};

SightingList.prototype.length = function() {
	return this.rows.length;
};

SightingList.prototype.byYear = function() {
	return this.rowsByYear;
};

SightingList.prototype.byMonth = function() {
	return [
		this.rowsByMonth['01'],
		this.rowsByMonth['02'],
		this.rowsByMonth['03'],
		this.rowsByMonth['04'],
		this.rowsByMonth['05'],
		this.rowsByMonth['06'],
		this.rowsByMonth['07'],
		this.rowsByMonth['08'],
		this.rowsByMonth['09'],
		this.rowsByMonth['10'],
		this.rowsByMonth['11'],
		this.rowsByMonth['12'],
	];
};

SightingList.prototype.createIndex = function() {
	var tmpIndex = lunr(function () {
	    this.field('location');
	    this.field('common');
	    this.field('county');
	    this.field('trip');
	    this.field('scientific');
	    this.ref('id');
	});

	for (var index = 0; index < this.rows.length; index++) {
		var aValue = this.rows[index];

		tmpIndex.add({
			location: aValue['Location'],
			county: aValue['County'],
			common: aValue['Common Name'],
			trip: gCustomDayNames[aValue['Date']],
			scientific: aValue['Scientific Name'],
			id: index,
		});
	}

	return tmpIndex;
};

SightingList.prototype.getUniqueValues = function(fieldName) {
	if (this._uniqueValuesCache[fieldName]) {
		console.log('returning cached unique values for', fieldName);
	} else {
		console.log('computing unique values for', fieldName);
		var tmpValues = [];
		for (var index = 0; index < this.rows.length; index++) {
			var aValue = this.rows[index][fieldName];
			if (tmpValues.indexOf(aValue) < 0) {
				tmpValues.push(aValue);
			}
		}
		this._uniqueValuesCache[fieldName] = tmpValues;
	}

	return this._uniqueValuesCache[fieldName];
};

SightingList.prototype.getLocationHierarchy = function() {
	var provinces = {};

	for (var index = 0; index < this.rows.length; index++) {
		var aSighting = this.rows[index];
		var province = aSighting['State/Province'];
		var county = aSighting['County'];
		var location = aSighting['Location'];

		if (! provinces[province]) {
			provinces[province] = {};
		}

		if (! provinces[province][county]) {
			provinces[province][county] = [];
		}

		if (provinces[province][county].indexOf(location) < 0) {
			provinces[province][county].push(location);
		}
	}

	return provinces;
};

SightingList.prototype.getSpeciesByDate = function() {
	console.log('computing speciesByDate');

	for (var index = 0; index < this.rows.length; index++) {
		var sighting = this.rows[index];

		if (! this._speciesByDate[sighting['Date']]) {
			this._speciesByDate[sighting['Date']] = {
				commonNames: [],
				dateObject: sighting['DateObject'],
			};
		}
		if (this._speciesByDate[sighting['Date']].commonNames.indexOf(sighting['Common Name']) < 0) {
			this._speciesByDate[sighting['Date']].commonNames.push(sighting['Common Name']);
		}
	};

	return this._speciesByDate;
};

SightingList.prototype.getEarliestByCommonName = function() {
	console.log('computing earliestByCommonName');

	this._earliestRowByCommonName = {};

	for (var index = 0; index < this.rows.length; index++) {
		var sighting = this.rows[index];

		if (gOmittedCommonNames.indexOf(sighting['Common Name']) < 0) {
			if (! this._earliestRowByCommonName[sighting['Common Name']]) {
				this._earliestRowByCommonName[sighting['Common Name']] = sighting;
			} else if (sighting.DateObject < this._earliestRowByCommonName[sighting['Common Name']].DateObject) {
				this._earliestRowByCommonName[sighting['Common Name']] = sighting;
			}
		} else {
			console.log('omit', sighting['Common Name']);
		}
	};

	return this._earliestRowByCommonName;
};

if (typeof module != 'undefined') {
	module.exports = SightingList;
}
<|endoftext|>


<commit_before>(function ($) {

   var UDBrains = function () {
      return new UDBrains.fn.init();
   }

   UDBrains.fn = UDBrains.prototype = {
      version: 2.0,
      reportURL: 'http://localhost:8989/',
      surroundings: {
         inside: false,
         position: [],
         map: [],
      },
      user: {
         name: "",
         id: 0
      },
      UI: {},
      init: function () {
         var udb = this;
         $(document).ready(function () {
            udb.populateSurroundings();
            udb.populateUser();
            udb.sendReport();
            $(udb).trigger('ready', [this]);
            udb.renderUI();
         });
         return this;
      },

      populateUser: function () {
         var playerInfo = $('.cp .gt');
         $.extend(this.user, {
            name:       playerInfo.find('a[href^=profile]').text(),
            id:         playerInfo.find('a[href^=profile]').attr('href').split('=')[1],
            alive:      playerInfo.text().search(/you are dead/) == -1 ? true : false,
            health:     playerInfo.text().match(/You have (\d+) Hit Points?/)[1],
            ap:         playerInfo.text().match(/You have (\d+) Action Points?/)[1],
            experience: playerInfo.text().match(/and (\d+) Experience Points?/)[1],
            inventory:  []
         });
         var udb = this;
         $('select[name=drop] option[value!=""]').each(function () {
            udb.user.inventory.push({
               id:   $(this).val(),
               name: $(this).text()
            });
         });

      },

      populateSurroundings: function () {
         var udb = this;
         this.surroundings.inside = this.isInside();
         $('table.c tr:has(td.b)').each(function (row) {
            udb.surroundings.map.push([]);
            $(this).find('td.b').each(function (col) {
               udb.surroundings.map[row].push({
                  element:          this,
                  coords:           udb.getCoordsFromMapTile(this),
                  zombies:          udb.getZombieCountFromMapTile(this),
                  survivors:        udb.getSurvivorsFromMapTile(this),
                  ruined:           udb.isMapTileRuined(this),
                  illuminated:      udb.isMapTileLit(this)
               });
               // Note the coordinates of our position in relation to surroundings.
               if(udb.isPositionElement(this))
                  udb.surroundings.position = udb.surroundings.map[row][udb.surroundings.map[row].length-1];
            });
            // Current position specific data.
            $.extend(udb.surroundings.position, {
               barricades: udb.getBarricadeLevel()
            });
         });
      },

      isPositionElement: function (elem) {
         // Position element has input with no form.
         return $(elem).is('td:has(>input)');
      },

      isInside: function () {
         //Check for the leave button to determine if we're inside a building.
         return ($('.gp form[action$=out]').length == 1);
      },

      isOutsideBuilding: function () {
         //Check for the enter button to see if we're outside a building.
         return ($('.gp form[action$=in]').length == 1);
      },

      isEmptyLot: function () {
         //Returns true if current tile is empty lot
         return (!this.isInside() && !this.isOutsideBuilding());
      },

      isMapTileRuined: function (elem) {
         //.mr = ruined or inside dark
         if(this.isPositionElement(elem)){
            return false;//fucking special cases
         } else {
            return $(elem).find('input[type=submit]').hasClass('mr');
         }
      },

      isMapTileLit: function (elem) {
         //.ml = lit tile
         //.mrl = ruined + powered
         var button = $(elem).find('input[type=submit]');
         return ( button.hasClass('ml') || button.hasClass('mrl') );
      },

      isHPDataAvailable: function () {
         return ( $('.gp .gt sub').length != 0 );
      },

      getCoordsFromMapTile: function (elem) {
         // Parse out the coordinates for the provided tile.
         var coords;
         if (this.isPositionElement(elem)) {
            // Player position has to be calculated from a nearby tile.
            coords = this.calculatePositionCoords(elem);
         } else {
            coords = this.parseCoords($(elem).find('input[type=hidden]').val());
         }
         return coords;
      },

      calculatePositionCoords: function (elem) {
         var locationTD = $('table.c td:has(>input)'); //Location TD always has an input without a form.
         var locationRow = locationTD.parent().find('td');
         var xOffset = 1;
         var offsetTDIndex = 0;
         if (locationRow.index(elem) == 0) {//We are at the left edge of the map.
            xOffset = -1;
            offsetTDIndex = 1;
         }
         var offset = this.parseCoords(
            // Get the coordinates of the tile to our left/right
            locationRow.eq(offsetTDIndex).find('input[type=hidden]').val()
         );
         return {
            x: offset.x + xOffset,
            y: offset.y
         }
      },

      parseCoords: function (coords) {
         coords = coords.split('-');
         return {
            x: parseInt(coords[0], 10),
            y: parseInt(coords[1], 10)
         }
      },

      getSurvivorsFromMapTile: function (elem) {
         //Returns an array of objects with survivor names and ids.
         var survivors = [];
         var survivorLinks = $(elem).find('a[href^=profile]');
         if (this.isPositionElement(elem)) {
            // If the query is for our current position we can provide a full list.
            survivorLinks = $('.gp .gt a');
         }
         var udb = this;
         survivorLinks.each(function (i) {
            survivors.push({
               name: $(this).text(),
               id:   $(this).attr('href').split('=')[1]
            })
            if (udb.isPositionElement(elem) && udb.isHPDataAvailable()) {
               survivors[i].hp = udb.getHPDataForSurvivor(survivors[i]);
            }
         });
         return survivors;
      },

      getHPDataForSurvivor: function (survivor) {
         var reg = new RegExp( survivor.name + "\\s\\((\\d+)HP\\)" );
         return $('.gp .gt').text().match(reg)[1];
      },

      getZombieCountFromMapTile: function (elem) {
         if($(elem).is('td:has(.fz)'))
            return parseInt($(elem).find('.fz').text().split(' ')[0], 10);
         else
            return 0;
      },

      getBarricadeLevel: function () {
         var reg = /The (building|doors to the street|building\'s doors) (has|have) been ([^\.]*(secured|barricaded|left wide open))[^\.]*./;
         if (this.isEmptyLot())
            var barricadeText = 'no building';
         else
            var barricadeText = $('.gp .gt').text().match(reg)[3];
         return this.barricadeLevels[barricadeText];
      },

      getLocationByCoord: function (locx, locy) {
         var location = false;
         $.each(this.surroundings, function () {
            $.each(this, function () {
               if (this.coords.x == locx && this.coords.y == locy)
                  location = this;
            });
         });
         return location;
      },

      sendReport: function () {
         $.ajax({
            type: "POST",
            url: this.reportURL,
            data: {data: JSON.stringify({user: this.user, surroundings: this.surroundings})},
            dataType: 'json',
            success: this.receiveData
         });
      },

      receiveData: function (data, status, xhr) {
         //placeholder
         console.log('xhr');
      },

      barricadeLevels: {
         'no building':                      0,
         'left wide open' :                  1,
         'secured' :                         2,
         'loosely barricaded' :              3,
         'lightly barricaded' :              4,
         'quite strongly barricaded' :       5,
         'very strongly barricaded' :        6,
         'heavily barricaded' :              7,
         'very heavily barricaded' :         8,
         'extremely heavily barricaded' :    9
      },

      renderUI: function () {
         for( ext in this.UI ) {
            this.UI[ext].init(this);
         }
      }

   }

   UDBrains.fn.init.prototype = UDBrains.fn;

   UDBrains = window.UDBrains = UDBrains();

   UDBrains.UI.ordersPane = {
      url: 'http://brains.somethingdead.com/orders/',
      init: function (udb) {
         var iframe = $('<iframe>').attr('id', 'orders').attr('src', this.url).css({
            width: '100%',
            height: '200px',
            border: '4px solid #445544'
         });
         var ordersLink = $('<a>').attr('href', '#orders').bind('click', function () {
            localStorage.ordersVisible = $('#orders').toggle().is(':visible');
         }).text('Click here to toggle orders.');
         $('.gp').append(ordersLink);
         $('.gp').append(iframe);
         if (localStorage.ordersVisible == "false")
            iframe.hide();

      }
   }

})(jQuery);<commit_msg>commented out sendreport<commit_after>(function ($) {

   var UDBrains = function () {
      return new UDBrains.fn.init();
   }

   UDBrains.fn = UDBrains.prototype = {
      version: 2.0,
      reportURL: 'http://localhost:8989/',
      surroundings: {
         inside: false,
         position: [],
         map: [],
      },
      user: {
         name: "",
         id: 0
      },
      UI: {},
      init: function () {
         var udb = this;
         $(document).ready(function () {
            udb.populateSurroundings();
            udb.populateUser();
            udb.sendReport();
            $(udb).trigger('ready', [this]);
            udb.renderUI();
         });
         return this;
      },

      populateUser: function () {
         var playerInfo = $('.cp .gt');
         $.extend(this.user, {
            name:       playerInfo.find('a[href^=profile]').text(),
            id:         playerInfo.find('a[href^=profile]').attr('href').split('=')[1],
            alive:      playerInfo.text().search(/you are dead/) == -1 ? true : false,
            health:     playerInfo.text().match(/You have (\d+) Hit Points?/)[1],
            ap:         playerInfo.text().match(/You have (\d+) Action Points?/)[1],
            experience: playerInfo.text().match(/and (\d+) Experience Points?/)[1],
            inventory:  []
         });
         var udb = this;
         $('select[name=drop] option[value!=""]').each(function () {
            udb.user.inventory.push({
               id:   $(this).val(),
               name: $(this).text()
            });
         });

      },

      populateSurroundings: function () {
         var udb = this;
         this.surroundings.inside = this.isInside();
         $('table.c tr:has(td.b)').each(function (row) {
            udb.surroundings.map.push([]);
            $(this).find('td.b').each(function (col) {
               udb.surroundings.map[row].push({
                  element:          this,
                  coords:           udb.getCoordsFromMapTile(this),
                  zombies:          udb.getZombieCountFromMapTile(this),
                  survivors:        udb.getSurvivorsFromMapTile(this),
                  ruined:           udb.isMapTileRuined(this),
                  illuminated:      udb.isMapTileLit(this)
               });
               // Note the coordinates of our position in relation to surroundings.
               if(udb.isPositionElement(this))
                  udb.surroundings.position = udb.surroundings.map[row][udb.surroundings.map[row].length-1];
            });
            // Current position specific data.
            $.extend(udb.surroundings.position, {
               barricades: udb.getBarricadeLevel()
            });
         });
      },

      isPositionElement: function (elem) {
         // Position element has input with no form.
         return $(elem).is('td:has(>input)');
      },

      isInside: function () {
         //Check for the leave button to determine if we're inside a building.
         return ($('.gp form[action$=out]').length == 1);
      },

      isOutsideBuilding: function () {
         //Check for the enter button to see if we're outside a building.
         return ($('.gp form[action$=in]').length == 1);
      },

      isEmptyLot: function () {
         //Returns true if current tile is empty lot
         return (!this.isInside() && !this.isOutsideBuilding());
      },

      isMapTileRuined: function (elem) {
         //.mr = ruined or inside dark
         if(this.isPositionElement(elem)){
            return false;//fucking special cases
         } else {
            return $(elem).find('input[type=submit]').hasClass('mr');
         }
      },

      isMapTileLit: function (elem) {
         //.ml = lit tile
         //.mrl = ruined + powered
         var button = $(elem).find('input[type=submit]');
         return ( button.hasClass('ml') || button.hasClass('mrl') );
      },

      isHPDataAvailable: function () {
         return ( $('.gp .gt sub').length != 0 );
      },

      getCoordsFromMapTile: function (elem) {
         // Parse out the coordinates for the provided tile.
         var coords;
         if (this.isPositionElement(elem)) {
            // Player position has to be calculated from a nearby tile.
            coords = this.calculatePositionCoords(elem);
         } else {
            coords = this.parseCoords($(elem).find('input[type=hidden]').val());
         }
         return coords;
      },

      calculatePositionCoords: function (elem) {
         var locationTD = $('table.c td:has(>input)'); //Location TD always has an input without a form.
         var locationRow = locationTD.parent().find('td');
         var xOffset = 1;
         var offsetTDIndex = 0;
         if (locationRow.index(elem) == 0) {//We are at the left edge of the map.
            xOffset = -1;
            offsetTDIndex = 1;
         }
         var offset = this.parseCoords(
            // Get the coordinates of the tile to our left/right
            locationRow.eq(offsetTDIndex).find('input[type=hidden]').val()
         );
         return {
            x: offset.x + xOffset,
            y: offset.y
         }
      },

      parseCoords: function (coords) {
         coords = coords.split('-');
         return {
            x: parseInt(coords[0], 10),
            y: parseInt(coords[1], 10)
         }
      },

      getSurvivorsFromMapTile: function (elem) {
         //Returns an array of objects with survivor names and ids.
         var survivors = [];
         var survivorLinks = $(elem).find('a[href^=profile]');
         if (this.isPositionElement(elem)) {
            // If the query is for our current position we can provide a full list.
            survivorLinks = $('.gp .gt a');
         }
         var udb = this;
         survivorLinks.each(function (i) {
            survivors.push({
               name: $(this).text(),
               id:   $(this).attr('href').split('=')[1]
            })
            if (udb.isPositionElement(elem) && udb.isHPDataAvailable()) {
               survivors[i].hp = udb.getHPDataForSurvivor(survivors[i]);
            }
         });
         return survivors;
      },

      getHPDataForSurvivor: function (survivor) {
         var reg = new RegExp( survivor.name + "\\s\\((\\d+)HP\\)" );
         return $('.gp .gt').text().match(reg)[1];
      },

      getZombieCountFromMapTile: function (elem) {
         if($(elem).is('td:has(.fz)'))
            return parseInt($(elem).find('.fz').text().split(' ')[0], 10);
         else
            return 0;
      },

      getBarricadeLevel: function () {
         var reg = /The (building|doors to the street|building\'s doors) (has|have) been ([^\.]*(secured|barricaded|left wide open))[^\.]*./;
         if (this.isEmptyLot())
            var barricadeText = 'no building';
         else
            var barricadeText = $('.gp .gt').text().match(reg)[3];
         return this.barricadeLevels[barricadeText];
      },

      getLocationByCoord: function (locx, locy) {
         var location = false;
         $.each(this.surroundings, function () {
            $.each(this, function () {
               if (this.coords.x == locx && this.coords.y == locy)
                  location = this;
            });
         });
         return location;
      },

      sendReport: function () {
         // $.ajax({
         //    type: "POST",
         //    url: this.reportURL,
         //    data: ,
         //    dataType: 'json',
         //    success: this.receiveData
         // });
      },

      receiveData: function (data, status, xhr) {
         //placeholder
         console.log('xhr');
      },

      barricadeLevels: {
         'no building':                      0,
         'left wide open' :                  1,
         'secured' :                         2,
         'loosely barricaded' :              3,
         'lightly barricaded' :              4,
         'quite strongly barricaded' :       5,
         'very strongly barricaded' :        6,
         'heavily barricaded' :              7,
         'very heavily barricaded' :         8,
         'extremely heavily barricaded' :    9
      },

      renderUI: function () {
         for( ext in this.UI ) {
            this.UI[ext].init(this);
         }
      }

   }

   UDBrains.fn.init.prototype = UDBrains.fn;

   UDBrains = window.UDBrains = UDBrains();

   UDBrains.UI.ordersPane = {
      url: 'http://brains.somethingdead.com/orders/',
      init: function (udb) {
         this.url = this.url
         var iframe = $('<iframe>').attr('id', 'orders').attr('src', this.url).css({
            width: '100%',
            height: '200px',
            border: '4px solid #445544'
         });
         var ordersLink = $('<a>').attr('href', '#orders').bind('click', function () {
            localStorage.ordersVisible = $('#orders').toggle().is(':visible');
         }).text('Click here to toggle orders.');
         $('.gp').append(ordersLink);
         $('.gp').append(iframe);
         if (localStorage.ordersVisible == "false")
            iframe.hide();

      }
   }

})(jQuery);<|endoftext|>


<commit_before>//File.create(test, testContent);
var Generate = require('./support/Generate');

// Create Template
var test = new Generate('test', 'test.js');

test.setContent(`var Help = require('./test-helper.js');

describe('${test.capitalize(test.name)}', () => {

    var ${test.capitalize(test.name)};
    beforeEach(() => {
        ${test.capitalize(test.name)} = Help.bootstrapComponent(require('../app/js/components/${test.name}.js'));
    });

    it('should exist', () => {
        expect(typeof ${test.capitalize(test.name)}).toBe('object');
    });

    // Add more tests here.
});
`);

test.create();
<commit_msg>Updated test template<commit_after>//File.create(test, testContent);
var Generate = require('./support/Generate');

// Create Template
var test = new Generate('test', 'test.js');

test.setContent(`var Help = require('./test-helper.js');

describe('${test.capitalize(test.name)}', () => {

    var ${test.capitalize(test.name)};
    beforeEach(() => {
        ${test.capitalize(test.name)} = Help.bootstrapComponent(
            require('../app/js/components/${test.name}.js')
        );
    });

    it('should exist', () => {
        expect(typeof ${test.capitalize(test.name)}).toBe('object');
    });

    // Add more tests here.
});
`);

test.create();
<|endoftext|>


<commit_before>/*
 * Inspects the environment for global variables.
 *
 * On some platforms- particularly some userscript engines- the global this
 * object !== window, and the two may have significantly different properties.
 */
function find_global(name) {
    return _global_this[name] || window[name] || undefined;
}

/*
 * Log functions. You should use these in preference to console.log(), which
 * isn't always available.
 */
var _log_buffer = [];
_global_this.bpm_logs = _log_buffer; // For console access

var _LOG_DEBUG = 0;
var _LOG_INFO = 1;
var _LOG_WARNING = 2;
var _LOG_ERROR = 3;
var _LOG_LEVEL = DEV_MODE ? _LOG_DEBUG : _LOG_WARNING;

var _console = find_global("console");
var _gm_log = find_global("GM_log");
var _raw_log;

if(_console && _console.log) {
    _raw_log = _console.log.bind(_console);
} else if(_gm_log) {
    _raw_log = function() {
        var args = Array.prototype.slice.call(arguments);
        var msg = args.join(" ");
        _gm_log(msg);
    };
} else {
    // ?!?
    _raw_log = function() {};
}

function _wrap_logger(cname, prefix, level) {
    var cfunc;
    if(_console && _console[cname]) {
        cfunc = _console[cname].bind(_console);
    } else {
        cfunc = _raw_log;
    }
    return function() {
        var args = Array.prototype.slice.call(arguments);
        args.unshift(prefix);
        if(window.name) {
            args.unshift("[" + window.name + "]:");
        }
        _log_buffer.push(args.join(" "));
        args.unshift("BPM:");
        if(_LOG_LEVEL <= level) {
            cfunc.apply(null, args);
        }
    };
}

var log_debug = _wrap_logger("log", "DEBUG:", _LOG_DEBUG);
var log_info = _wrap_logger("log", "INFO:", _LOG_INFO);
var log_warning = _wrap_logger("warn", "WARNING:", _LOG_WARNING);
var log_error = _wrap_logger("error", "ERROR:", _LOG_ERROR);
var log_trace = function() {};
if(_console && _console.trace) {
    log_trace = _console.trace.bind(_console);
}

/*
 * A string referring to the current platform BPM is running on. This is a
 * best guess, made by inspecting global variables, and needed because this
 * script runs unmodified on all supported platforms.
 */
var platform;
// FIXME: "self" is a standard object, though self.on is specific to
// Firefox content scripts. I'd prefer something a little more clearly
// affiliated, though.
if(self.on) {
    platform = "firefox-ext";
} else if(find_global("chrome") && chrome.extension) {
    platform = "chrome-ext";
} else {
    log_error("Unknown platform! Your installation is badly broken.");
    platform = "unknown";
    // may as well just die at this point; nothing will actually work
}

log_debug("Platform:", platform);

/*
 * Wraps a function with an error-detecting variant. Useful for callbacks
 * and the like, since some browsers (Firefox...) have a way of swallowing
 * exceptions.
 */
function catch_errors(f) {
    return function() {
        try {
            return f.apply(this, arguments);
        } catch(e) {
            log_error("Exception on line " + e.lineNumber + ": ", e.name + ": " + e.message);
            if(e.trace) {
                log_error("Stack trace:");
                log_error(e.trace);
            } else {
                log_error("Current stack:");
                // This probably isn't very useful...
                log_trace();
            }
            throw e;
        }
    };
}

/*
 * Usage: with_dom(function() { ... code ... });
 */
var with_dom = (function() {
    var callbacks = [];
    var listening = false;
    var is_ready = function() {
        return (document.readyState === "interactive" || document.readyState === "complete");
    };
    var ready = is_ready();

    if(ready) {
        log_debug("Document loaded on startup");
    }

    var loaded = function(event) {
        log_debug("Document loaded");
        _checkpoint("dom");
        ready = true;

        for(var i = 0; i < callbacks.length; i++) {
            callbacks[i]();
        }

        callbacks = null; // unreference, just in case
    };

    var add = function(callback) {
        if(ready || is_ready()) {
            callback();
        } else {
            callbacks.push(callback);
            if(!listening) {
                listening = true;
                document.addEventListener("DOMContentLoaded", catch_errors(loaded), false);
            }
        }
    };

    return add;
})();

/*
 * A reference to the MutationObserver object. It's unprefixed on Firefox,
 * but not on Chrome. Safari presumably has this as well. Defined to be
 * null on platforms that don't support it.
 */
// NOTE: As of right now, MutationObserver is badly broken on Chrome.
// https://code.google.com/p/chromium/issues/detail?id=160985
// Disabling it until they release a fix.
var MutationObserver = (find_global("MutationObserver") || /*find_global("WebKitMutationObserver") ||*/ find_global("MozMutationObserver") || null);

/*
 * Wrapper to monitor the DOM for inserted nodes, using either
 * MutationObserver or DOMNodeInserted, falling back for a broken MO object.
 */
function observe_document(callback) {
    if(MutationObserver) {
        log_debug("Monitoring document with MutationObserver");
        var observer = new MutationObserver(catch_errors(function(mutations, observer) {
            for(var m = 0; m < mutations.length; m++) {
                var added = mutations[m].addedNodes;
                if(!added || !added.length) {
                    continue; // Nothing to do
                }

                callback(added);
            }
        }));

        try {
            // FIXME: For some reason observe(document.body, [...]) doesn't work
            // on Firefox. It just throws an exception. document works.
            observer.observe(document, {"childList": true, "subtree": true});
            return;
        } catch(e) {
            // Failed with whatever the error of the week is
            log_warning("Can't use MutationObserver: L" + e.lineNumber + ": ", e.name + ": " + e.message + ")");
        }
    }

    log_debug("Monitoring document with DOMNodeInserted");
    document.body.addEventListener("DOMNodeInserted", catch_errors(function(event) {
        callback([event.target]);
    }));
}

var _tag_blacklist = {
    // Meta tags we should never touch
    "HEAD": 1, "TITLE": 1, "BASE": 1, "LINK": 1, "META": 1, "STYLE": 1, "SCRIPT": 1,
    // Things I'm worried about
    "IFRAME": 1, "OBJECT": 1, "CANVAS": 1, "SVG": 1, "MATH": 1, "TEXTAREA": 1
};

/*
 * Walks the DOM tree from the given root, running a callback on each node
 * where its nodeType === node_filter. Pass only three arguments.
 *
 * This is supposed to be much faster than TreeWalker, and also chunks its
 * work into batches of 1000, waiting 50ms in between in order to ensure
 * browser responsiveness no matter the size of the tree.
 */
function walk_dom(root, node_filter, process, end, node, depth) {
    if(!node) {
        if(_tag_blacklist[root.tagName]) {
            return; // A bit odd, but possible
        } else {
            // Treat root as a special case
            if(root.nodeType === node_filter) {
                process(root);
            }
            node = root.firstChild;
            depth = 1;
        }
    }
    var num = 1000;
    // If the node/root was null for whatever reason, we die here
    while(node && num > 0) {
        num--;
        if(!_tag_blacklist[node.tagName]) {
            // Only process valid nodes.
            if(node.nodeType === node_filter) {
                process(node);
            }
            // Descend (but never into blacklisted tags).
            if(node.hasChildNodes()) {
                node = node.firstChild;
                depth++;
                continue;
            }
        }
        while(!node.nextSibling) {
            node = node.parentNode;
            depth--;
            if(!depth) {
                end();
                return; // Done!
            }
        }
        node = node.nextSibling;
    }
    if(num) {
        // Ran out of nodes, or hit null somehow. I'm not sure how either
        // of these can happen, but oh well.
        end();
    } else {
        setTimeout(catch_errors(function() {
            walk_dom(root, node_filter, process, end, node, depth);
        }), 50);
    }
}

/*
 * Helper function to make elements "draggable", i.e. clicking and dragging
 * them will move them around.
 */
function enable_drag(element, start_callback, callback) {
    var start_x, start_y;

    var on_mousemove = catch_errors(function(event) {
        var dx = event.clientX - start_x;
        var dy = event.clientY - start_y;
        callback(event, dx, dy);
    });

    element.addEventListener("mousedown", catch_errors(function(event) {
        start_x = event.clientX;
        start_y = event.clientY;
        window.addEventListener("mousemove", on_mousemove, false);
        document.body.classList.add("bpm-noselect");
        start_callback(event);
    }), false);

    window.addEventListener("mouseup", catch_errors(function(event) {
        window.removeEventListener("mousemove", on_mousemove, false);
        document.body.classList.remove("bpm-noselect");
    }), false);
}

/*
 * Wrapper around enable_drag for the common case of moving elements.
 */
function make_movable(element, container, callback) {
    var start_x, start_y;

    enable_drag(element, function(event) {
        start_x = parseInt(container.style.left, 10);
        start_y = parseInt(container.style.top, 10);
    }, function(event, dx, dy) {
        var left = Math.max(start_x + dx, 0);
        var top = Math.max(start_y + dy, 0);

        function move() {
            container.style.left = left + "px";
            container.style.top = top + "px";
        }

        if(callback) {
            callback(event, left, top, move);
        } else {
            move();
        }
    });
}

/*
 * Makes a nice <style> element out of the given CSS.
 */
function style_tag(css) {
    log_debug("Building <style> tag");
    var tag = document.createElement("style");
    tag.type = "text/css";
    tag.textContent = css;
    return tag;
}

/*
 * Makes a nice <link> element to the given URL (for CSS).
 */
function stylesheet_link(url) {
    log_debug("Building <link> tag to", url);
    var tag = document.createElement("link");
    tag.href = url;
    tag.rel = "stylesheet";
    tag.type = "text/css";
    return tag;
}

/*
 * Determines whether this element, or any ancestor, have the given id.
 */
function id_above(element, id) {
    while(true) {
        if(element.id === id) {
            return true;
        } else if(element.parentElement) {
            element = element.parentElement;
        } else {
            return false;
        }
    }
}

/*
 * Determines whether this element, or any ancestor, have the given class.
 */
function class_above(element, class_name) {
    while(true) {
        if(element.classList.contains(class_name)) {
            return element;
        } else if(element.parentElement) {
            element = element.parentElement;
        } else {
            return null;
        }
    }
}

/*
 * Locates an element at or above the given one matching a particular test.
 */
function locate_matching_ancestor(element, predicate, none) {
    while(true) {
        if(predicate(element)) {
            return element;
        } else if(element.parentElement) {
            element = element.parentElement;
        } else {
            return none;
        }
    }
}

/*
 * Locates an element with the given class name. Logs a warning message if
 * more than one element matches. Returns null if there wasn't one.
 */
function find_class(root, class_name) {
    var elements = root.getElementsByClassName(class_name);
    if(!elements.length) {
        return null;
    } else if(elements.length === 1) {
        return elements[0];
    } else {
        log_warning("Multiple elements under", root, "with class '" + class_name + "'");
        return elements[0];
    }
}

/* str.startswith() and str.endswith() */
function starts_with(text, s) {
    return text.slice(0, s.length) === s;
}

function ends_with(text, s) {
    return text.slice(-s.length) === s;
}

/*
 * Lazy way to get to A.slice() on any list-like. Useful for getElements()
 * calls, since the returned objects are slow to access.
 */
var slice = Array.prototype.slice.call.bind(Array.prototype.slice);
<commit_msg>Use MutationObserver again<commit_after>/*
 * Inspects the environment for global variables.
 *
 * On some platforms- particularly some userscript engines- the global this
 * object !== window, and the two may have significantly different properties.
 */
function find_global(name) {
    return _global_this[name] || window[name] || undefined;
}

/*
 * Log functions. You should use these in preference to console.log(), which
 * isn't always available.
 */
var _log_buffer = [];
_global_this.bpm_logs = _log_buffer; // For console access

var _LOG_DEBUG = 0;
var _LOG_INFO = 1;
var _LOG_WARNING = 2;
var _LOG_ERROR = 3;
var _LOG_LEVEL = DEV_MODE ? _LOG_DEBUG : _LOG_WARNING;

var _console = find_global("console");
var _gm_log = find_global("GM_log");
var _raw_log;

if(_console && _console.log) {
    _raw_log = _console.log.bind(_console);
} else if(_gm_log) {
    _raw_log = function() {
        var args = Array.prototype.slice.call(arguments);
        var msg = args.join(" ");
        _gm_log(msg);
    };
} else {
    // ?!?
    _raw_log = function() {};
}

function _wrap_logger(cname, prefix, level) {
    var cfunc;
    if(_console && _console[cname]) {
        cfunc = _console[cname].bind(_console);
    } else {
        cfunc = _raw_log;
    }
    return function() {
        var args = Array.prototype.slice.call(arguments);
        args.unshift(prefix);
        if(window.name) {
            args.unshift("[" + window.name + "]:");
        }
        _log_buffer.push(args.join(" "));
        args.unshift("BPM:");
        if(_LOG_LEVEL <= level) {
            cfunc.apply(null, args);
        }
    };
}

var log_debug = _wrap_logger("log", "DEBUG:", _LOG_DEBUG);
var log_info = _wrap_logger("log", "INFO:", _LOG_INFO);
var log_warning = _wrap_logger("warn", "WARNING:", _LOG_WARNING);
var log_error = _wrap_logger("error", "ERROR:", _LOG_ERROR);
var log_trace = function() {};
if(_console && _console.trace) {
    log_trace = _console.trace.bind(_console);
}

/*
 * A string referring to the current platform BPM is running on. This is a
 * best guess, made by inspecting global variables, and needed because this
 * script runs unmodified on all supported platforms.
 */
var platform;
// FIXME: "self" is a standard object, though self.on is specific to
// Firefox content scripts. I'd prefer something a little more clearly
// affiliated, though.
if(self.on) {
    platform = "firefox-ext";
} else if(find_global("chrome") && chrome.extension) {
    platform = "chrome-ext";
} else {
    log_error("Unknown platform! Your installation is badly broken.");
    platform = "unknown";
    // may as well just die at this point; nothing will actually work
}

log_debug("Platform:", platform);

/*
 * Wraps a function with an error-detecting variant. Useful for callbacks
 * and the like, since some browsers (Firefox...) have a way of swallowing
 * exceptions.
 */
function catch_errors(f) {
    return function() {
        try {
            return f.apply(this, arguments);
        } catch(e) {
            log_error("Exception on line " + e.lineNumber + ": ", e.name + ": " + e.message);
            if(e.trace) {
                log_error("Stack trace:");
                log_error(e.trace);
            } else {
                log_error("Current stack:");
                // This probably isn't very useful...
                log_trace();
            }
            throw e;
        }
    };
}

/*
 * Usage: with_dom(function() { ... code ... });
 */
var with_dom = (function() {
    var callbacks = [];
    var listening = false;
    var is_ready = function() {
        return (document.readyState === "interactive" || document.readyState === "complete");
    };
    var ready = is_ready();

    if(ready) {
        log_debug("Document loaded on startup");
    }

    var loaded = function(event) {
        log_debug("Document loaded");
        _checkpoint("dom");
        ready = true;

        for(var i = 0; i < callbacks.length; i++) {
            callbacks[i]();
        }

        callbacks = null; // unreference, just in case
    };

    var add = function(callback) {
        if(ready || is_ready()) {
            callback();
        } else {
            callbacks.push(callback);
            if(!listening) {
                listening = true;
                document.addEventListener("DOMContentLoaded", catch_errors(loaded), false);
            }
        }
    };

    return add;
})();

/*
 * A reference to the MutationObserver object. It's unprefixed on Firefox,
 * but not on Chrome. Safari presumably has this as well. Defined to be
 * null on platforms that don't support it.
 */
var MutationObserver = (find_global("MutationObserver") || find_global("WebKitMutationObserver") || find_global("MozMutationObserver") || null);

/*
 * Wrapper to monitor the DOM for inserted nodes, using either
 * MutationObserver or DOMNodeInserted, falling back for a broken MO object.
 */
function observe_document(callback) {
    if(MutationObserver) {
        log_debug("Monitoring document with MutationObserver");
        var observer = new MutationObserver(catch_errors(function(mutations, observer) {
            for(var m = 0; m < mutations.length; m++) {
                var added = mutations[m].addedNodes;
                if(!added || !added.length) {
                    continue; // Nothing to do
                }

                callback(added);
            }
        }));

        try {
            // FIXME: For some reason observe(document.body, [...]) doesn't work
            // on Firefox. It just throws an exception. document works.
            observer.observe(document, {"childList": true, "subtree": true});
            return;
        } catch(e) {
            // Failed with whatever the error of the week is
            log_warning("Can't use MutationObserver: L" + e.lineNumber + ": ", e.name + ": " + e.message + ")");
        }
    }

    log_debug("Monitoring document with DOMNodeInserted");
    document.body.addEventListener("DOMNodeInserted", catch_errors(function(event) {
        callback([event.target]);
    }));
}

var _tag_blacklist = {
    // Meta tags we should never touch
    "HEAD": 1, "TITLE": 1, "BASE": 1, "LINK": 1, "META": 1, "STYLE": 1, "SCRIPT": 1,
    // Things I'm worried about
    "IFRAME": 1, "OBJECT": 1, "CANVAS": 1, "SVG": 1, "MATH": 1, "TEXTAREA": 1
};

/*
 * Walks the DOM tree from the given root, running a callback on each node
 * where its nodeType === node_filter. Pass only three arguments.
 *
 * This is supposed to be much faster than TreeWalker, and also chunks its
 * work into batches of 1000, waiting 50ms in between in order to ensure
 * browser responsiveness no matter the size of the tree.
 */
function walk_dom(root, node_filter, process, end, node, depth) {
    if(!node) {
        if(_tag_blacklist[root.tagName]) {
            return; // A bit odd, but possible
        } else {
            // Treat root as a special case
            if(root.nodeType === node_filter) {
                process(root);
            }
            node = root.firstChild;
            depth = 1;
        }
    }
    var num = 1000;
    // If the node/root was null for whatever reason, we die here
    while(node && num > 0) {
        num--;
        if(!_tag_blacklist[node.tagName]) {
            // Only process valid nodes.
            if(node.nodeType === node_filter) {
                process(node);
            }
            // Descend (but never into blacklisted tags).
            if(node.hasChildNodes()) {
                node = node.firstChild;
                depth++;
                continue;
            }
        }
        while(!node.nextSibling) {
            node = node.parentNode;
            depth--;
            if(!depth) {
                end();
                return; // Done!
            }
        }
        node = node.nextSibling;
    }
    if(num) {
        // Ran out of nodes, or hit null somehow. I'm not sure how either
        // of these can happen, but oh well.
        end();
    } else {
        setTimeout(catch_errors(function() {
            walk_dom(root, node_filter, process, end, node, depth);
        }), 50);
    }
}

/*
 * Helper function to make elements "draggable", i.e. clicking and dragging
 * them will move them around.
 */
function enable_drag(element, start_callback, callback) {
    var start_x, start_y;

    var on_mousemove = catch_errors(function(event) {
        var dx = event.clientX - start_x;
        var dy = event.clientY - start_y;
        callback(event, dx, dy);
    });

    element.addEventListener("mousedown", catch_errors(function(event) {
        start_x = event.clientX;
        start_y = event.clientY;
        window.addEventListener("mousemove", on_mousemove, false);
        document.body.classList.add("bpm-noselect");
        start_callback(event);
    }), false);

    window.addEventListener("mouseup", catch_errors(function(event) {
        window.removeEventListener("mousemove", on_mousemove, false);
        document.body.classList.remove("bpm-noselect");
    }), false);
}

/*
 * Wrapper around enable_drag for the common case of moving elements.
 */
function make_movable(element, container, callback) {
    var start_x, start_y;

    enable_drag(element, function(event) {
        start_x = parseInt(container.style.left, 10);
        start_y = parseInt(container.style.top, 10);
    }, function(event, dx, dy) {
        var left = Math.max(start_x + dx, 0);
        var top = Math.max(start_y + dy, 0);

        function move() {
            container.style.left = left + "px";
            container.style.top = top + "px";
        }

        if(callback) {
            callback(event, left, top, move);
        } else {
            move();
        }
    });
}

/*
 * Makes a nice <style> element out of the given CSS.
 */
function style_tag(css) {
    log_debug("Building <style> tag");
    var tag = document.createElement("style");
    tag.type = "text/css";
    tag.textContent = css;
    return tag;
}

/*
 * Makes a nice <link> element to the given URL (for CSS).
 */
function stylesheet_link(url) {
    log_debug("Building <link> tag to", url);
    var tag = document.createElement("link");
    tag.href = url;
    tag.rel = "stylesheet";
    tag.type = "text/css";
    return tag;
}

/*
 * Determines whether this element, or any ancestor, have the given id.
 */
function id_above(element, id) {
    while(true) {
        if(element.id === id) {
            return true;
        } else if(element.parentElement) {
            element = element.parentElement;
        } else {
            return false;
        }
    }
}

/*
 * Determines whether this element, or any ancestor, have the given class.
 */
function class_above(element, class_name) {
    while(true) {
        if(element.classList.contains(class_name)) {
            return element;
        } else if(element.parentElement) {
            element = element.parentElement;
        } else {
            return null;
        }
    }
}

/*
 * Locates an element at or above the given one matching a particular test.
 */
function locate_matching_ancestor(element, predicate, none) {
    while(true) {
        if(predicate(element)) {
            return element;
        } else if(element.parentElement) {
            element = element.parentElement;
        } else {
            return none;
        }
    }
}

/*
 * Locates an element with the given class name. Logs a warning message if
 * more than one element matches. Returns null if there wasn't one.
 */
function find_class(root, class_name) {
    var elements = root.getElementsByClassName(class_name);
    if(!elements.length) {
        return null;
    } else if(elements.length === 1) {
        return elements[0];
    } else {
        log_warning("Multiple elements under", root, "with class '" + class_name + "'");
        return elements[0];
    }
}

/* str.startswith() and str.endswith() */
function starts_with(text, s) {
    return text.slice(0, s.length) === s;
}

function ends_with(text, s) {
    return text.slice(-s.length) === s;
}

/*
 * Lazy way to get to A.slice() on any list-like. Useful for getElements()
 * calls, since the returned objects are slow to access.
 */
var slice = Array.prototype.slice.call.bind(Array.prototype.slice);
<|endoftext|>


<commit_before>/*
;(function() {
  var xANDy = function(direction, positionsArray, options) {
    var
      align = {},
      newAlign = {},
      animateObj = {},
      opt = $.extend({
        val: (isNaN(options) ? null : options),
        getAlign: direction,
        setAlign: '',
        duration: 0,
        fn: function() {}
      }, options || {});

    direction = direction || 'left';
    positionsArray = positionsArray || ['left','center','right'];

    for( var i = 0; i < this.length; i++ ) {
      if (direction === 'left') {
        diameter = $(this[i]).innerWidth();
        startPos = $(this[i]).offset().left;
      }
      else if (direction === 'top') {
        diameter = $(this[i]).innerHeight();
        startPos = $(this[i]).offset().top;
      }

      align[positionsArray[0]] = startPos;
      align[positionsArray[1]] = startPos + (diameter / 2);
      align[positionsArray[2]] = startPos + diameter;

      newAlign[positionsArray[0]] = 0;
      newAlign[positionsArray[1]] = diameter / 2;
      newAlign[positionsArray[2]] = diameter;

      if(opt.val === null && opt.setAlign.length < 1) {
        // return startPos position / left or top
        return align[opt.getAlign];
      }
      else if(opt.setAlign.length > 0) {
        // align object axis to new coordinate
        animateObj[direction] = opt.val - newAlign[opt.setAlign];
        $(this[i]).animate(animateObj, opt.duration, opt.fn);
      }
      else {
        // SET to new position / left or top
        animateObj[direction] = opt.val;
        $(this[i]).animate(animateObj, opt.duration, opt.fn);
      }
    }

    return this;
  };

  $.fn.x = function(options) {
    return xANDy.call(this, 'left', ['left', 'center', 'right'], options);
  };

  $.fn.y = function(options) {
    return xANDy.call(this, 'top', ['top', 'middle', 'bottom'], options);
  };
})();
*/

;(function() {

  var

    isObject = function(arg) {
      var response = true;

      for (var i = 0; i < arguments.length; i++) {
        if ( typeof arguments[i] !== 'object' ) {
          response = false;
        }
      }
      return response;
    },

    isNumber = function(arg) {
      var response = true;

      for (var i = 0; i < arguments.length; i++) {
        if ( typeof arguments[i] !== 'number' ) {
          response = false;
        }
      }
      return response;
    },

    getXY = function(_direction, _type) {
      switch(_type) {
        case "abs":
          return $(this).offset()[_direction];
          break;
        case "abs-all":
          return $(this).offset();
        case "rel-all":
          return $(this).position();
        default:
          return $(this).position()[_direction];
      }
    },

    xyPosition = function(_options) {
      var
        opt = $.extend({
          val: (isNaN(_options) ? null : _options),
          type: undefined,
          x: undefined,
          y: undefined,
          direction: undefined,
          stepDuration: 0,
          duration: 0,
          fn: $.noop()
        }, _options, {});

      $.each(this, function(index, element) {
        var $this = $(element);

        if (opt.direction === 'both') {
          // Both x and y
          setTimeout(function(_my) {
            $this.animate({
              left: opt.x,
              top: opt.y
            }, opt.duration, opt.fn);
          }, (opt.stepDuration * index) );
        }
        else {
          // Just one direction

          if(arguments.length === 2) {

          }
          else {
            switch(type) {
              case "number":
                $this.animate({
                  left: (opt.direction === 'left')? _options: getXY.call(element, 'left'),
                  top: (opt.direction === 'top')? _options: getXY.call(element, 'top')
                }, opt.duration, opt.fn);
                break;
              case "string":
                return getXY.call(element, opt.direction, _options);
                break;
              default:
                return getXY.call(element, opt.direction);
            }
          }
        }
      });

      return this;
    },

    innerFnXY = function(_options, _direction) {
      var
        that = this,
        opt = {
          direction: _direction
        };
      return function() {
        if (arguments.length === 1) {
          switch(typeof arguments[0]) {
            case "number":
              opt.type = 'number';
              break;
            case "string":
              opt.type = 'string';
              break;
            default:
              opt.type = undefined;
          }

          return xyPosition.call(that, arguments[0]);
        }
        else if (arguments.length === 2) {
          opt = $.extend(opt, arguments[1], {});
          return xyPosition.call(that, opt, arguments[0]);
        }
      }
    };

  $.fn.x = function(options) {
    innerFnXY.call(this, options, 'left');
  }

  $.fn.y = function(options) {
    options = $.extend({
      direction: 'top'
    }, options, {});
    return xyPosition.call(this, options, 'top');
  };

  $.fn.xy = function(options) {
    var opt;

    if (options === undefined || arguments.length === 1) {
      opt = options;
      switch(typeof opt) {
        case "string":
          return getXY.call(this, 'all', opt + '-all');
          break;
        default:
          return getXY.call(this, 'all', 'rel-all');
      }
    }
    else if(arguments.length === 2) {
      if (isNumber.apply(this, arguments)) {
        xyPosition.call(this, $.extend({
          x: arguments[0],
          y: arguments[1],
          direction: 'both'
        }));
      }
    }
    else if (arguments.length === 3) {
      if ( isNumber.apply(this, [arguments[0], arguments[1]]) && isObject.apply(this, arguments[2]) ) {
        xyPosition.call(this, $.extend({
            x: arguments[0],
            y: arguments[1],
            direction: 'both'
          }, arguments[2]));
      }
    }

    return this;
  }
})();

/*

$element.x();
$element.x(10);
$element.x('abs');
$element.x(10, {
  duration: 0,
  stepDuration: 0,
  fn: $.noop()
});

$element.xy();
$element.xy('abs');
$element.xy(10, 100);
$element.xy(10, 100, {
  duration: 0,
  stepDuration: 0,
  fn: $.noop()
});

*/
<commit_msg>big changes<commit_after>;(function() {

  var

    /**
     *
     * @param {String} _type
     * @param {Array} _arguments
     * @returns {Boolean}
     */
    isInnerWrap = function(_type, _arguments) {
      var
        response = true;

      // Start with third item onwards
      for (var i = 0; i < _arguments.length; i++) {
        if ( typeof _arguments[i] !== _type ) {
          response = false;
        }
      }
      return response;
    },

    isObject = function() {
      return isInnerWrap.call(this, 'object', arguments);
    },

    isNumber = function() {
      return isInnerWrap.call(this, 'number', arguments);
    },

    isString = function() {
      return isInnerWrap.call(this, 'string', arguments);
    },

    getXY = function(_direction, _type) {
      switch(_type) {
        case "abs":
          return $(this).offset()[_direction];
          break;
        case "abs-all":
          return $(this).offset();
        case "rel-all":
          return $(this).position();
        default:
          return $(this).position()[_direction];
      }
    },

    xyPosition = function(_options) {
      var
        opt = $.extend({
          val: (isNaN(_options) ? null : _options),
          type: undefined,
          relativeTo: undefined,
          x: undefined,
          y: undefined,
          direction: undefined,
          stepDuration: 0,
          duration: 0,
          fn: $.noop()
        }, _options, {});

      $.each(this, function(index, element) {
        var $this = $(element);

        if (opt.direction === 'both') {
          // Both x and y
          setTimeout(function(_my) {
            $this.animate({
              left: opt.x,
              top: opt.y
            }, opt.duration, opt.fn);
          }, (opt.stepDuration * index) );
        }
        else {
          // Just one direction

          if(arguments.length === 2) {

          }
          else {
            switch(type) {
              case "number":
                $this.animate({
                  left: (opt.direction === 'left')? _options: getXY.call(element, 'left'),
                  top: (opt.direction === 'top')? _options: getXY.call(element, 'top')
                }, opt.duration, opt.fn);
                break;
              case "string":
                return getXY.call(element, opt.direction, _options);
                break;
              default:
                return getXY.call(element, opt.direction);
            }
          }
        }
      });

      return this;
    },

    /**
     *
     * @param {Object} opt
     * @param {Number} value
     * @returns {Object}
     */
    optSetXY = function(opt, value) {
      return $.extend(opt, {
        x: (opt.direction === 'left') ? value : undefined,
        y: (opt.direction === 'top') ? value : undefined
      });
    },

    /**
     *
     * @param {Array} _arg
     *   0: []
     *   1: [Number] OR [String]
     *   2: [Number, Object]
     * @param {String} _direction
     * @returns {Function|String}
     */
    innerXY = function(_arg, _direction) {
      var
        directionValue = undefined,
        self = this,
        options = {
          direction: _direction
        },
        animOptions = {};

      // Checks if argument 1 is a Number
      if ( isNumber(_arg[0]) ) {
        directionValue = _arg[0];
      }

      if (_arg === undefined) {
        // return X OR Y Position
        return xyPosition.call(self, options);
      }
      else if(_arg.length === 1) {
        // Checks for Number OR String values
        return xyPosition.call(self, $.extend(optSetXY(options, directionValue), {
          relativeTo: (isString(_arg[0])) ? _arg[0] : undefined
        }));
      }
      else if(_arg.length === 2) {
        // Animate to position then return this

        if ( isObject(_arg[1]) ) {
          animOptions = _arg[1];
        }

        return xyPosition.call(self, $.extend(
          optSetXY(options, directionValue),
          animOptions
        ));
      }
      else {
        return 'incorrect arguments';
      }
    };

  $.fn.x = function() {
    innerXY.call(this, arguments, 'left');
  };

  $.fn.y = function() {
    innerXY.call(this, arguments, 'top');
  };

  $.fn.xy = function(options) {
    var opt;

    if (_arguments === undefined) {
      // return {} of x&y position
    }
    else if(_arguments.length === 1) {
      // return {} of x&y position
    }
    else if(_arguments.length === 2) {
      // return this
    }
    else if(_arguments.length === 3) {
      // return this
    }
    else {
      return 'incorrect arguments';
    }

    /*
    if (options === undefined || arguments.length === 1) {
      opt = options;
      switch(typeof opt) {
        case "string":
          return getXY.call(this, 'all', opt + '-all');
          break;
        default:
          return getXY.call(this, 'all', 'rel-all');
      }
    }
    else if(arguments.length === 2) {
      if (isNumber.apply(this, arguments)) {
        xyPosition.call(this, $.extend({
          x: arguments[0],
          y: arguments[1],
          direction: 'both'
        }));
      }
    }
    else if (arguments.length === 3) {
      if ( isNumber.apply(this, [arguments[0], arguments[1]]) && isObject.apply(this, arguments[2]) ) {
        xyPosition.call(this, $.extend({
            x: arguments[0],
            y: arguments[1],
            direction: 'both'
          }, arguments[2]));
      }
    }
    */

    return this;
  };
})();

/*

$element.x();
$element.x(10);
$element.x('abs');
$element.x(10, {
  duration: 0,
  stepDuration: 0,
  fn: $.noop()
});

$element.xy();
$element.xy('abs');
$element.xy(10, 100);
$element.xy(10, 100, {
  duration: 0,
  stepDuration: 0,
  fn: $.noop()
});

*/<|endoftext|>


<commit_before>export default {
  dropdown: {
    position: 'relative',
    top: 1,
    backgroundColor: 'white',
    height: 38,
    paddingLeft: 20,
    border: '3px solid #0275d8',
    color: '#0275d8',
    margin: '0',
    WebkitAppearance: 'none',
    padding: '0 10px 0 15px'
  },
  input: {
    position: 'relative',
    top: 1,
    backgroundColor: 'white',
    borderRadius: 0,
    height: 16,
    margin: 0,
    color: '#0275d8',
    border: '3px solid #0275d8'
  },
  toolbar: {
    position: 'absolute',
    top: 0,
    left: 0,
    width: '100%',
    zIndex: 5,
    display: 'none'
  }
}
<commit_msg>Move EditorSlate component styles to a separated file #511<commit_after>export default {
<<<<<<< HEAD
=======
  button: {
    borderRight: '1px solid #fff'
  },
>>>>>>> Move EditorSlate component styles to a separated file #511
  dropdown: {
    position: 'relative',
    top: 1,
    backgroundColor: 'white',
    height: 38,
    paddingLeft: 20,
    border: '3px solid #0275d8',
    color: '#0275d8',
    margin: '0',
    WebkitAppearance: 'none',
    padding: '0 10px 0 15px'
  },
  input: {
    position: 'relative',
    top: 1,
    backgroundColor: 'white',
    borderRadius: 0,
    height: 16,
    margin: 0,
    color: '#0275d8',
    border: '3px solid #0275d8'
  },
  toolbar: {
    position: 'absolute',
    top: 0,
    left: 0,
    width: '100%',
<<<<<<< HEAD
    zIndex: 5,
=======
    zIndex: 4,
    display: 'none'
  },
  overlay: {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: '#222',
    color: '#fff',
    borderRadius: 3,
    opacity: '.82',
    fontWeight: 300,
    fontSize: '2.15rem',
    cursor: 'pointer',
>>>>>>> Move EditorSlate component styles to a separated file #511
    display: 'none'
  }
}
<|endoftext|>