<commit_before>function renderBarchart(element, headDisplayName) {

	var data = window.variantData;
	var variantIndex = window.variantIndex;

	//detail view of population level frequencies
	//possible head frequencies
	var populationFrequencies = [];

	// switch(headDisplayName) {
	// 	case "ExAC Frequency":
	// 		populationFrequencies = [
	// 			["ExAC East Asian Frequency", ""],
	// 			["ExAC South Asian Frequency", ""],
	// 			["ExAC African Frequency", ""],
	// 			["ExAC European Frequency", ""],
	// 			["ExAC Latino Frequency", ""]
	// 			];
	// 		break;
	// 	case "gnomAD Max Frequency":
	// 		populationFrequencies = [
	// 			//[population frequency, population frequency n (denominator)]
	// 			["AF_EAS", "AN_EAS"],
	// 			["AF_NFE", "AN_NFE"],
	// 			["AF_SAS", "AN_SAS"],
	// 			["AF_AMR", "AN_AMR"],
	// 			["AF_AFR", "AN_AFR"]
	// 		];
	// 		break;
	// 	default:
	// 		console.log("unknown head frequency " + headDisplayName)
	// }

	//right now just gnomAD frequencies //wait but we have ExAC pop freqs, we just don't have their denominators
	populationFrequencies = [
		["AF_EAS", "AN_EAS"],
		["AF_NFE", "AN_NFE"],
		["AF_SAS", "AN_SAS"],
		["AF_AMR", "AN_AMR"],
		["AF_AFR", "AN_AFR"]
	];

	//PREPARE THE DATAs
	var nFrequencies = populationFrequencies.length;
	var frequencyData = {};
	var maxFreq = 0;

	var denominators = [];

	$.each(populationFrequencies, (i, pair) => {

		var freq = parseFloat(data[variantIndex].core[pair[0]].originalValue);
		var denominator = parseInt(data[variantIndex].core[pair[1]].originalValue);

		if (freq > maxFreq) {
			maxFreq = freq;
		}

		denominators.push(denominator);

		frequencyData[pair[0]] = [freq, denominator];
	});

	var labels = $.map(populationFrequencies, (d, i) => d[0]);

	//LAYOUT
	var margin = {
		top: 20, bottom: 40,
		left: 40, right: 20
	};

	var outerHeight = $(element).height();
	var outerWidth = $(element).width();

	var height = outerHeight - margin.top - margin.bottom;
	var width = outerWidth - margin.left - margin.right;

	//CLEAR ANY PREEXISTING BAR CHART SVG ELEMENTS
	d3.select("g.barchart")
		.remove();

	var g = d3.select(element)
		.append("g")
		.attr("class", "barchart")
		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

	//MAKE SCALES
	var yScale = d3.scaleLinear()
		.domain([0, maxFreq])
		.range([height, 0]);

	var xScale = d3.scaleBand()
		.domain(labels)
		.range([0, width])
		.paddingInner(.1);

	//CREATE BARS
	g.selectAll("rect")
		.data(labels)
		.enter()
		.append("rect")
		.attr("x", (d, i) => xScale(d))
		.attr("y", (d, _) => {

			return yScale(frequencyData[d][0]);

		}).attr("width", xScale.bandwidth())
		.attr("height", (d, _) => {

			return height - yScale(frequencyData[d][0]);

		}).attr("fill", (d, _) => colorForPopulation(d));

	//X AXIS FOR LABELS
	var xAxis = d3.axisBottom()
		.scale(xScale)
		.tickFormat((d, i) => axisLabel(d, frequencyData));

	g.append("g")
		.attr("class", "xAxis")
		.attr("transform", "translate(0," + (height - 0) + ")")
		.call(xAxis);

	//X AXIS FOR NS
	var xAxis2 = d3.axisBottom()
		.scale(xScale)
		.tickFormat((d, i) => denominators[i]);

	g.append("g")
		.attr("class", "xAxis2")
		.attr("transform", "translate(0," + (height + 10) + ")")
		.call(xAxis2)

	//remove the actual lines, so just the labels remain
	d3.select(".xAxis2")
		.selectAll("line")
		.remove();

	//Y AXIS
	var yAxis = d3.axisLeft()
		.scale(yScale)
		.ticks(6);

	g.append("g")
		.attr("class", "yAxis")
		.call(yAxis);
}

function axisLabel(d, frequencyData) {
	var shortName = shortNameForPopulation(d);
	var denominator = frequencyData[d][1];
	return shortName;
}<commit_msg>started clustered bar chart for barchart.js<commit_after>function renderBarchart(element) {

	//modeleed on
	//https://bl.ocks.org/mbostock/3887051

	var data = window.variantData[window.variantIndex];

	var populations = ["EAS","NFE","SAS","AMR","AFR"];
	var columnHeaders = [

		//ExAC
		["ExAC East Asian Frequency", "ExAC South Asian Frequency", "ExAC African Frequency", "ExAC European Frequency", "ExAC Latino Frequency"],

		//gnomAD
		["AF_EAS","AF_NFE","AF_SAS", "AF_AMR", "AF_AFR"]

	];

	var freqData = $.map(populations, (p, i) => {

		var headersToGetDataFrom = $.map(columnHeaders, (cH, _) => cH[i]);
		console.log(headersToGetDataFrom);

		var frequencyData = $.map(headersToGetDataFrom, (h, _) => parseFloat(data.core[h].originalValue));
		console.log(frequencyData);

		return [[p].concat(frequencyData)];

	});

	console.log(freqData);

	var margin = {
		top: 20, bottom: 40,
		left: 40, right: 20
	};

	var outerHeight = $(element).height();
	var outerWidth = $(element).width();

	var height = outerHeight - margin.top - margin.bottom;
	var width = outerWidth - margin.left - margin.right;

	var x0 = d3.scaleBand()
	    .rangeRound([0, width])
	    .paddingInner(0.1);

	var x1 = d3.scaleBand()
	    .padding(0.05);

	var y = d3.scaleLinear()
	    .rangeRound([height, 0]);

	var z = d3.scaleOrdinal()
	    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

	//set scales
	var keys = ["ExAC", "gnomAD"];

	x0.domain(populations);
	x1.domain(keys).rangeRound([0, x0.bandwidth()]);

	var maxFreq = d3.max(freqData, (d, _) => d3.max(d, (e, i) => i == 0 ? 0 : e));
	console.log(maxFreq);

	y.domain([0, maxFreq]);

	var g = d3.select(element)
		.append("g")
		.attr("class", "barchart")
		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

	g.selectAll("g")
		.data(freqData)
		.enter()
		.append("g")
		.attr("transform", function(d, i) { return "translate(" + x0(populations[i]) + ",0)"; })
		.selectAll("rect")
		.data((d, _) => {

			var innerData = $.map(keys, (p, i) => {

				// return {key: p, value: d[i + 1]}
				return {key: p, value: maxFreq}

			});

			console.log(innerData);
			return innerData;

		}).enter()
		.append("rect")
		.attr("x", (d, _) => x1(d.key))
		.attr("y", (d, _) => y(d.value))
		.attr("width", x1.bandwidth())
		.attr("height", (d, _) => height - y(d.value))
		.attr("fill", (d, _) => z(d.key));

	g.append("g")
	    .attr("class", "axis")
	    .attr("transform", "translate(0," + height + ")")
	    .call(d3.axisBottom(x0));

	g.append("g")
    	.attr("class", "axis")
      	.call(d3.axisLeft(y).ticks(null, "s"))
    	.append("text")
     	.attr("x", 2)
      	.attr("y", y(y.ticks().pop()) + 0.5)
      	.attr("dy", "0.32em")
      	.attr("fill", "#000")
      	.attr("font-weight", "bold")
      	.attr("text-anchor", "start")
      	.text("Population");

}

function deprecated_renderBarchart(element, headDisplayName) {

	var data = window.variantData;
	var variantIndex = window.variantIndex;

	//detail view of population level frequencies
	//possible head frequencies
	var populationFrequencies = [];

	// switch(headDisplayName) {
	// 	case "ExAC Frequency":
	// 		populationFrequencies = [
	// 			["ExAC East Asian Frequency", ""],
	// 			["ExAC South Asian Frequency", ""],
	// 			["ExAC African Frequency", ""],
	// 			["ExAC European Frequency", ""],
	// 			["ExAC Latino Frequency", ""]
	// 			];
	// 		break;
	// 	case "gnomAD Max Frequency":
	// 		populationFrequencies = [
	// 			//[population frequency, population frequency n (denominator)]
	// 			["AF_EAS", "AN_EAS"],
	// 			["AF_NFE", "AN_NFE"],
	// 			["AF_SAS", "AN_SAS"],
	// 			["AF_AMR", "AN_AMR"],
	// 			["AF_AFR", "AN_AFR"]
	// 		];
	// 		break;
	// 	default:
	// 		console.log("unknown head frequency " + headDisplayName)
	// }

	//right now just gnomAD frequencies //wait but we have ExAC pop freqs, we just don't have their denominators
	populationFrequencies = [
		["AF_EAS", "AN_EAS"],
		["AF_NFE", "AN_NFE"],
		["AF_SAS", "AN_SAS"],
		["AF_AMR", "AN_AMR"],
		["AF_AFR", "AN_AFR"]
	];

	//PREPARE THE DATAs
	var frequencyData = {};
	var maxFreq = 0;

	var denominators = [];

	$.each(populationFrequencies, (i, pair) => {

		var freq = parseFloat(data[variantIndex].core[pair[0]].originalValue);
		var denominator = parseInt(data[variantIndex].core[pair[1]].originalValue);

		if (freq > maxFreq) {
			maxFreq = freq;
		}

		denominators.push(denominator);

		frequencyData[pair[0]] = [freq, denominator];
	});

	var labels = $.map(populationFrequencies, (d, i) => d[0]);

	//LAYOUT
	var margin = {
		top: 20, bottom: 40,
		left: 40, right: 20
	};

	var outerHeight = $(element).height();
	var outerWidth = $(element).width();

	var height = outerHeight - margin.top - margin.bottom;
	var width = outerWidth - margin.left - margin.right;

	//CLEAR ANY PREEXISTING BAR CHART SVG ELEMENTS
	d3.select("g.barchart")
		.remove();

	var g = d3.select(element)
		.append("g")
		.attr("class", "barchart")
		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

	//MAKE SCALES
	var yScale = d3.scaleLinear()
		.domain([0, maxFreq])
		.range([height, 0]);

	var xScale = d3.scaleBand()
		.domain(labels)
		.range([0, width])
		.paddingInner(.1);

	//CREATE BARS
	g.selectAll("rect")
		.data(labels)
		.enter()
		.append("rect")
		.attr("x", (d, i) => xScale(d))
		.attr("y", (d, _) => {

			return yScale(frequencyData[d][0]);

		}).attr("width", xScale.bandwidth())
		.attr("height", (d, _) => {

			return height - yScale(frequencyData[d][0]);

		}).attr("fill", (d, _) => colorForPopulation(d));

	//X AXIS FOR LABELS
	var xAxis = d3.axisBottom()
		.scale(xScale)
		.tickFormat((d, i) => axisLabel(d, frequencyData));

	g.append("g")
		.attr("class", "xAxis")
		.attr("transform", "translate(0," + (height - 0) + ")")
		.call(xAxis);

	//X AXIS FOR NS
	var xAxis2 = d3.axisBottom()
		.scale(xScale)
		.tickFormat((d, i) => denominators[i]);

	g.append("g")
		.attr("class", "xAxis2")
		.attr("transform", "translate(0," + (height + 10) + ")")
		.call(xAxis2)

	//remove the actual lines, so just the labels remain
	d3.select(".xAxis2")
		.selectAll("line")
		.remove();

	//Y AXIS
	var yAxis = d3.axisLeft()
		.scale(yScale)
		.ticks(6);

	g.append("g")
		.attr("class", "yAxis")
		.call(yAxis);
}

function axisLabel(d, frequencyData) {
	var shortName = shortNameForPopulation(d);
	var denominator = frequencyData[d][1];
	return shortName;
}<|endoftext|>


<commit_before>//      Basilisk 0.1
//      A simple library for immutable state.
//
//      (c) 2012 Brad Shuttleworth, under a BSD license.
//      see http://github.com/shuttlebrad/basilisk

(function () {
    "use strict";
    // bind to window or global, depending on environment.
    var root = this;
    var previousBasilisk = root.basilisk;

    var basilisk = root.basilisk = {};

    // TODO: we depend on underscore, but how does one properly detect that
    //       it is missing?

    if (!root._) {
        throw "Basilisk depends on underscore: please ensure that underscore is loaded first.";
    }

    var _ = root._;

    // TODO we log watcher-failure and a few other events - they are considered
    //      "broken" behaviours.

    var log = function () { };
    if (root.console && root.console.log) {
        log = function () { root.console.log.apply(root.console, arguments); }
    }

    // Atoms provide a way to manage shared, synchronous, independent state.
    // http://clojure.org/atoms
    //
    // If supplied the validator must be a function (new, old) {} -> boolean,
    // returning true if the changed value is valid, and false if not.
    //
    // the value must be immutable.
    basilisk.Atom = function (initialValue, validator) {
        if (!this instanceof basilisk.Atom) { throw "Please instantiate each atom separately." }

        // Most state is held in closure, and thus can only be changed by these
        // privileged methods.

        var current,
            self = this,
            // TODO replace with a FixedVector.
            watchers = [],
            // set the value if it passes the validator.
            _set = function (possible) {
                var old = current;
                if (possible !== current) {
                    if (!validator(possible, current)) {
                        throw "Value does not pass validator.";
                    }

                    current = possible;

                    _.each(watchers.slice(0), function (watcher) {
                        try {
                            watcher(current, old);
                        } catch (e) {
                            // do nothing
                            log("Watcher threw exception: this behaviour is broken.");
                        }
                    });
                }

                return current;
            };

        validator = validator || function () { return true; };
        // we fail immediately if the initial value does not validate.

        _.extend(self, {
            // Retrieve the current value of the Atom.
            deref: function () { return current; },

            // Applies the given "change" function to the old state,
            // checks that the result passes the validator, and updates the current state.
            //
            // Will be called as swapFunction(old, *args);  The function should have no side-effects.
            //
            // Returns the new state or throws an exception.

            swap: function (swapFunction) {
                var possible, args = [current];

                if (arguments.length > 1) {
                    args.push.apply(args, _.rest(argument));
                }

                possible = swapFunction.apply(null, args);

                // update current, call watchers
                return this.compareAndSet(current, possible);
            },

            // If oldVal matches current, change to using newVal.
            // return true if changed, false if not changed.
            compareAndSet: function (oldVal, newVal) {
                if (oldVal === current) {
                    return (_set(newVal) === newVal);
                } else {
                    return false;
                }
            },

            // add a watcher.  Will be called if the value changes.
            addWatcher: function (watcher) {
                if (_.indexOf(watchers, watcher) === -1) {
                    watchers.push(watcher);
                }
            },

            removeWatcher: function (watcher) {
                watchers = _.without(watchers, watcher);
            }
        });

        // shorter alias for cas.
        this.cas = this.compareAndSet;

        // set the initial state.
        _set(initialValue);
    };

    // Definitions
    // -----------
    //
    // Helpers for class definition:

    // whether defineProperty is available and functions according to ES5.1
    var defineAvailable = false,
        defineProperty = Object.defineProperty,
        _eg = {};

    // IE8 has a badly implemented version of defineProperty, so function detection
    // is insufficient.
    try {
        Object.defineProperty(_eg, 'x', {value:13, writable:false});
        try { _eg.x = 14; } catch (e2) {}
        defineAvailable = (_eg.x === 13);
    } catch (e) {
        defineAvailable = false;
    }

    if (defineAvailable) {
        Object.defineProperty(basilisk, 'isStrict', {
            value: true,
            writable: false,
            enumerable: true
        });
    } else {
        basilisk.isStrict = false;
    }

    // Definitions module.
    basilisk.definitions = {};

    // Create a class constructor.
    // actual contents of properties is undefined.
    basilisk.definitions.makeConstructor = function (properties) {
        var constructor,
            propList = properties;

        // cannot have a property called with_ in the list.

        if (properties['with_']) {
            throw "You cannot have a property called with_ in your list: this is used within the Basilisk defition system.";
        }

        // generate the actual contructor.
        if (!defineAvailable) {
            constructor =  function (sample) {
                var self = this,
                    sample = sample || {},
                    origValues = _.extend({}, sample);

                if (sample instanceof constructor) {
                    return sample;
                }

                if (!self instanceof constructor) {
                    throw "Object must be instantiated with new.";
                }

                // we don't actually have any guarantee of immutability
                // in this scenario: we will have to rely on failure modes
                // being caught in modern browsers.
                _.each(propList, function (value, key) {
                    var valueFn = value.filter || _.identity;
                    self[key] = valueFn(sample[key] || undefined);
                });

                // we have to do this per-instance, rather than per-class.
                self.with_ = function (adjustedProperties) {
                    var sample = _.defaults({}, adjustedProperties, origValues);
                    _.each(propList, function (value, key) {
                        var valueFn = value.filter || _.identity;
                        sample[key] = valueFn(sample[key] || undefined);
                    });
                    return new constructor(sample);
                }
            };
        } else {
            // create a fully immutable object chain.
            constructor = function (sample) {
                var self = this,
                    sample = sample || {};

                if (sample instanceof constructor) {
                    return sample;
                }

                if (!self instanceof constructor) {
                    throw "Object must be instantiated with new.";
                }

                // TODO: handle more complex property defitions.
                // TODO: verify performance on this.
                _.each(propList, function (value, key) {
                    var valueFn = value.filter || _.identity;
                    Object.defineProperty(self, key, {
                        value: valueFn(sample[key] || undefined),
                        writable: false,
                        enumerable: true
                    });
                });
            };

            // Create a new version of the object, with the specified "adjusted"
            // properties set to their specified values (and un-specified properties
            // set to their value in the current object.)
            constructor.prototype.with_ = function (adjustProperties) {
                    // *we* are a perfect reference sample, since defineProperty
                    // ensures immutability.
                    var sample = _.defaults({}, adjustProperties, this);
                    _.each(propList, function (value, key) {
                        var valueFn = value.filter || _.identity;
                        sample[key] = valueFn(sample[key] || undefined);
                    });
                    return new constructor(sample);
                }
        }

        // add a properties object, with the original properties defined.
        constructor._properties = function () { return propList.slice(0, propList.length); };

        // TODO: handle definitions for complex objects.
        _.each(propList, function (value, key) {
            var withLabel = key;
            withLabel = withLabel[0].toUpperCase() + withLabel.slice(1, withLabel.length);
            withLabel = 'with' + withLabel;

            constructor.prototype[withLabel] = function (value) {
                var adjust = {};
                adjust[key] = value;
                return this.with_(adjust);
            }
        });

        return constructor;
    }

    // Standard Watcher creation functions
    // ----
    //
    // A *lot* of watching boils down to some very simple patterns:
    //   - watch only when a specified property changes
    //   - watch only when a specified property (on a path) changes
    //   - watch for a change in a particular key in a dictionary.
    //
    // Rather than leave a lot of boilerplate lying around (and hopefully to allow
    // for optimisation and collapsing of functions), you can use the creation functions
    // below here to create new functions which can be used as watchers.

    basilisk.watchers = {};

    // TODO these are very much first-pass implementations: replace with something
    // substantially more clever.

    // Watcher function for a dotted path inside a particular atom.
    // will call the "watcher" function with the "stemmed" properties
    // @return fn watching a particular path.
    basilisk.watchers.path = function (path, watcher) {
        var parts = path.split('.'),
            // function to extract the specified path from the root.
            // WILL mutate the parts parameter.
            recur = function (parts, newVal, oldVal) {
                var first = parts.shift(),
                    newRest, oldRest;

                // if newval === oldval, there's no change so no chance of a watch.
                if (newVal === oldVal) {
                    return;
                }

                if (oldVal !== undefined && _.has(oldVal, first)) {
                    oldRest = oldVal[first];
                };

                if (newVal !== undefined && _.has(newVal, first)) {
                    newRest = newVal[first];
                }

                if (parts.length == 0) {
                    // this is the leaf: if we see a difference in value,
                    // apply it.

                    if (newRest !== oldRest) {
                        watcher(newRest, oldRest);
                    }
                } else {
                    recur(parts, newRest, oldRest);
                }
            };

        return function (newVal, oldVal) {
            recur(parts.slice(0, parts.length), newVal, oldVal);
        }
    }

    // Collections
    // -----------
    //
    // Very simple collection objects.  Not currently optimised for performance,
    // though that would not be exceptionally difficult to accomplish.

    basilisk.collections = {};

    // we routinely have methods that are called once, with no arguments.
    // (eg. length, etc.). Since we're immutable, as long as we cache the result
    // on "this", we can easily make ourselves perpetually cached.

    var oncePerInstance = function (method, key) {
        // we store our value on "this", but with a long (probably unique) key...
        var storageKey = key || _.uniqueId('__basilisk-fn-oncePerInstance');

        return function () {
            var value;
            if (arguments.length > 0) {
                throw "Cannot supply any arguments to a once-per-instance function.";
            }
            if (!this.hasOwnProperty(storageKey)) {
                value = method.apply(this, []);
                if (defineAvailable) {
                    Object.defineProperty(this, storageKey, {
                        value: value,
                        writable: false,
                        enumerable: false
                    });
                } else {
                    this[storageKey] = value;
                }

            }
            return this[storageKey];
        }
    }

    basilisk.collections.ForwardListNode = basilisk.definitions.makeConstructor({
        rest: { noWith: true },
        value: {}
    });

    basilisk.collections.ForwardListNode.prototype.length = oncePerInstance(function () {
        if (this.rest === undefined) {
            return 1;
        } else {
            return 1 + this.rest.length();
        }
    }, '_length');

    // A simple list, with O(1) shift (onto head) and O(n) each.
    basilisk.collections.ForwardList = basilisk.definitions.makeConstructor({
        head: {}
    });

    // create a node with the specified value, and return a list with that as its head.
    // this is a little more expensive here, but it makes iteration in the empty case
    // simple.
    basilisk.collections.ForwardList.prototype.shift = function (value) {
        var self = this;
        return self.with_({
            head: new basilisk.collections.ForwardListNode({
                rest: self.head,
                value: value
            })
        });
    };

    basilisk.collections.ForwardList.prototype.length = oncePerInstance(function () {
        if (this.head === undefined) {
            return 0;
        } else {
            return this.head.length();
        }
    }, '_length');

    // return a list without the head node,
    basilisk.collections.ForwardList.prototype.unshift = function () {
        var self = this,
            rest = undefined;
        if (self.head) {
            rest = self.head.rest;
        }
        return [this.head.value, new basilisk.collections.ForwardList({
            head: rest
        })];
    }

    basilisk.collections.ForwardList.prototype.each = function (iterator, context) {
        var idx = 0,
            next = this.head;

        while (next !== undefined && next !== null) {
            iterator.apply(context, [next.value, idx, this, next]);
            idx += 1;
            next = next.rest;
        }
    };

    /**
     * Return a new ForwardList containing only those elements of this list for which
     * the iterator function returns a truthy value.
     *
     * @param filterFn a function taking (value, index, list, node) -> boolean
     * @return ForwardList
     */
    basilisk.collections.ForwardList.prototype.filter = function (filterFn, context)
    {
        var values = [],
            changedValue = false;

        this.each(function (value, idx, list, node) {
            if (filterFn.apply(this, arguments)) {
                values.push(value);
            } else {
                changedValue = true;
            }
        });

        if (!changedValue) {
            return this;
        } else {
            return basilisk.collections.ForwardList.from(values);
        }
    }

    /**
     * Returns the first value that matches the specified filter function.
     */
    basilisk.collections.ForwardList.prototype.first = function (filterFn, context) {
        var idx = 0,
            filterFn = filterFn || function () { return true; },
            next = this.head;

        while (next !== undefined && next !== null) {
            if (filterFn.apply(context, [next.value, idx, this, next])) {
                return next.value;
            }
            idx += 1;
            next = next.rest;
        }

        return undefined;
    }

    // Factory method: given an array-like object or a forward list, return a forward list.
    basilisk.collections.ForwardList.from = function (source) {
        if (source instanceof basilisk.collections.ForwardList) {
            return source;
        } else {
            return _.reduceRight(source, function (memo, value) {
                return memo.shift(value);
            }, new basilisk.collections.ForwardList({ head: null }));
        }
    }

    // uninstalls basilisk, returns this instance.
    basilisk.noConflict = function () {
        root.basilisk = previousBasilisk;
        return basilisk;
    }

    // TODO wrapper for AMD.
    // TODO wrapper for use in nodejs.

}).call(this);
<commit_msg>simplify watcher code by moving to using forwardlist<commit_after>//      Basilisk 0.1
//      A simple library for immutable state.
//
//      (c) 2012 Brad Shuttleworth, under a BSD license.
//      see http://github.com/shuttlebrad/basilisk

(function () {
    "use strict";
    // bind to window or global, depending on environment.
    var root = this;
    var previousBasilisk = root.basilisk;

    var basilisk = root.basilisk = {};

    // TODO: we depend on underscore, but how does one properly detect that
    //       it is missing?

    if (!root._) {
        throw "Basilisk depends on underscore: please ensure that underscore is loaded first.";
    }

    var _ = root._;

    // TODO we log watcher-failure and a few other events - they are considered
    //      "broken" behaviours.

    var log = function () { };
    if (root.console && root.console.log) {
        log = function () { root.console.log.apply(root.console, arguments); }
    }

    // Atoms provide a way to manage shared, synchronous, independent state.
    // http://clojure.org/atoms
    //
    // If supplied the validator must be a function (new, old) {} -> boolean,
    // returning true if the changed value is valid, and false if not.
    //
    // the value must be immutable.
    basilisk.Atom = function (initialValue, validator) {
        if (!this instanceof basilisk.Atom) { throw "Please instantiate each atom separately." }

        // Most state is held in closure, and thus can only be changed by these
        // privileged methods.

        var current,
            self = this,
            // TODO replace with a FixedVector.
            watchers = basilisk.collections.ForwardList.from([]),
            // set the value if it passes the validator.
            _set = function (possible) {
                var old = current;
                if (possible !== current) {
                    if (!validator(possible, current)) {
                        throw "Value does not pass validator.";
                    }

                    current = possible;

                    watchers.each(function (watcher) {
                        try {
                            watcher(current, old);
                        } catch (e) {
                            // do nothing
                            log("Watcher threw exception: this behaviour is broken.");
                        }
                    });
                }

                return current;
            };

        validator = validator || function () { return true; };
        // we fail immediately if the initial value does not validate.

        _.extend(self, {
            // Retrieve the current value of the Atom.
            deref: function () { return current; },

            // Applies the given "change" function to the old state,
            // checks that the result passes the validator, and updates the current state.
            //
            // Will be called as swapFunction(old, *args);  The function should have no side-effects.
            //
            // Returns the new state or throws an exception.

            swap: function (swapFunction) {
                var possible, args = [current];

                if (arguments.length > 1) {
                    args.push.apply(args, _.rest(argument));
                }

                possible = swapFunction.apply(null, args);

                // update current, call watchers
                return this.compareAndSet(current, possible);
            },

            // If oldVal matches current, change to using newVal.
            // return true if changed, false if not changed.
            compareAndSet: function (oldVal, newVal) {
                if (oldVal === current) {
                    return (_set(newVal) === newVal);
                } else {
                    return false;
                }
            },

            // add a watcher.  Will be called if the value changes.
            addWatcher: function (watcher) {
                if (watchers.first(function (compare) { return compare === watcher; }) === undefined) {
                    watchers = watchers.shift(watcher);
                }
            },

            removeWatcher: function (watcher) {
                watchers = watchers.filter(function (compare) { return compare !== watcher; });
            }
        });

        // shorter alias for cas.
        this.cas = this.compareAndSet;

        // set the initial state.
        _set(initialValue);
    };

    // Definitions
    // -----------
    //
    // Helpers for class definition:

    // whether defineProperty is available and functions according to ES5.1
    var defineAvailable = false,
        defineProperty = Object.defineProperty,
        _eg = {};

    // IE8 has a badly implemented version of defineProperty, so function detection
    // is insufficient.
    try {
        Object.defineProperty(_eg, 'x', {value:13, writable:false});
        try { _eg.x = 14; } catch (e2) {}
        defineAvailable = (_eg.x === 13);
    } catch (e) {
        defineAvailable = false;
    }

    if (defineAvailable) {
        Object.defineProperty(basilisk, 'isStrict', {
            value: true,
            writable: false,
            enumerable: true
        });
    } else {
        basilisk.isStrict = false;
    }

    // Definitions module.
    basilisk.definitions = {};

    // Create a class constructor.
    // actual contents of properties is undefined.
    basilisk.definitions.makeConstructor = function (properties) {
        var constructor,
            propList = properties;

        // cannot have a property called with_ in the list.

        if (properties['with_']) {
            throw "You cannot have a property called with_ in your list: this is used within the Basilisk defition system.";
        }

        // generate the actual contructor.
        if (!defineAvailable) {
            constructor =  function (sample) {
                var self = this,
                    sample = sample || {},
                    origValues = _.extend({}, sample);

                if (sample instanceof constructor) {
                    return sample;
                }

                if (!self instanceof constructor) {
                    throw "Object must be instantiated with new.";
                }

                // we don't actually have any guarantee of immutability
                // in this scenario: we will have to rely on failure modes
                // being caught in modern browsers.
                _.each(propList, function (value, key) {
                    var valueFn = value.filter || _.identity;
                    self[key] = valueFn(sample[key] || undefined);
                });

                // we have to do this per-instance, rather than per-class.
                self.with_ = function (adjustedProperties) {
                    var sample = _.defaults({}, adjustedProperties, origValues);
                    _.each(propList, function (value, key) {
                        var valueFn = value.filter || _.identity;
                        sample[key] = valueFn(sample[key] || undefined);
                    });
                    return new constructor(sample);
                }
            };
        } else {
            // create a fully immutable object chain.
            constructor = function (sample) {
                var self = this,
                    sample = sample || {};

                if (sample instanceof constructor) {
                    return sample;
                }

                if (!self instanceof constructor) {
                    throw "Object must be instantiated with new.";
                }

                // TODO: handle more complex property defitions.
                // TODO: verify performance on this.
                _.each(propList, function (value, key) {
                    var valueFn = value.filter || _.identity;
                    Object.defineProperty(self, key, {
                        value: valueFn(sample[key] || undefined),
                        writable: false,
                        enumerable: true
                    });
                });
            };

            // Create a new version of the object, with the specified "adjusted"
            // properties set to their specified values (and un-specified properties
            // set to their value in the current object.)
            constructor.prototype.with_ = function (adjustProperties) {
                    // *we* are a perfect reference sample, since defineProperty
                    // ensures immutability.
                    var sample = _.defaults({}, adjustProperties, this);
                    _.each(propList, function (value, key) {
                        var valueFn = value.filter || _.identity;
                        sample[key] = valueFn(sample[key] || undefined);
                    });
                    return new constructor(sample);
                }
        }

        // add a properties object, with the original properties defined.
        constructor._properties = function () { return propList.slice(0, propList.length); };

        // TODO: handle definitions for complex objects.
        _.each(propList, function (value, key) {
            var withLabel = key;
            withLabel = withLabel[0].toUpperCase() + withLabel.slice(1, withLabel.length);
            withLabel = 'with' + withLabel;

            constructor.prototype[withLabel] = function (value) {
                var adjust = {};
                adjust[key] = value;
                return this.with_(adjust);
            }
        });

        return constructor;
    }

    // Standard Watcher creation functions
    // ----
    //
    // A *lot* of watching boils down to some very simple patterns:
    //   - watch only when a specified property changes
    //   - watch only when a specified property (on a path) changes
    //   - watch for a change in a particular key in a dictionary.
    //
    // Rather than leave a lot of boilerplate lying around (and hopefully to allow
    // for optimisation and collapsing of functions), you can use the creation functions
    // below here to create new functions which can be used as watchers.

    basilisk.watchers = {};

    // TODO these are very much first-pass implementations: replace with something
    // substantially more clever.

    // Watcher function for a dotted path inside a particular atom.
    // will call the "watcher" function with the "stemmed" properties
    // @return fn watching a particular path.
    basilisk.watchers.path = function (path, watcher) {
        var parts = path.split('.'),
            // function to extract the specified path from the root.
            // WILL mutate the parts parameter.
            recur = function (parts, newVal, oldVal) {
                var first = parts.shift(),
                    newRest, oldRest;

                // if newval === oldval, there's no change so no chance of a watch.
                if (newVal === oldVal) {
                    return;
                }

                if (oldVal !== undefined && _.has(oldVal, first)) {
                    oldRest = oldVal[first];
                };

                if (newVal !== undefined && _.has(newVal, first)) {
                    newRest = newVal[first];
                }

                if (parts.length == 0) {
                    // this is the leaf: if we see a difference in value,
                    // apply it.

                    if (newRest !== oldRest) {
                        watcher(newRest, oldRest);
                    }
                } else {
                    recur(parts, newRest, oldRest);
                }
            };

        return function (newVal, oldVal) {
            recur(parts.slice(0, parts.length), newVal, oldVal);
        }
    }

    // Collections
    // -----------
    //
    // Very simple collection objects.  Not currently optimised for performance,
    // though that would not be exceptionally difficult to accomplish.

    basilisk.collections = {};

    // we routinely have methods that are called once, with no arguments.
    // (eg. length, etc.). Since we're immutable, as long as we cache the result
    // on "this", we can easily make ourselves perpetually cached.

    var oncePerInstance = function (method, key) {
        // we store our value on "this", but with a long (probably unique) key...
        var storageKey = key || _.uniqueId('__basilisk-fn-oncePerInstance');

        return function () {
            var value;
            if (arguments.length > 0) {
                throw "Cannot supply any arguments to a once-per-instance function.";
            }
            if (!this.hasOwnProperty(storageKey)) {
                value = method.apply(this, []);
                if (defineAvailable) {
                    Object.defineProperty(this, storageKey, {
                        value: value,
                        writable: false,
                        enumerable: false
                    });
                } else {
                    this[storageKey] = value;
                }

            }
            return this[storageKey];
        }
    }

    basilisk.collections.ForwardListNode = basilisk.definitions.makeConstructor({
        rest: { noWith: true },
        value: {}
    });

    basilisk.collections.ForwardListNode.prototype.length = oncePerInstance(function () {
        if (this.rest === undefined) {
            return 1;
        } else {
            return 1 + this.rest.length();
        }
    }, '_length');

    // A simple list, with O(1) shift (onto head) and O(n) each.
    basilisk.collections.ForwardList = basilisk.definitions.makeConstructor({
        head: {}
    });

    // create a node with the specified value, and return a list with that as its head.
    // this is a little more expensive here, but it makes iteration in the empty case
    // simple.
    basilisk.collections.ForwardList.prototype.shift = function (value) {
        var self = this;
        return self.with_({
            head: new basilisk.collections.ForwardListNode({
                rest: self.head,
                value: value
            })
        });
    };

    basilisk.collections.ForwardList.prototype.length = oncePerInstance(function () {
        if (this.head === undefined) {
            return 0;
        } else {
            return this.head.length();
        }
    }, '_length');

    // return a list without the head node,
    basilisk.collections.ForwardList.prototype.unshift = function () {
        var self = this,
            rest = undefined;
        if (self.head) {
            rest = self.head.rest;
        }
        return [this.head.value, new basilisk.collections.ForwardList({
            head: rest
        })];
    }

    basilisk.collections.ForwardList.prototype.each = function (iterator, context) {
        var idx = 0,
            next = this.head;

        while (next !== undefined && next !== null) {
            iterator.apply(context, [next.value, idx, this, next]);
            idx += 1;
            next = next.rest;
        }
    };

    /**
     * Return a new ForwardList containing only those elements of this list for which
     * the iterator function returns a truthy value.
     *
     * @param filterFn a function taking (value, index, list, node) -> boolean
     * @return ForwardList
     */
    basilisk.collections.ForwardList.prototype.filter = function (filterFn, context)
    {
        var values = [],
            changedValue = false;

        this.each(function (value, idx, list, node) {
            if (filterFn.apply(this, arguments)) {
                values.push(value);
            } else {
                changedValue = true;
            }
        });

        if (!changedValue) {
            return this;
        } else {
            return basilisk.collections.ForwardList.from(values);
        }
    }

    /**
     * Returns the first value that matches the specified filter function.
     */
    basilisk.collections.ForwardList.prototype.first = function (filterFn, context) {
        var idx = 0,
            filterFn = filterFn || function () { return true; },
            next = this.head;

        while (next !== undefined && next !== null) {
            if (filterFn.apply(context, [next.value, idx, this, next])) {
                return next.value;
            }
            idx += 1;
            next = next.rest;
        }

        return undefined;
    }

    // Factory method: given an array-like object or a forward list, return a forward list.
    basilisk.collections.ForwardList.from = function (source) {
        if (source instanceof basilisk.collections.ForwardList) {
            return source;
        } else {
            return _.reduceRight(source, function (memo, value) {
                return memo.shift(value);
            }, new basilisk.collections.ForwardList({ head: null }));
        }
    }

    // uninstalls basilisk, returns this instance.
    basilisk.noConflict = function () {
        root.basilisk = previousBasilisk;
        return basilisk;
    }

    // TODO wrapper for AMD.
    // TODO wrapper for use in nodejs.

}).call(this);
<|endoftext|>


<commit_before>var spawnSync = require('child_process').spawnSync;

function checkSuccess(result) {
  var stderr = result.stderr;
  if (stderr && stderr.length) {
    throw new Error(stderr + '');
  }
}

function getKeyChain() {
  var result = spawnSync('security', ['default-keychain']);
  checkSuccess(result);
  return (result.stdout + '').split('"')[1];
}

function installMac(certPath) {
  var result = spawnSync('security', ['add-trusted-cert', '-k', getKeyChain(), certPath]);
  checkSuccess(result);
}

function installWin(certFile) {
  var result = spawnSync('certutil', ['-addstore', '-user', 'Root', certFile]);
  checkSuccess(result);
  if (/ERROR_CANCELLED/i.test(result.stdout + '')) {
    throw new Error('ERROR_CANCELLED');
  }
}

module.exports = function(certFile) {
  var platform = process.platform;
  if (platform === 'darwin') {
    return installMac(certFile);
  }
  if (platform === 'win32') {
    return installWin(certFile);
  }
  throw new Error('Platform ' + platform + ' is unsupported to install Root CA for now.');
};
<commit_msg>chore: refine tips<commit_after>var spawnSync = require('child_process').spawnSync;

function checkSuccess(result) {
  var stderr = result.stderr;
  if (stderr && stderr.length) {
    throw new Error(stderr + '');
  }
}

function getKeyChain() {
  var result = spawnSync('security', ['default-keychain']);
  checkSuccess(result);
  return (result.stdout + '').split('"')[1];
}

function installMac(certPath) {
  var result = spawnSync('security', ['add-trusted-cert', '-k', getKeyChain(), certPath]);
  checkSuccess(result);
}

function installWin(certFile) {
  var result = spawnSync('certutil', ['-addstore', '-user', 'Root', certFile]);
  checkSuccess(result);
  if (/ERROR_CANCELLED/i.test(result.stdout + '')) {
    throw new Error('The authorization was canceled by the user.');
  }
}

module.exports = function(certFile) {
  var platform = process.platform;
  if (platform === 'darwin') {
    return installMac(certFile);
  }
  if (platform === 'win32') {
    return installWin(certFile);
  }
  throw new Error('Platform ' + platform + ' is unsupported to install Root CA for now.');
};
<|endoftext|>


<commit_before>import React from 'react';
import AppSettingsMenuSubtitle from './AppSettingsMenuSubtitle';
import MessageBox from '../MessageBox';

import '../../assets/css/AppSettingsMenu/AppSettingsMenu.css';
import '../../assets/css/ToolBarButton.css';

class DatabaseSettingsPage extends React.Component {
    constructor(props) {
        super(props);

        // State.
        this.state = {
            isPurgeDatabaseMessageBoxOpen: false,
            isRestoreDatabaseConfirmBoxOpen: false,
            isRestoringMessageBoxOpen: false,
            isRestoreDatabaseStatusMessageBoxOpen: false,
            restoringMessage: "Backing up current Data",
        }

        // Method Bindings.
        this.getDatabaseInfoPaneJSX = this.getDatabaseInfoPaneJSX.bind(this);
        this.handleGetInfoButtonClick = this.handleGetInfoButtonClick.bind(this);
        this.getPurgeButtonJSX = this.getPurgeButtonJSX.bind(this);
        this.handlePurgeCompletedTasksButtonClick = this.handlePurgeCompletedTasksButtonClick.bind(this);
        this.handlePurgeDatabaseMessageBoxClosing = this.handlePurgeDatabaseMessageBoxClosing.bind(this);
        this.handleRestoreDatabaseConfirmBoxClosing = this.handleRestoreDatabaseConfirmBoxClosing.bind(this);
        this.handleRestoreDatabaseButtonClick = this.handleRestoreDatabaseButtonClick.bind(this);
        this.getRestoreButtonJSX = this.getRestoreButtonJSX.bind(this);
        this.handleRestoreDatabaseCompleteDialogClosing = this.handleRestoreDatabaseCompleteDialogClosing.bind(this);
    }

    render() {
        var databaseInfoPaneJSX = this.getDatabaseInfoPaneJSX()
        var purgeButtonJSX = this.getPurgeButtonJSX();
        var restoreButtonJSX = this.getRestoreButtonJSX();

        return (

                {/* Database Info */}

                         Database Info

                        {databaseInfoPaneJSX}

                {/* Purge Database of completed items */}

 Purge Database of completed tasks

                        {purgeButtonJSX}

                {/* Restore Database from Disk */}

 Restore Database from Local backup

                        {restoreButtonJSX}

                { /* Purge Database Message Box */ }
                <MessageBox isOpen={this.state.isPurgeDatabaseMessageBoxOpen} message="Are you sure?"
                onDialogClosing={this.handlePurgeDatabaseMessageBoxClosing}/>

                { /* Restore from Interactive Backup Message Box */ }
                <MessageBox isOpen={this.state.isRestoreDatabaseConfirmBoxOpen} message="Are you sure?"
                onDialogClosing={this.handleRestoreDatabaseConfirmBoxClosing}/>

                { /* Restore Database Complete Dialog */}
                <MessageBox isOpen={this.props.isRestoreDatabaseCompleteDialogOpen}
                 message={this.props.restoreDatabaseStatusMessage} okOnly={true}
                 onDialogClosing={this.handleRestoreDatabaseCompleteDialogClosing}/>

        )
    }

    handleRestoreDatabaseCompleteDialogClosing() {
        this.props.onRestoreDatabaseCompleteDialogClosing();
    }

    getRestoreButtonJSX() {
        if (this.props.isDatabaseRestoring) {
            return (

            )
        }

        else {
            return (

                     Restore

            )
        }
    }

    handleRestoreDatabaseButtonClick() {
        this.setState({
            isRestoreDatabaseConfirmBoxOpen: true
        })
    }

    handleRestoreDatabaseConfirmBoxClosing(userChoice) {
        if (userChoice === "ok") {
            this.setState({
                isRestoreDatabaseConfirmBoxOpen: false
            })

            this.props.onRequestDatabaseRestore();
        }

        if (userChoice === "cancel") {
            this.setState({
                isRestoreDatabaseConfirmBoxOpen: false
            })
        }

    }

    handlePurgeDatabaseMessageBoxClosing(userChoice) {
        if (userChoice === "ok") {
            this.setState({
                isPurgeDatabaseMessageBoxOpen: false,
            })

            this.props.onPurgeCompletedTasksButtonClick();
        }

        if (userChoice === "cancel") {
            this.setState({
                isPurgeDatabaseMessageBoxOpen: false,
            })
        }
    }

    handlePurgeCompletedTasksButtonClick() {
        // Defer to Message Box for Confirmation.
        this.setState({
            isPurgeDatabaseMessageBoxOpen: true,
        })
    }

    getPurgeButtonJSX() {
        if (this.props.isDatabasePurging) {
            return (

            )

        }

        else {
            return (

                     Purge

            )
        }
    }

    getDatabaseInfoPaneJSX() {
        if (this.props.databaseInfo === "") {
            return (

                     Get Info

            )
        }

        else {
            return (
                <textarea className="DatabaseSettingsPageInfoPane" type='text' defaultValue={this.props.databaseInfo}
                readOnly="true" />
            )
        }
    }

    handleGetInfoButtonClick(e) {
        this.props.onGetDatabaseInfoClick();
    }
}

export default DatabaseSettingsPage;<commit_msg>Added Refresh button for Database Info Panel.<commit_after>import React from 'react';
import AppSettingsMenuSubtitle from './AppSettingsMenuSubtitle';
import MessageBox from '../MessageBox';

import '../../assets/css/AppSettingsMenu/AppSettingsMenu.css';
import '../../assets/css/ToolBarButton.css';

class DatabaseSettingsPage extends React.Component {
    constructor(props) {
        super(props);

        // State.
        this.state = {
            isPurgeDatabaseMessageBoxOpen: false,
            isRestoreDatabaseConfirmBoxOpen: false,
            isRestoringMessageBoxOpen: false,
            isRestoreDatabaseStatusMessageBoxOpen: false,
            restoringMessage: "Backing up current Data",
        }

        // Method Bindings.
        this.getDatabaseInfoPaneJSX = this.getDatabaseInfoPaneJSX.bind(this);
        this.handleGetInfoButtonClick = this.handleGetInfoButtonClick.bind(this);
        this.getPurgeButtonJSX = this.getPurgeButtonJSX.bind(this);
        this.handlePurgeCompletedTasksButtonClick = this.handlePurgeCompletedTasksButtonClick.bind(this);
        this.handlePurgeDatabaseMessageBoxClosing = this.handlePurgeDatabaseMessageBoxClosing.bind(this);
        this.handleRestoreDatabaseConfirmBoxClosing = this.handleRestoreDatabaseConfirmBoxClosing.bind(this);
        this.handleRestoreDatabaseButtonClick = this.handleRestoreDatabaseButtonClick.bind(this);
        this.getRestoreButtonJSX = this.getRestoreButtonJSX.bind(this);
        this.handleRestoreDatabaseCompleteDialogClosing = this.handleRestoreDatabaseCompleteDialogClosing.bind(this);
    }

    render() {
        var databaseInfoPaneJSX = this.getDatabaseInfoPaneJSX()
        var purgeButtonJSX = this.getPurgeButtonJSX();
        var restoreButtonJSX = this.getRestoreButtonJSX();

        return (

                {/* Database Info */}

                         Database Info

                        {databaseInfoPaneJSX}

                {/* Purge Database of completed items */}

 Purge Database of completed tasks

                        {purgeButtonJSX}

                {/* Restore Database from Disk */}

 Restore Database from Local backup

                        {restoreButtonJSX}

                { /* Purge Database Message Box */ }
                <MessageBox isOpen={this.state.isPurgeDatabaseMessageBoxOpen} message="Are you sure?"
                onDialogClosing={this.handlePurgeDatabaseMessageBoxClosing}/>

                { /* Restore from Interactive Backup Message Box */ }
                <MessageBox isOpen={this.state.isRestoreDatabaseConfirmBoxOpen} message="Are you sure?"
                onDialogClosing={this.handleRestoreDatabaseConfirmBoxClosing}/>

                { /* Restore Database Complete Dialog */}
                <MessageBox isOpen={this.props.isRestoreDatabaseCompleteDialogOpen}
                 message={this.props.restoreDatabaseStatusMessage} okOnly={true}
                 onDialogClosing={this.handleRestoreDatabaseCompleteDialogClosing}/>

        )
    }

    handleRestoreDatabaseCompleteDialogClosing() {
        this.props.onRestoreDatabaseCompleteDialogClosing();
    }

    getRestoreButtonJSX() {
        if (this.props.isDatabaseRestoring) {
            return (

            )
        }

        else {
            return (

                     Restore

            )
        }
    }

    handleRestoreDatabaseButtonClick() {
        this.setState({
            isRestoreDatabaseConfirmBoxOpen: true
        })
    }

    handleRestoreDatabaseConfirmBoxClosing(userChoice) {
        if (userChoice === "ok") {
            this.setState({
                isRestoreDatabaseConfirmBoxOpen: false
            })

            this.props.onRequestDatabaseRestore();
        }

        if (userChoice === "cancel") {
            this.setState({
                isRestoreDatabaseConfirmBoxOpen: false
            })
        }

    }

    handlePurgeDatabaseMessageBoxClosing(userChoice) {
        if (userChoice === "ok") {
            this.setState({
                isPurgeDatabaseMessageBoxOpen: false,
            })

            this.props.onPurgeCompletedTasksButtonClick();
        }

        if (userChoice === "cancel") {
            this.setState({
                isPurgeDatabaseMessageBoxOpen: false,
            })
        }
    }

    handlePurgeCompletedTasksButtonClick() {
        // Defer to Message Box for Confirmation.
        this.setState({
            isPurgeDatabaseMessageBoxOpen: true,
        })
    }

    getPurgeButtonJSX() {
        if (this.props.isDatabasePurging) {
            return (

            )

        }

        else {
            return (

                     Purge

            )
        }
    }

    getDatabaseInfoPaneJSX() {
        if (this.props.databaseInfo === "") {
            return (

                     Get Info

            )
        }

        else {
            return (

                    <textarea className="DatabaseSettingsPageInfoPane" type='text' value={this.props.databaseInfo}
                        readOnly="true" />

                         Refresh

            )
        }
    }

    handleGetInfoButtonClick(e) {
        this.props.onGetDatabaseInfoClick();
    }
}

export default DatabaseSettingsPage;<|endoftext|>


<commit_before>#!/usr/bin/env node

(function() {
    'use strict';

    var config,
        Info        = require('../package'),
        Config      = require('../json/config.json'),

        DIR         = __dirname + '/../',
        DIR_LIB     = DIR + 'lib/',
        DIR_SERVER  = DIR_LIB + 'server/',

        rendy       = require('rendy'),
        createPass  = require(DIR_SERVER + 'password'),

        HOME_PAGE   = 'General help using Cloud Commander: <{{ url }}>',

        argv        = process.argv,
        args        = require('minimist')(argv.slice(2), {
            string: [
                'port',
                'password',
                'username',
                'online',
                'offline',
            ],
            boolean: [
                'auth',
                'server',
                'repl',
                'save'],
            default: {
                'auth'  : Config.auth,
                'online': Config.online,
                'server': true
            },
            alias: {
                v: 'version',
                h: 'help',
                p: 'port',
                on: 'online',
                u: 'username',
                ps: 'password',
                s: 'save',
                a: 'auth'
            }
        });

    if (args.version) {
        version();
    } else if (args.help) {
        help();
    } else {
        if (args.repl)
            repl();

        config  = require(DIR_SERVER + 'config');

        password(args.password);
        username(args.username);
        port(args.port);

        config('auth', args.auth);
        config('online', args.online);

        if (args.save)
            config.save(start);
        else
            start();
    }

    function version() {
        console.log('v' + Info.version);
    }

    function start(config) {
        var SERVER      = '../lib/server';

        if (args.server)
            require(SERVER)(config);
    }

    function password(pass) {
        var algo, hash;

        if (pass) {
            algo    = config('algo');
            hash    = createPass(algo, pass);

            config('password', hash);
        }
    }

    function username(name) {
        if (name)
            config('username', name);
    }

    function port(number) {
        if (number) {
            if (!isNaN(number))
                config('port', number);
            else
                console.error('port: ignored, should be a number');
        }
    }

    function help() {
        var bin         = require('../json/bin'),
            usage       = 'Usage: cloudcmd [options]',

            site        = rendy(HOME_PAGE, {
                url: Info.homepage
            });

        console.log(usage);
        console.log('Options:');

        Object.keys(bin).forEach(function(name) {
            var line = '  ' + name + ' ' + bin[name];
            console.log(line);
        });

        console.log('\n' + site);
    }

    function repl() {
        console.log('REPL mode enabled (telnet localhost 1337)');
        require(DIR_LIB + '/server/repl');
    }

})();
<commit_msg>fix(cloudcmd) auth always false<commit_after>#!/usr/bin/env node

(function() {
    'use strict';

    var Info        = require('../package'),

        DIR         = __dirname + '/../',
        DIR_LIB     = DIR + 'lib/',
        DIR_SERVER  = DIR_LIB + 'server/',

        config      = require(DIR_SERVER + 'config'),
        rendy       = require('rendy'),
        createPass  = require(DIR_SERVER + 'password'),

        HOME_PAGE   = 'General help using Cloud Commander: <{{ url }}>',

        argv        = process.argv,
        args        = require('minimist')(argv.slice(2), {
            string: [
                'port',
                'password',
                'username',
                'online',
                'offline',
            ],
            boolean: [
                'auth',
                'server',
                'repl',
                'save'],
            default: {
                'auth'  : config('auth'),
                'online': config('online'),
                'server': true
            },
            alias: {
                v: 'version',
                h: 'help',
                p: 'port',
                on: 'online',
                u: 'username',
                ps: 'password',
                s: 'save',
                a: 'auth'
            }
        });

    if (args.version) {
        version();
    } else if (args.help) {
        help();
    } else {
        if (args.repl)
            repl();

        password(args.password);
        username(args.username);
        port(args.port);

        config('auth', args.auth);
        config('online', args.online);

        if (args.save)
            config.save(start);
        else
            start();
    }

    function version() {
        console.log('v' + Info.version);
    }

    function start(config) {
        var SERVER      = '../lib/server';

        if (args.server)
            require(SERVER)(config);
    }

    function password(pass) {
        var algo, hash;

        if (pass) {
            algo    = config('algo');
            hash    = createPass(algo, pass);

            config('password', hash);
        }
    }

    function username(name) {
        if (name)
            config('username', name);
    }

    function port(number) {
        if (number) {
            if (!isNaN(number))
                config('port', number);
            else
                console.error('port: ignored, should be a number');
        }
    }

    function help() {
        var bin         = require('../json/bin'),
            usage       = 'Usage: cloudcmd [options]',

            site        = rendy(HOME_PAGE, {
                url: Info.homepage
            });

        console.log(usage);
        console.log('Options:');

        Object.keys(bin).forEach(function(name) {
            var line = '  ' + name + ' ' + bin[name];
            console.log(line);
        });

        console.log('\n' + site);
    }

    function repl() {
        console.log('REPL mode enabled (telnet localhost 1337)');
        require(DIR_LIB + '/server/repl');
    }

})();
<|endoftext|>


<commit_before>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const log_tree = require("../lib/log_tree");
var tree;

describe("a log_tree with no description and no children", function() {
  beforeEach(function() {
    tree = log_tree({});
  });

  it("has a description of ''", function() {
    expect(tree.description).toBe("");
  });

  it("has a denominator of 1", function() {
    expect(tree.den()).toBe(1);
  });

  it("has a numerator of 0", function() {
    expect(tree.num()).toBe(0);
  });

  it("expands into an empty array", function() {
    expect([...tree]).toEqual([]);
  });

  describe("when told that [] is complete", function() {
    beforeEach(function() {
      tree.complete('[1496756029, true, "it finished"]');
    });

    it("has a numerator of 1", function() {
      expect(tree.num()).toBe(1);
    });
  });
});
<commit_msg>:construction: denominator should be calculated<commit_after>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const log_tree = require("../lib/log_tree");
var tree;

describe("a log_tree with no description and no children", function() {
  beforeEach(function() {
    tree = log_tree({});
  });

  it("has a description of ''", function() {
    expect(tree.description).toBe("");
  });

  it("has a denominator of 1", function() {
    expect(tree.den()).toBe(1);
  });

  it("has a numerator of 0", function() {
    expect(tree.num()).toBe(0);
  });

  it("expands into an empty array", function() {
    expect([...tree]).toEqual([]);
  });

  describe("when told that [] is complete", function() {
    beforeEach(function() {
      tree.complete('[1496756029, true, "it finished"]');
    });

    it("has a numerator of 1", function() {
      expect(tree.num()).toBe(1);
    });
  });
});

describe("a log_tree with two children", function() {
  beforeEach(function() {
    tree = log_tree({c:[{}, {}]});
  });

  xit("has a denominator of 3", function() {
    expect(tree.den()).toBe(3);
  });
});
<|endoftext|>


<commit_before>import _ from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import {
  FormattedMessage,
  injectIntl,
  intlShape,
} from 'react-intl';
import {
  Row,
  Col,
  Accordion,
  Icon,
  MultiColumnList,
  Button,
  Headline
} from '@folio/stripes/components';
import moment from 'moment';

class PatronBlock extends React.Component {
  static manifest = Object.freeze({
    patronBlocks: {
      type: 'okapi',
      records: 'manualblocks',
      path: 'manualblocks',
      accumulate: 'true',
      DELETE: {
        path: 'manualblocks/%{activeRecord.blockId}',
      },
    },
    activeRecord: {},
  });

  static propTypes = {
    stripes: PropTypes.shape({
      hasPerm: PropTypes.func,
    }),
    onClickViewPatronBlock: PropTypes.func,
    intl: intlShape.isRequired,
    onToggle: PropTypes.func,
    expanded: PropTypes.bool,
    accordionId: PropTypes.string,
    patronBlocks: PropTypes.arrayOf(PropTypes.object),
    mutator: PropTypes.shape({
      activeRecord: PropTypes.shape({
        update: PropTypes.func,
      }),
      patronBlocks: PropTypes.shape({
        DELETE: PropTypes.func,
      }),
    }),
    user: PropTypes.object,
  };

  constructor(props) {
    super(props);

    this.onSort = this.onSort.bind(this);
    this.onRowClick = this.onRowClick.bind(this);
    const { intl: { formatMessage } } = props;

    this.sortMap = {
      [formatMessage({ id: 'ui-users.blocks.columns.type' })]: f => f.type,
      [formatMessage({ id: 'ui-users.blocks.columns.desc' })]: f => f.desc,
      [formatMessage({ id: 'ui-users.blocks.columns.blocked' })]: f => f.renewals,
    };

    this.state = {
      sortOrder: [
        formatMessage({ id: 'ui-users.blocks.columns.type' }),
        formatMessage({ id: 'ui-users.blocks.columns.desc' }),
        formatMessage({ id: 'ui-users.blocks.columns.blocked' }),
      ],
      sortDirection: ['desc', 'asc'],
      submitting: false,
    };
  }

  componentDidMount() {
    const { mutator: { patronBlocks }, user, onToggle, expanded, accordionId } = this.props;
    const query = `userId=${user.id}`;
    patronBlocks.GET({ params: { query } }).then(records => {
      const blocks = records.filter(p => moment(moment(p.expirationDate).format()).isSameOrAfter(moment().format()));
      if ((blocks.length > 0 && !expanded) || (!blocks.length && expanded)) {
        onToggle({ id: accordionId });
      }
    });
  }

  componentDidUpdate(prevProps) {
    const { patronBlocks } = this.props;
    const prevBlocks = prevProps.patronBlocks;
    const { submitting } = this.state;
    const prevExpirated = prevBlocks.filter(p => moment(moment(p.expirationDate).format()).isSameOrBefore(moment().format()) && p.expirationDate) || [];
    const expirated = patronBlocks.filter(p => moment(moment(p.expirationDate).format()).isSameOrBefore(moment().format()) && p.expirationDate) || [];

    if (prevExpirated.length > 0 && expirated.length === 0) {
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({ submitting: false });
    }

    if (expirated.length > 0 && !submitting) {
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({ submitting: true });
      expirated.forEach(p => {
        this.props.mutator.activeRecord.update({ blockId: p.id });
        this.props.mutator.patronBlocks.DELETE({ id: p.id });
      });
    }
  }

  onSort(e, meta) {
    if (!this.sortMap[meta.alias]) return;

    let { sortOrder, sortDirection } = this.state;

    if (sortOrder[0] !== meta.alias) {
      sortOrder = [meta.alias, sortOrder[1]];
      sortDirection = ['asc', sortDirection[1]];
    } else {
      const direction = (sortDirection[0] === 'desc') ? 'asc' : 'desc';
      sortDirection = [direction, sortDirection[1]];
    }
    this.setState({ sortOrder, sortDirection });
  }

  onRowClick(e, row) {
    const permAbled = this.props.stripes.hasPerm('ui-users.feesfines.actions.all');
    if (permAbled === true && (e.target.type !== 'button') && (e.target.tagName !== 'IMG')) {
      this.props.onClickViewPatronBlock(e, 'edit', row);
    }
  }

  getPatronFormatter() {
    const { intl: { formatMessage } } = this.props;

    return {
      'Type': f => f.type,
      'Display description': f => f.desc,
      'Blocked actions': f => `${f.borrowing ? [formatMessage({ id: 'ui-users.blocks.columns.borrowing' })] : ''}${f.renewals && f.borrowing ? ', ' : ''}${f.renewals ? [formatMessage({ id: 'ui-users.blocks.columns.renewals' })] : ''}${(f.requests && f.renewals) || (f.borrowing && f.requests) ? ', ' : ''}${f.requests ? [formatMessage({ id: 'ui-users.blocks.columns.requests' })] : ''}`,
    };
  }

  render() {
    const props = this.props;
    const {
      expanded,
      onToggle,
      accordionId,
      patronBlocks,
    } = props;
    const {
      sortOrder,
      sortDirection
    } = this.state;
    let contentData = patronBlocks.filter(p => moment(moment(p.expirationDate).format()).isSameOrAfter(moment().format()));
    contentData = _.orderBy(contentData, ['metadata.createdDate'], ['desc']);
    const visibleColumns = [
      'Type',
      'Display description',
      'Blocked actions',
    ];
    const buttonDisabled = this.props.stripes.hasPerm('ui-users.feesfines.actions.all');
    const displayWhenOpen =
      <Button id="create-patron-block" disabled={!buttonDisabled} onClick={e => { props.onClickViewPatronBlock(e, 'add'); }}>
        <FormattedMessage id="ui-users.blocks.buttons.add" />
      </Button>;
    const items =
      <MultiColumnList
        id="patron-block-mcl"
        contentData={contentData}
        formatter={this.getPatronFormatter()}
        visibleColumns={visibleColumns}
        onHeaderClick={this.onSort}
        sortOrder={sortOrder[0]}
        sortDirection={`${sortDirection[0]}ending`}
        onRowClick={this.onRowClick}
        columnWidths={{
          'Type': 100,
          'Display description': 350,
          'Blocked actions': 250
        }}
      />;
    const title =
      <Row>
        <Col><Headline style={{ 'marginLeft': '8px' }} size="large" tag="h3"><FormattedMessage id="ui-users.blocks.label" /></Headline></Col>
        <Col>{(props.hasPatronBlocks) ? <Icon size="medium" icon="exclamation-circle" status="error" /> : ''}</Col>
      </Row>;
    return (
      <Accordion
        open={expanded}
        id={accordionId}
        onToggle={onToggle}
        label={title}
        displayWhenOpen={displayWhenOpen}
      >
        <Row><Col xs>{items}</Col></Row>
      </Accordion>

    );
  }
}

export default injectIntl(PatronBlock);
<commit_msg>UIU-728: Add patron block permission<commit_after>import _ from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import {
  FormattedMessage,
  injectIntl,
  intlShape,
} from 'react-intl';
import {
  Row,
  Col,
  Accordion,
  Icon,
  MultiColumnList,
  Button,
  Headline
} from '@folio/stripes/components';
import moment from 'moment';

class PatronBlock extends React.Component {
  static manifest = Object.freeze({
    patronBlocks: {
      type: 'okapi',
      records: 'manualblocks',
      path: 'manualblocks',
      accumulate: 'true',
      DELETE: {
        path: 'manualblocks/%{activeRecord.blockId}',
      },
    },
    activeRecord: {},
  });

  static propTypes = {
    stripes: PropTypes.shape({
      hasPerm: PropTypes.func,
    }),
    onClickViewPatronBlock: PropTypes.func,
    intl: intlShape.isRequired,
    onToggle: PropTypes.func,
    expanded: PropTypes.bool,
    accordionId: PropTypes.string,
    patronBlocks: PropTypes.arrayOf(PropTypes.object),
    mutator: PropTypes.shape({
      activeRecord: PropTypes.shape({
        update: PropTypes.func,
      }),
      patronBlocks: PropTypes.shape({
        DELETE: PropTypes.func,
      }),
    }),
    user: PropTypes.object,
  };

  constructor(props) {
    super(props);

    this.onSort = this.onSort.bind(this);
    this.onRowClick = this.onRowClick.bind(this);
    const { intl: { formatMessage } } = props;

    this.sortMap = {
      [formatMessage({ id: 'ui-users.blocks.columns.type' })]: f => f.type,
      [formatMessage({ id: 'ui-users.blocks.columns.desc' })]: f => f.desc,
      [formatMessage({ id: 'ui-users.blocks.columns.blocked' })]: f => f.renewals,
    };

    this.state = {
      sortOrder: [
        formatMessage({ id: 'ui-users.blocks.columns.type' }),
        formatMessage({ id: 'ui-users.blocks.columns.desc' }),
        formatMessage({ id: 'ui-users.blocks.columns.blocked' }),
      ],
      sortDirection: ['desc', 'asc'],
      submitting: false,
    };
  }

  componentDidMount() {
    const { mutator: { patronBlocks }, user, onToggle, expanded, accordionId } = this.props;
    const query = `userId=${user.id}`;
    patronBlocks.GET({ params: { query } }).then(records => {
      const blocks = records.filter(p => moment(moment(p.expirationDate).format()).isSameOrAfter(moment().format()));
      if ((blocks.length > 0 && !expanded) || (!blocks.length && expanded)) {
        onToggle({ id: accordionId });
      }
    });
  }

  componentDidUpdate(prevProps) {
    const { patronBlocks } = this.props;
    const prevBlocks = prevProps.patronBlocks;
    const { submitting } = this.state;
    const prevExpirated = prevBlocks.filter(p => moment(moment(p.expirationDate).format()).isSameOrBefore(moment().format()) && p.expirationDate) || [];
    const expirated = patronBlocks.filter(p => moment(moment(p.expirationDate).format()).isSameOrBefore(moment().format()) && p.expirationDate) || [];

    if (prevExpirated.length > 0 && expirated.length === 0) {
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({ submitting: false });
    }

    if (expirated.length > 0 && !submitting) {
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({ submitting: true });
      expirated.forEach(p => {
        this.props.mutator.activeRecord.update({ blockId: p.id });
        this.props.mutator.patronBlocks.DELETE({ id: p.id });
      });
    }
  }

  onSort(e, meta) {
    if (!this.sortMap[meta.alias]) return;

    let { sortOrder, sortDirection } = this.state;

    if (sortOrder[0] !== meta.alias) {
      sortOrder = [meta.alias, sortOrder[1]];
      sortDirection = ['asc', sortDirection[1]];
    } else {
      const direction = (sortDirection[0] === 'desc') ? 'asc' : 'desc';
      sortDirection = [direction, sortDirection[1]];
    }
    this.setState({ sortOrder, sortDirection });
  }

  onRowClick(e, row) {
    const permAbled = this.props.stripes.hasPerm('ui-users.patron_blocks');
    if (permAbled === true && (e.target.type !== 'button') && (e.target.tagName !== 'IMG')) {
      this.props.onClickViewPatronBlock(e, 'edit', row);
    }
  }

  getPatronFormatter() {
    const { intl: { formatMessage } } = this.props;

    return {
      'Type': f => f.type,
      'Display description': f => f.desc,
      'Blocked actions': f => `${f.borrowing ? [formatMessage({ id: 'ui-users.blocks.columns.borrowing' })] : ''}${f.renewals && f.borrowing ? ', ' : ''}${f.renewals ? [formatMessage({ id: 'ui-users.blocks.columns.renewals' })] : ''}${(f.requests && f.renewals) || (f.borrowing && f.requests) ? ', ' : ''}${f.requests ? [formatMessage({ id: 'ui-users.blocks.columns.requests' })] : ''}`,
    };
  }

  render() {
    const props = this.props;
    const {
      expanded,
      onToggle,
      accordionId,
      patronBlocks,
    } = props;
    const {
      sortOrder,
      sortDirection
    } = this.state;
    let contentData = patronBlocks.filter(p => moment(moment(p.expirationDate).format()).isSameOrAfter(moment().format()));
    contentData = _.orderBy(contentData, ['metadata.createdDate'], ['desc']);
    const visibleColumns = [
      'Type',
      'Display description',
      'Blocked actions',
    ];
    const buttonDisabled = this.props.stripes.hasPerm('ui-users.patron_blocks');
    const displayWhenOpen =
      <Button id="create-patron-block" disabled={!buttonDisabled} onClick={e => { props.onClickViewPatronBlock(e, 'add'); }}>
        <FormattedMessage id="ui-users.blocks.buttons.add" />
      </Button>;
    const items =
      <MultiColumnList
        id="patron-block-mcl"
        contentData={contentData}
        formatter={this.getPatronFormatter()}
        visibleColumns={visibleColumns}
        onHeaderClick={this.onSort}
        sortOrder={sortOrder[0]}
        sortDirection={`${sortDirection[0]}ending`}
        onRowClick={this.onRowClick}
        columnWidths={{
          'Type': 100,
          'Display description': 350,
          'Blocked actions': 250
        }}
      />;
    const title =
      <Row>
        <Col><Headline style={{ 'marginLeft': '8px' }} size="large" tag="h3"><FormattedMessage id="ui-users.blocks.label" /></Headline></Col>
        <Col>{(props.hasPatronBlocks) ? <Icon size="medium" icon="exclamation-circle" status="error" /> : ''}</Col>
      </Row>;
    return (
      <Accordion
        open={expanded}
        id={accordionId}
        onToggle={onToggle}
        label={title}
        displayWhenOpen={displayWhenOpen}
      >
        <Row><Col xs>{items}</Col></Row>
      </Accordion>

    );
  }
}

export default injectIntl(PatronBlock);
<|endoftext|>


<commit_before>var config    = require("./config/config")
  , Sequelize = require("../index")
  , sequelize = new Sequelize(config.database, config.username, config.password, { logging: false })
  , Helpers   = new (require("./config/helpers"))(sequelize)
  , Migrator  = require("../lib/migrator")

describe('Migrator', function() {
  describe('getUndoneMigrations', function() {
    var migrator = null

    var setup = function(_options) {
      var options = Sequelize.Utils._.extend({
        path: __dirname + '/assets/migrations'
      }, _options || {})

      migrator = new Migrator(sequelize, options)
    }

    beforeEach(function() { migrator = null })

    // specs

    it("returns no files if timestamps are after the files timestamp", function() {
      setup({ from: 20120101010101 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(0)
          done()
        })
      })
    })

    it("returns only files between from and to", function() {
      setup({ from: 19700101000000, to: 20111117063700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(1)
          expect(files[0]).toEqual('20111117063700-createPerson.js')
          done()
        })
      })
    })

    it("returns also the file which is exactly options.from or options.to", function() {
      setup({ from: 20111117063700, to: 20111123060700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(2)
          expect(files[0]).toEqual('20111117063700-createPerson.js')
          expect(files[1]).toEqual('20111123060700-addBirthdateToPerson.js')
          done()
        })
      })
    })

    //it("returns")
  })
/*

  describe('getLastMigrationId', function() {
    it("should correctly transform array into IN", function() {
      Helpers.async(function(done) {
        new Migrator(sequelize, {
          path: __dirname + '/assets/migrations',
          from: 2011111706370020111117063700,
          to: 20111117063700
        }).migrate().success(function() {
          done()
        })
      })
    })
  })*/
})
<commit_msg>another spec<commit_after>var config    = require("./config/config")
  , Sequelize = require("../index")
  , sequelize = new Sequelize(config.database, config.username, config.password, { logging: false })
  , Helpers   = new (require("./config/helpers"))(sequelize)
  , Migrator  = require("../lib/migrator")

describe('Migrator', function() {
  describe('getUndoneMigrations', function() {
    var migrator = null

    var setup = function(_options) {
      var options = Sequelize.Utils._.extend({
        path: __dirname + '/assets/migrations'
      }, _options || {})

      migrator = new Migrator(sequelize, options)
    }

    beforeEach(function() { migrator = null })

    // specs

    it("returns no files if timestamps are after the files timestamp", function() {
      setup({ from: 20120101010101 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(0)
          done()
        })
      })
    })

    it("returns only files between from and to", function() {
      setup({ from: 19700101000000, to: 20111117063700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(1)
          expect(files[0]).toEqual('20111117063700-createPerson.js')
          done()
        })
      })
    })

    it("returns also the file which is exactly options.from or options.to", function() {
      setup({ from: 20111117063700, to: 20111123060700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(2)
          expect(files[0]).toEqual('20111117063700-createPerson.js')
          expect(files[1]).toEqual('20111123060700-addBirthdateToPerson.js')
          done()
        })
      })
    })

    it("returns all files to options.to if no options.from is defined", function() {
      setup({ to: 20111123060700 })

      Helpers.async(function(done) {
        migrator.getUndoneMigrations(function(files) {
          expect(files.length).toEqual(2)
          done()
        })
      })
    })
  })
/*

  describe('getLastMigrationId', function() {
    it("should correctly transform array into IN", function() {
      Helpers.async(function(done) {
        new Migrator(sequelize, {
          path: __dirname + '/assets/migrations',
          from: 2011111706370020111117063700,
          to: 20111117063700
        }).migrate().success(function() {
          done()
        })
      })
    })
  })*/
})
<|endoftext|>