<commit_before>/**
 * @depend ../sinon.js
 * @depend spy.js
 */
/*jslint eqeqeq: false, onevar: false*/
/*global module, require, sinon*/
/**
 * Stub functions
 *
 * @author Christian Johansen (christian@cjohansen.no)
 * @license BSD
 *
 * Copyright (c) 2010-2011 Christian Johansen
 */
"use strict";

(function (sinon) {
    var commonJSModule = typeof module == "object" && typeof require == "function";

    if (!sinon && commonJSModule) {
        sinon = require("../sinon");
    }

    if (!sinon) {
        return;
    }

    function stub(object, property, func) {
        if (!!func && typeof func != "function") {
            throw new TypeError("Custom stub should be function");
        }

        var wrapper;

        if (func) {
            wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
        } else {
            wrapper = stub.create();
        }

        if (!object && !property) {
            return sinon.stub.create();
        }

        if (!property && !!object && typeof object == "object") {
            for (var prop in object) {
                if (typeof object[prop] === "function") {
                    stub(object, prop);
                }
            }

            return object;
        }

        return sinon.wrapMethod(object, property, wrapper);
    }

    function getChangingValue(stub, property) {
        var index = stub.callCount - 1;
        var prop = index in stub[property] ? stub[property][index] : stub[property + "Last"];
        stub[property + "Last"] = prop;

        return prop;
    }

    function getCallback(stub, args) {
        var callArgAt = getChangingValue(stub, "callArgAts");

        if (callArgAt < 0) {
            var callArgProp = getChangingValue(stub, "callArgProps");

            for (var i = 0, l = args.length; i < l; ++i) {
                if (!callArgProp && typeof args[i] == "function") {
                    return args[i];
                }

                if (callArgProp && args[i] &&
                    typeof args[i][callArgProp] == "function") {
                    return args[i][callArgProp];
                }
            }

            return null;
        }

        return args[callArgAt];
    }

    var join = Array.prototype.join;

    function getCallbackError(stub, func, args) {
        if (stub.callArgAtsLast < 0) {
            var msg;

            if (stub.callArgPropsLast) {
                msg = sinon.functionName(stub) +
                    " expected to yield to '" + stub.callArgPropsLast +
                    "', but no object with such a property was passed."
            } else {
                msg = sinon.functionName(stub) +
                            " expected to yield, but no callback was passed."
            }

            if (args.length > 0) {
                msg += " Received [" + join.call(args, ", ") + "]";
            }

            return msg;
        }

        return "argument at index " + stub.callArgAtsLast + " is not a function: " + func;
    }

    var nextTick = (function () {
        if (typeof process === "object" && typeof process.nextTick === "function") {
            return process.nextTick;
        } else if (typeof msSetImmediate === "function") {
            return msSetImmediate.bind(window);
        } else if (typeof setImmediate === "function") {
            return setImmediate;
        } else {
            return function (callback) {
                setTimeout(callback, 0);
            };
        }
    })();

    function callCallback(stub, args) {
        if (stub.callArgAts.length > 0) {
            var func = getCallback(stub, args);

            if (typeof func != "function") {
                throw new TypeError(getCallbackError(stub, func, args));
            }

            var index = stub.callCount - 1;

            var callbackArguments = getChangingValue(stub, "callbackArguments");
            var callbackContext = getChangingValue(stub, "callbackContexts");

            if (stub.callbackAsync) {
                nextTick(function() {
                    func.apply(callbackContext, callbackArguments);
                });
            } else {
                func.apply(callbackContext, callbackArguments);
            }
        }
    }

    var uuid = 0;

    sinon.extend(stub, (function () {
        var slice = Array.prototype.slice, proto;

        function throwsException(error, message) {
            if (typeof error == "string") {
                this.exception = new Error(message || "");
                this.exception.name = error;
            } else if (!error) {
                this.exception = new Error("Error");
            } else {
                this.exception = error;
            }

            return this;
        }

        proto = {
            create: function create() {
                var functionStub = function () {

                    callCallback(functionStub, arguments);

                    if (functionStub.exception) {
                        throw functionStub.exception;
                    } else if (typeof functionStub.returnArgAt == 'number') {
                        return arguments[functionStub.returnArgAt];
                    } else if (functionStub.returnThis) {
                        return this;
                    }
                    return functionStub.returnValue;
                };

                functionStub.id = "stub#" + uuid++;
                var orig = functionStub;
                functionStub = sinon.spy.create(functionStub);
                functionStub.func = orig;
                functionStub._super_reset = functionStub.reset;

                functionStub.callArgAts = [];
                functionStub.callbackArguments = [];
                functionStub.callbackContexts = [];
                functionStub.callArgProps = [];

                sinon.extend(functionStub, stub);
                functionStub._create = sinon.stub.create;
                functionStub.displayName = "stub";
                functionStub.toString = sinon.functionToString;

                return functionStub;
            },

            reset: function () {
                this._super_reset();
                this.callArgAts = [];
                this.callbackArguments = [];
                this.callbackContexts = [];
                this.callArgProps = [];
            },

            returns: function returns(value) {
                this.returnValue = value;

                return this;
            },

            returnsArg: function returnsArg(pos) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }

                this.returnArgAt = pos;

                return this;
            },

            returnsThis: function returnsThis() {
                this.returnThis = true;

                return this;
            },

            "throws": throwsException,
            throwsException: throwsException,

            callsArg: function callsArg(pos) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }

                this.callArgAts.push(pos);
                this.callbackArguments.push([]);
                this.callbackContexts.push(undefined);
                this.callArgProps.push(undefined);

                return this;
            },

            callsArgOn: function callsArgOn(pos, context) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }
                if (typeof context != "object") {
                    throw new TypeError("argument context is not an object");
                }

                this.callArgAts.push(pos);
                this.callbackArguments.push([]);
                this.callbackContexts.push(context);
                this.callArgProps.push(undefined);

                return this;
            },

            callsArgWith: function callsArgWith(pos) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }

                this.callArgAts.push(pos);
                this.callbackArguments.push(slice.call(arguments, 1));
                this.callbackContexts.push(undefined);
                this.callArgProps.push(undefined);

                return this;
            },

            callsArgOnWith: function callsArgWith(pos, context) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }
                if (typeof context != "object") {
                    throw new TypeError("argument context is not an object");
                }

                this.callArgAts.push(pos);
                this.callbackArguments.push(slice.call(arguments, 2));
                this.callbackContexts.push(context);
                this.callArgProps.push(undefined);

                return this;
            },

            yields: function () {
                this.callArgAts.push(-1);
                this.callbackArguments.push(slice.call(arguments, 0));
                this.callbackContexts.push(undefined);
                this.callArgProps.push(undefined);

                return this;
            },

            yieldsOn: function (context) {
                if (typeof context != "object") {
                    throw new TypeError("argument context is not an object");
                }

                this.callArgAts.push(-1);
                this.callbackArguments.push(slice.call(arguments, 1));
                this.callbackContexts.push(context);
                this.callArgProps.push(undefined);

                return this;
            },

            yieldsTo: function (prop) {
                this.callArgAts.push(-1);
                this.callbackArguments.push(slice.call(arguments, 1));
                this.callbackContexts.push(undefined);
                this.callArgProps.push(prop);

                return this;
            },

            yieldsToOn: function (prop, context) {
                if (typeof context != "object") {
                    throw new TypeError("argument context is not an object");
                }

                this.callArgAts.push(-1);
                this.callbackArguments.push(slice.call(arguments, 2));
                this.callbackContexts.push(context);
                this.callArgProps.push(prop);

                return this;
            }
        };

        // create asynchronous versions of callsArg* and yields* methods
        for (var method in proto) {
            // need to avoid creating anotherasync versions of the newly added async methods
            if (proto.hasOwnProperty(method) &&
                method.match(/^(callsArg|yields|thenYields$)/) &&
                !method.match(/Async/)) {
                proto[method + 'Async'] = (function (syncFnName) {
                    return function () {
                        this.callbackAsync = true;
                        return this[syncFnName].apply(this, arguments);
                    };
                })(method);
            }
        }

        return proto;

    }()));

    if (commonJSModule) {
        module.exports = stub;
    } else {
        sinon.stub = stub;
    }
}(typeof sinon == "object" && sinon || null));
<commit_msg>calling spy.reset directly from stub.reset<commit_after>/**
 * @depend ../sinon.js
 * @depend spy.js
 */
/*jslint eqeqeq: false, onevar: false*/
/*global module, require, sinon*/
/**
 * Stub functions
 *
 * @author Christian Johansen (christian@cjohansen.no)
 * @license BSD
 *
 * Copyright (c) 2010-2011 Christian Johansen
 */
"use strict";

(function (sinon) {
    var commonJSModule = typeof module == "object" && typeof require == "function";

    if (!sinon && commonJSModule) {
        sinon = require("../sinon");
    }

    if (!sinon) {
        return;
    }

    function stub(object, property, func) {
        if (!!func && typeof func != "function") {
            throw new TypeError("Custom stub should be function");
        }

        var wrapper;

        if (func) {
            wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
        } else {
            wrapper = stub.create();
        }

        if (!object && !property) {
            return sinon.stub.create();
        }

        if (!property && !!object && typeof object == "object") {
            for (var prop in object) {
                if (typeof object[prop] === "function") {
                    stub(object, prop);
                }
            }

            return object;
        }

        return sinon.wrapMethod(object, property, wrapper);
    }

    function getChangingValue(stub, property) {
        var index = stub.callCount - 1;
        var prop = index in stub[property] ? stub[property][index] : stub[property + "Last"];
        stub[property + "Last"] = prop;

        return prop;
    }

    function getCallback(stub, args) {
        var callArgAt = getChangingValue(stub, "callArgAts");

        if (callArgAt < 0) {
            var callArgProp = getChangingValue(stub, "callArgProps");

            for (var i = 0, l = args.length; i < l; ++i) {
                if (!callArgProp && typeof args[i] == "function") {
                    return args[i];
                }

                if (callArgProp && args[i] &&
                    typeof args[i][callArgProp] == "function") {
                    return args[i][callArgProp];
                }
            }

            return null;
        }

        return args[callArgAt];
    }

    var join = Array.prototype.join;

    function getCallbackError(stub, func, args) {
        if (stub.callArgAtsLast < 0) {
            var msg;

            if (stub.callArgPropsLast) {
                msg = sinon.functionName(stub) +
                    " expected to yield to '" + stub.callArgPropsLast +
                    "', but no object with such a property was passed."
            } else {
                msg = sinon.functionName(stub) +
                            " expected to yield, but no callback was passed."
            }

            if (args.length > 0) {
                msg += " Received [" + join.call(args, ", ") + "]";
            }

            return msg;
        }

        return "argument at index " + stub.callArgAtsLast + " is not a function: " + func;
    }

    var nextTick = (function () {
        if (typeof process === "object" && typeof process.nextTick === "function") {
            return process.nextTick;
        } else if (typeof msSetImmediate === "function") {
            return msSetImmediate.bind(window);
        } else if (typeof setImmediate === "function") {
            return setImmediate;
        } else {
            return function (callback) {
                setTimeout(callback, 0);
            };
        }
    })();

    function callCallback(stub, args) {
        if (stub.callArgAts.length > 0) {
            var func = getCallback(stub, args);

            if (typeof func != "function") {
                throw new TypeError(getCallbackError(stub, func, args));
            }

            var index = stub.callCount - 1;

            var callbackArguments = getChangingValue(stub, "callbackArguments");
            var callbackContext = getChangingValue(stub, "callbackContexts");

            if (stub.callbackAsync) {
                nextTick(function() {
                    func.apply(callbackContext, callbackArguments);
                });
            } else {
                func.apply(callbackContext, callbackArguments);
            }
        }
    }

    var uuid = 0;

    sinon.extend(stub, (function () {
        var slice = Array.prototype.slice, proto;

        function throwsException(error, message) {
            if (typeof error == "string") {
                this.exception = new Error(message || "");
                this.exception.name = error;
            } else if (!error) {
                this.exception = new Error("Error");
            } else {
                this.exception = error;
            }

            return this;
        }

        proto = {
            create: function create() {
                var functionStub = function () {

                    callCallback(functionStub, arguments);

                    if (functionStub.exception) {
                        throw functionStub.exception;
                    } else if (typeof functionStub.returnArgAt == 'number') {
                        return arguments[functionStub.returnArgAt];
                    } else if (functionStub.returnThis) {
                        return this;
                    }
                    return functionStub.returnValue;
                };

                functionStub.id = "stub#" + uuid++;
                var orig = functionStub;
                functionStub = sinon.spy.create(functionStub);
                functionStub.func = orig;

                functionStub.callArgAts = [];
                functionStub.callbackArguments = [];
                functionStub.callbackContexts = [];
                functionStub.callArgProps = [];

                sinon.extend(functionStub, stub);
                functionStub._create = sinon.stub.create;
                functionStub.displayName = "stub";
                functionStub.toString = sinon.functionToString;

                return functionStub;
            },

            reset: function () {
                sinon.spy.reset.call(this);
                this.callArgAts = [];
                this.callbackArguments = [];
                this.callbackContexts = [];
                this.callArgProps = [];
            },

            returns: function returns(value) {
                this.returnValue = value;

                return this;
            },

            returnsArg: function returnsArg(pos) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }

                this.returnArgAt = pos;

                return this;
            },

            returnsThis: function returnsThis() {
                this.returnThis = true;

                return this;
            },

            "throws": throwsException,
            throwsException: throwsException,

            callsArg: function callsArg(pos) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }

                this.callArgAts.push(pos);
                this.callbackArguments.push([]);
                this.callbackContexts.push(undefined);
                this.callArgProps.push(undefined);

                return this;
            },

            callsArgOn: function callsArgOn(pos, context) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }
                if (typeof context != "object") {
                    throw new TypeError("argument context is not an object");
                }

                this.callArgAts.push(pos);
                this.callbackArguments.push([]);
                this.callbackContexts.push(context);
                this.callArgProps.push(undefined);

                return this;
            },

            callsArgWith: function callsArgWith(pos) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }

                this.callArgAts.push(pos);
                this.callbackArguments.push(slice.call(arguments, 1));
                this.callbackContexts.push(undefined);
                this.callArgProps.push(undefined);

                return this;
            },

            callsArgOnWith: function callsArgWith(pos, context) {
                if (typeof pos != "number") {
                    throw new TypeError("argument index is not number");
                }
                if (typeof context != "object") {
                    throw new TypeError("argument context is not an object");
                }

                this.callArgAts.push(pos);
                this.callbackArguments.push(slice.call(arguments, 2));
                this.callbackContexts.push(context);
                this.callArgProps.push(undefined);

                return this;
            },

            yields: function () {
                this.callArgAts.push(-1);
                this.callbackArguments.push(slice.call(arguments, 0));
                this.callbackContexts.push(undefined);
                this.callArgProps.push(undefined);

                return this;
            },

            yieldsOn: function (context) {
                if (typeof context != "object") {
                    throw new TypeError("argument context is not an object");
                }

                this.callArgAts.push(-1);
                this.callbackArguments.push(slice.call(arguments, 1));
                this.callbackContexts.push(context);
                this.callArgProps.push(undefined);

                return this;
            },

            yieldsTo: function (prop) {
                this.callArgAts.push(-1);
                this.callbackArguments.push(slice.call(arguments, 1));
                this.callbackContexts.push(undefined);
                this.callArgProps.push(prop);

                return this;
            },

            yieldsToOn: function (prop, context) {
                if (typeof context != "object") {
                    throw new TypeError("argument context is not an object");
                }

                this.callArgAts.push(-1);
                this.callbackArguments.push(slice.call(arguments, 2));
                this.callbackContexts.push(context);
                this.callArgProps.push(prop);

                return this;
            }
        };

        // create asynchronous versions of callsArg* and yields* methods
        for (var method in proto) {
            // need to avoid creating anotherasync versions of the newly added async methods
            if (proto.hasOwnProperty(method) &&
                method.match(/^(callsArg|yields|thenYields$)/) &&
                !method.match(/Async/)) {
                proto[method + 'Async'] = (function (syncFnName) {
                    return function () {
                        this.callbackAsync = true;
                        return this[syncFnName].apply(this, arguments);
                    };
                })(method);
            }
        }

        return proto;

    }()));

    if (commonJSModule) {
        module.exports = stub;
    } else {
        sinon.stub = stub;
    }
}(typeof sinon == "object" && sinon || null));
<|endoftext|>


<commit_before>const RangeFinder = require('./range-finder')
const shuffle = require('array-shuffle')
const naturalSort = require('javascript-natural-sort')

module.exports = {
  activate () {
    atom.commands.add('atom-text-editor:not([mini])', {
      'sort-lines:sort' () {
        sortLines(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:reverse-sort' () {
        sortLinesReversed(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:unique' () {
        uniqueLines(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:case-insensitive-sort' () {
        sortLinesInsensitive(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:natural' () {
        sortLinesNatural(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:by-length' () {
        sortLinesByLength(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:shuffle' () {
        shuffleLines(atom.workspace.getActiveTextEditor())
      }
    })
  }
}

function sortTextLines (editor, sorter) {
  const sortableRanges = RangeFinder.rangesFor(editor)
  sortableRanges.forEach((range) => {
    const textLines = editor.getTextInBufferRange(range).split(/\r?\n/g)
    const sortedTextLines = sorter(textLines)
    editor.setTextInBufferRange(range, sortedTextLines.join('\n'))
  })
}

function sortLines (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort((a, b) => a.localeCompare(b))
  )
}

function sortLinesReversed (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort((a, b) => b.localeCompare(a))
  )
}

function uniqueLines (editor) {
  sortTextLines(editor,
    (textLines) => Array.from(new Set(textLines))
  )
}

function sortLinesInsensitive (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
  )
}

function sortLinesNatural (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort(naturalSort)
  )
}

function sortLinesByLength (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort((a, b) => a.length - b.length)
  )
}

function shuffleLines (editor) {
  sortTextLines(editor,
    (textLines) => shuffle(textLines)
  )
}
<commit_msg>Dispose of disposables on deactivation<commit_after>const RangeFinder = require('./range-finder')
const shuffle = require('array-shuffle')
const naturalSort = require('javascript-natural-sort')

module.exports = {
  activate () {
    this.commandsDisposable = atom.commands.add('atom-text-editor:not([mini])', {
      'sort-lines:sort' () {
        sortLines(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:reverse-sort' () {
        sortLinesReversed(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:unique' () {
        uniqueLines(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:case-insensitive-sort' () {
        sortLinesInsensitive(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:natural' () {
        sortLinesNatural(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:by-length' () {
        sortLinesByLength(atom.workspace.getActiveTextEditor())
      },
      'sort-lines:shuffle' () {
        shuffleLines(atom.workspace.getActiveTextEditor())
      }
    })
  },

  deactivate () {
    this.commandsDisposable.dispose()
  }
}

function sortTextLines (editor, sorter) {
  const sortableRanges = RangeFinder.rangesFor(editor)
  sortableRanges.forEach((range) => {
    const textLines = editor.getTextInBufferRange(range).split(/\r?\n/g)
    const sortedTextLines = sorter(textLines)
    editor.setTextInBufferRange(range, sortedTextLines.join('\n'))
  })
}

function sortLines (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort((a, b) => a.localeCompare(b))
  )
}

function sortLinesReversed (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort((a, b) => b.localeCompare(a))
  )
}

function uniqueLines (editor) {
  sortTextLines(editor,
    (textLines) => Array.from(new Set(textLines))
  )
}

function sortLinesInsensitive (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
  )
}

function sortLinesNatural (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort(naturalSort)
  )
}

function sortLinesByLength (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort((a, b) => a.length - b.length)
  )
}

function shuffleLines (editor) {
  sortTextLines(editor,
    (textLines) => shuffle(textLines)
  )
}
<|endoftext|>


<commit_before>/**
 * Cangraph
 *
 * Graphing and function plotting for the HTML5 canvas. Main function plotting
 * engine was taken from the link below and modified.
 *
 * @link http://www.javascripter.net/faq/plotafunctiongraph.htm
 *
 * @todo Allow setting into nesting objects for better organization
 * @todo Make plot able to ignore negative values for y
 */
(function ($) {

    /**
     * Constructor and initialization
     *
     * @class Cangraph
     *
     * @param {String} canvasId The canvas element to draw on
     * @param {Object} options Allows us to change defaults upon instantiation
     */
    function Cangraph(canvasId, options) {
        var defaults = {
            axes: {
                xOffset: 0,
                yOffset: 0,
                scale: 40,
                showNegativeX: true,
                showNegativeY: true,
                strokeColor: '#000000',
                showX: true,
                showY: true,
                markings: {
                    showX: true,
                    showY: true,
                    xInterval: 10,
                    yInterval: 10,
                    xHeight: 5,
                    yWidth: 5
                }
            },
            graph: {
                strokeColor: '#1fcd38',
                lineWidth: '1',
                scale: 4
            },
            point: {
                strokeColor: '#e61a3f',
                lineWidth: 11,
                radius: 3,
                fillColor: '#000000'
            }
        };
        var canvas;

        // Set canvas and context
        this.set('canvasId', canvasId);
        canvas = document.getElementById(this.canvasId);
        this.set('canvas', canvas);
        this.setContext();

        // Merge defaults with passed in options
        this.options = options || {};
        this.options = $.extend(true, {}, defaults, this.options);

        this.setDerivedAxesProperties();
        this.setDerivedGraphProperties();
    }

    /**
     * Determines if a value is undefined or null and presents and error message
     *
     * @method validate
     *
     * @param {String} name Description for value
     * @param {Mixed} value To validate
     */
    Cangraph.prototype.validate = function (name, value) {
        if (value === null || typeof value === 'undefined') {
            console.log(name, 'is undefined or null!');

            return false;
        }

        return true;
    };

    /**
     * Basic setter to help provide validation and error checking
     *
     * @method set
     *
     * @param {String} name Member name to store value
     * @param {Mixed} value To store in member name
     */
    Cangraph.prototype.set = function (name, value) {
        if (this.validate(name, value)) {
            this[name] = value;
        }
    };

    /**
     * Set canvas context for later use
     *
     * @method setContext
     */
    Cangraph.prototype.setContext = function () {
        var context = this.canvas.getContext('2d');

        this.set('context', context);
    };

    /**
     * Set axes properties, that can be derived from base values, for later use
     *
     * @method setDerivedAxesProperties
     */
    Cangraph.prototype.setDerivedAxesProperties = function () {
        this.set('x0', this.options.axes.xOffset + .5 * this.canvas.width);
        this.set('y0', this.options.axes.yOffset + .5 * this.canvas.height);

        if (this.options.axes.showNegativeX) {
            this.set('xMin', 0);
        } else {
            this.set('xMin', this.x0);
        }
    };

    /**
     * Set graph properties, that can be derived from base values, for later
     * use.
     *
     * @method setDerivedGraphProperties
     */
    Cangraph.prototype.setDerivedGraphProperties = function () {
        this.set('graphPlottingMax', Math.round((this.canvas.width - this.x0) / this.options.graph.scale));

        if (this.options.axes.showNegativeX) {
            this.set('graphPlottingMin', Math.round(-this.x0 / this.options.graph.scale));
        } else {
            this.set('graphPlottingMin', 0);
        }
    };

    /**
     * Allows us to draw the axes of the graph
     *
     * @method drawAxes
     *
     * @todo Keep axes markings separate from axes lines?
     */
    Cangraph.prototype.drawAxes = function () {
        this.context.beginPath();
        this.context.strokeStyle = this.options.axes.strokeColor;

        if (this.options.axes.showX) {
            this.context.moveTo(this.xMin, this.y0);
            this.context.lineTo(this.canvas.width, this.y0);
        }
        if (this.options.axes.showY) {
            if (this.options.axes.showNegativeY) {
                this.context.moveTo(this.x0, 0);
                this.context.lineTo(this.x0, this.canvas.height);
            } else {
                this.context.moveTo(this.x0, -this.y0);
                this.context.lineTo(this.x0, Math.ceil(this.canvas.height / 2));
            }
        }

        if (this.options.axes.markings.showX) {
            this.drawXAxisMarkings();
        }
        if (this.options.axes.markings.showY) {
            this.drawYAxisMarkings();
        }

        this.context.stroke();
    };

    /**
     * Draws markings for x-axis
     *
     * @method drawXAxisMarkings
     */
    Cangraph.prototype.drawXAxisMarkings = function () {
        var iX;
        var iXMax;
        var iXMaxScale = Math.ceil((this.canvas.width - this.xMin) / this.options.axes.markings.xInterval);

        if (this.options.axes.showNegativeX) {
            iX = 0;
            iXMax = Math.ceil(this.canvas.width - this.xMin);
        } else {
            iX = Math.ceil(this.canvas.width / 2);
            iXMax = this.canvas.width;
        }

        for (iX; iX <= iXMax; iX += 1) {
            if (iX % iXMaxScale === 0) {
                this.context.moveTo(iX, this.y0 + this.options.axes.markings.xHeight);
                this.context.lineTo(iX, this.y0 - this.options.axes.markings.xHeight);
                this.context.strokeStyle = this.options.axes.strokeColor;
            }
        }
    };

    /**
     * Draws markings for y-axis
     *
     * @method drawYAxisMarkings
     */
    Cangraph.prototype.drawYAxisMarkings = function () {
        var iY;
        var iYMax;
        var iYMaxScale = Math.ceil(this.canvas.height / this.options.axes.markings.yInterval);
        var halfCanvasHeight = Math.ceil(this.canvas.height / 2);

        if (this.options.axes.showNegativeY) {
            iY = 0;
            iYMax = Math.ceil(this.canvas.width - this.xMin);
        } else {
            iY = halfCanvasHeight;
            iYMax = this.canvas.height;
        }

        if (this.options.axes.markings.showY) {
            for (iY; iY <= iYMax; iY += 1) {
                if (iY % iYMaxScale === 0) {
                    this.context.moveTo(this.options.axes.markings.yWidth + halfCanvasHeight, iY);
                    this.context.lineTo(-this.options.axes.markings.yWidth + halfCanvasHeight, iY);
                    this.context.strokeStyle = this.options.axes.strokeColor;
                }
            }
        }
    };

    /**
     * Plots a function and draws it as a graph
     *
     * @method drawGraph
     *
     * @param {Function} fx Function to plot
     * @param {String} color Optional color value to override default
     */
    Cangraph.prototype.drawGraph = function (fx, color) {
        var x;
        var y;
        var i;
        var fx;

        this.context.beginPath();

        // Set up line options
        this.context.lineWidth = this.options.graph.lineWidth;
        if (typeof color !== 'undefined') {
            this.context.strokeStyle = color;
        } else {
            this.context.strokeStyle = this.options.graph.strokeColor;
        }

        // Loop for function plotting
        for (i = this.graphPlottingMin; i <= this.graphPlottingMax; i += 1) {
            x = this.options.graph.scale * i;
            y = this.options.axes.scale * fx(x / this.options.axes.scale);

            if (i === this.graphPlottingMin) {
                // Run only for the first iteration
                this.context.moveTo(this.x0 + x, this.y0 - y);
            } else {
                this.context.lineTo(this.x0 + x, this.y0 - y);
            }
        }

        this.context.stroke();
        this.context.closePath();
    };

    /**
     * Finds a single point on a function and plots it
     *
     * @method drawPlottedValue
     *
     * @param {Function} fx Function to plot point for
     * @param {Integer} value X value point to plot
     */
    Cangraph.prototype.drawPlottedValue = function (fx, value) {
        var x;
        var y;
        var j;

        this.context.beginPath();
        this.context.moveTo(this.x0 + x, this.y0 - y);

        x = this.options.graph.scale * value;
        y = this.options.axes.scale * fx(x / this.options.axes.scale);

        this.context.arc(this.x0 + x, this.y0 - y, this.options.point.radius, 0, Math.PI * 2, false);
        this.context.strokeStyle = this.options.point.strokeColor;
        this.context.lineWidth = this.options.point.lineWidth;
        this.context.stroke();
        this.context.fillStyle = this.options.point.fillColor;
        this.context.fill();
        this.context.closePath();
    };

    // Attach object to global namespace
    this.Cangraph = Cangraph;
}).call(this, $);<commit_msg>Add code/naming clarify<commit_after>/**
 * Cangraph
 *
 * Graphing and function plotting for the HTML5 canvas. Main function plotting
 * engine was taken from the link below and modified.
 *
 * @link http://www.javascripter.net/faq/plotafunctiongraph.htm
 *
 * @todo Allow setting into nesting objects for better organization
 * @todo Make plot able to ignore negative values for y
 * @todo Write standalone merge function to eliminate need for jquery
 */
(function ($) {

    /**
     * Constructor and initialization
     *
     * @class Cangraph
     *
     * @param {String} canvasId The canvas element to draw on
     * @param {Object} options Allows us to override defaults upon instantiation
     */
    function Cangraph(canvasId, options) {
        var defaults = {
            axes: {
                xOffset: 0,
                yOffset: 0,
                scale: 40,
                showNegativeX: true,
                showNegativeY: true,
                strokeColor: '#000000',
                showX: true,
                showY: true,
                markings: {
                    showX: true,
                    showY: true,
                    xInterval: 10,
                    yInterval: 10,
                    xHeight: 5,
                    yWidth: 5
                }
            },
            graph: {
                strokeColor: '#1fcd38',
                lineWidth: 3,
                smoothnessScale: 4
            },
            point: {
                strokeColor: '#e61a3f',
                lineWidth: 11,
                radius: 3,
                fillColor: '#000000'
            }
        };
        var canvas;

        // Set canvas and context
        this.set('canvasId', canvasId);
        canvas = document.getElementById(this.canvasId);
        this.set('canvas', canvas);
        this.setContext();

        // Merge defaults with passed in options
        this.options = options || {};
        this.options = $.extend(true, {}, defaults, this.options);

        this.setDerivedAxesProperties();
        this.setDerivedGraphProperties();
    }

    /**
     * Determines if a value is undefined or null and presents and error message
     *
     * @method validate
     *
     * @param {String} name Description for value
     * @param {Mixed} value To validate
     */
    Cangraph.prototype.validate = function (name, value) {
        if (value === null || typeof value === 'undefined') {
            console.log(name, 'is undefined or null!');

            return false;
        }

        return true;
    };

    /**
     * Basic setter to help provide validation and error checking
     *
     * @method set
     *
     * @param {String} name Member name to store value
     * @param {Mixed} value To store in member name
     */
    Cangraph.prototype.set = function (name, value) {
        if (this.validate(name, value)) {
            this[name] = value;
        }
    };

    /**
     * Set canvas context for later use
     *
     * @method setContext
     */
    Cangraph.prototype.setContext = function () {
        var context = this.canvas.getContext('2d');

        this.set('context', context);
    };

    /**
     * Set axes properties, that can be derived from base values, for later use
     *
     * @method setDerivedAxesProperties
     */
    Cangraph.prototype.setDerivedAxesProperties = function () {
        this.set('x0', this.options.axes.xOffset + .5 * this.canvas.width);
        this.set('y0', this.options.axes.yOffset + .5 * this.canvas.height);

        if (this.options.axes.showNegativeX) {
            this.set('xMin', 0);
        } else {
            this.set('xMin', this.x0);
        }
    };

    /**
     * Set graph properties, that can be derived from base values, for later
     * use.
     *
     * @method setDerivedGraphProperties
     */
    Cangraph.prototype.setDerivedGraphProperties = function () {
        this.set('graphPlottingMax', Math.round((this.canvas.width - this.x0) / this.options.graph.smoothnessScale));

        if (this.options.axes.showNegativeX) {
            this.set('graphPlottingMin', Math.round(-this.x0 / this.options.graph.smoothnessScale));
        } else {
            this.set('graphPlottingMin', 0);
        }
    };

    /**
     * Allows us to draw the axes of the graph
     *
     * @method drawAxes
     *
     * @todo Keep axes markings separate from axes lines?
     */
    Cangraph.prototype.drawAxes = function () {
        this.context.beginPath();
        this.context.strokeStyle = this.options.axes.strokeColor;

        if (this.options.axes.showX) {
            this.context.moveTo(this.xMin, this.y0);
            this.context.lineTo(this.canvas.width, this.y0);
        }
        if (this.options.axes.showY) {
            if (this.options.axes.showNegativeY) {
                this.context.moveTo(this.x0, 0);
                this.context.lineTo(this.x0, this.canvas.height);
            } else {
                this.context.moveTo(this.x0, -this.y0);
                this.context.lineTo(this.x0, Math.ceil(this.canvas.height / 2));
            }
        }

        if (this.options.axes.markings.showX) {
            this.drawXAxisMarkings();
        }
        if (this.options.axes.markings.showY) {
            this.drawYAxisMarkings();
        }

        this.context.stroke();
    };

    /**
     * Draws markings for x-axis
     *
     * @method drawXAxisMarkings
     */
    Cangraph.prototype.drawXAxisMarkings = function () {
        var iX;
        var iXMax;
        var iXMaxScale = Math.ceil((this.canvas.width - this.xMin) / this.options.axes.markings.xInterval);

        if (this.options.axes.showNegativeX) {
            iX = 0;
            iXMax = Math.ceil(this.canvas.width - this.xMin);
        } else {
            iX = Math.ceil(this.canvas.width / 2);
            iXMax = this.canvas.width;
        }

        for (iX; iX <= iXMax; iX += 1) {
            if (iX % iXMaxScale === 0) {
                this.context.moveTo(iX, this.y0 + this.options.axes.markings.xHeight);
                this.context.lineTo(iX, this.y0 - this.options.axes.markings.xHeight);
                this.context.strokeStyle = this.options.axes.strokeColor;
            }
        }
    };

    /**
     * Draws markings for y-axis
     *
     * @method drawYAxisMarkings
     */
    Cangraph.prototype.drawYAxisMarkings = function () {
        var iY;
        var iYMax;
        var iYMaxScale = Math.ceil(this.canvas.height / this.options.axes.markings.yInterval);
        var halfCanvasHeight = Math.ceil(this.canvas.height / 2);

        if (this.options.axes.showNegativeY) {
            iY = 0;
            iYMax = Math.ceil(this.canvas.width - this.xMin);
        } else {
            iY = halfCanvasHeight;
            iYMax = this.canvas.height;
        }

        if (this.options.axes.markings.showY) {
            for (iY; iY <= iYMax; iY += 1) {
                if (iY % iYMaxScale === 0) {
                    this.context.moveTo(this.options.axes.markings.yWidth + halfCanvasHeight, iY);
                    this.context.lineTo(-this.options.axes.markings.yWidth + halfCanvasHeight, iY);
                    this.context.strokeStyle = this.options.axes.strokeColor;
                }
            }
        }
    };

    /**
     * Plots a function and draws it as a graph
     *
     * @method drawGraph
     *
     * @param {Function} fx Function to plot
     * @param {String} color Optional color value to override default
     */
    Cangraph.prototype.drawGraph = function (fx, color) {
        var x;
        var y;
        var i;

        this.context.beginPath();

        // Set up line options
        this.context.lineWidth = this.options.graph.lineWidth;
        if (typeof color !== 'undefined') {
            this.context.strokeStyle = color;
        } else {
            this.context.strokeStyle = this.options.graph.strokeColor;
        }

        // Loop for function plotting
        for (i = this.graphPlottingMin; i <= this.graphPlottingMax; i += 1) {
            x = this.options.graph.smoothnessScale * i;
            y = this.options.axes.scale * fx(x / this.options.axes.scale);

            if (i === this.graphPlottingMin) {
                // Run only for the first iteration
                this.context.moveTo(this.x0 + x, this.y0 - y);
            } else {
                this.context.lineTo(this.x0 + x, this.y0 - y);
            }
        }

        this.context.stroke();
        this.context.closePath();
    };

    /**
     * Finds a single point on a function and plots it
     *
     * @method drawPlottedValue
     *
     * @param {Function} fx Function to plot point for
     * @param {Integer} value X value point to plot
     */
    Cangraph.prototype.drawPlottedValue = function (fx, value) {
        var x;
        var y;
        var j;

        this.context.beginPath();
        this.context.moveTo(this.x0 + x, this.y0 - y);

        x = this.options.graph.smoothnessScale * value;
        y = this.options.axes.scale * fx(x / this.options.axes.scale);

        this.context.arc(this.x0 + x, this.y0 - y, this.options.point.radius, 0, Math.PI * 2, false);
        this.context.strokeStyle = this.options.point.strokeColor;
        this.context.lineWidth = this.options.point.lineWidth;
        this.context.stroke();
        this.context.fillStyle = this.options.point.fillColor;
        this.context.fill();
        this.context.closePath();
    };

    // Attach object to global namespace
    this.Cangraph = Cangraph;
}).call(this, $);<|endoftext|>


<commit_before>/**
 * @license
 * js-data-structures <http://github.com/Tyriar/js-data-structures>
 * Copyright 2014 Daniel Imms <http://www.growingwiththeweb.com>
 * Released under the MIT license <http://github.com/Tyriar/js-data-structures/blob/master/LICENSE>
 */
'use strict';

if (typeof exports === 'object' && typeof define !== 'function') {
  var define = function (factory) {
    factory(require, exports, module);
  };
}

define(function (require, exports, module) {
  var BaseBinaryTree = require('./base-binary-tree');
  var BinaryTreeNode = require('./binary-tree-node');

  /**
   * Creates a splay tree.
   *
   * @constructor
   * @param {function} customCompare An optional custom node comparison
   * function.
   */
  var SplayTree = function (customCompare) {
    BaseBinaryTree.call(this);

    this.nodeCount = 0;

    if (customCompare) {
      this.compare = customCompare;
    }
  };

  SplayTree.prototype = Object.create(BaseBinaryTree.prototype);

  SplayTree.prototype.constructor = SplayTree;

  /**
   * Adds a key to the tree.
   *
   * @param {Object} key The key to add.
   * @return {boolean} Whether the node was added.
   */
  SplayTree.prototype.add = function (key) {
    if (!this.root) {
      this.root = new BinaryTreeNode(key);
      this.nodeCount++;
      return true;
    }

    var wasAdded = insertInternal(this, key, this.root);
    this.contains(key);
    return wasAdded;
  };

  SplayTree.prototype.contains = function (key) {
    if (!this.root) {
      return false;
    }

    var node = containsInternal(this, key, this.root);
    if (node) {
      splay(this, node);
    }
    return !!node;
  };

  SplayTree.prototype.findMaximum = function () {
    if (!this.root) {
      return undefined;
    }

    var current = this.root;
    while (true) {
      if (current.right) {
        current = current.right;
      } else {
        return current.key;
      }
    }
  };

  SplayTree.prototype.findMinimum = function () {
    if (!this.root) {
      return undefined;
    }

    var current = this.root;
    while (true) {
      if (current.left) {
        current = current.left;
      } else {
        return current.key;
      }
    }
  };

  SplayTree.prototype.isEmpty = function () {
    return !this.root;
  };

  SplayTree.prototype.remove = function (key) {
    if (!this.root) {
      return false;
    }

    this.contains(key);
    return removeInternal(this, key, this.root);
  };

  SplayTree.prototype.size = function () {
    return this.nodeCount;
  };

  SplayTree.prototype.compare = function (a, b) {
    if (a > b) {
      return 1;
    }
    if (a < b) {
      return -1;
    }
    return 0;
  };

  function rotateLeft(tree, x) {
    var y = x.right;
    x.right = y.left;
    if (y.left) {
      y.left.parent = x;
    }
    y.parent = x.parent;
    if (!x.parent) {
      tree.root = y;
    } else {
      if (x === x.parent.left) {
        x.parent.left = y;
      } else {
        x.parent.right = y;
      }
    }
    y.left = x;
    x.parent = y;
  }

  function rotateRight(tree, x) {
    var y = x.left;
    x.left = y.right;
    if (y.right) {
      y.right.parent = x;
    }
    y.parent = x.parent;
    if (!x.parent) {
      tree.root = y;
    } else {
      if (x === x.parent.left) {
        x.parent.left = y;
      } else {
        x.parent.right = y;
      }
    }
    y.right = x;
    x.parent = y;
  }

  function insertInternal(tree, key, node) {
    if (tree.compare(key, node.key) < 0) {
      if (node.left) {
        return insertInternal(tree, key, node.left);
      } else {
        node.left = new BinaryTreeNode(key, node);
        tree.nodeCount++;
        return true;
      }
    }

    if (tree.compare(key, node.key) > 0) {
      if (node.right) {
        return insertInternal(tree, key, node.right);
      } else {
        node.right = new BinaryTreeNode(key, node);
        tree.nodeCount++;
        return true;
      }
    }

    return false;
  }

  function containsInternal(tree, key, node) {
    if (key === node.key) {
      return node;
    }

    if (tree.compare(key, node.key) < 0) {
      if (!node.left) {
        return undefined;
      }
      return containsInternal(tree, key, node.left);
    }

    if (tree.compare(key, node.key) > 0) {
      if (!node.right) {
        return undefined;
      }
      return containsInternal(tree, key, node.right);
    }

    return undefined;
  }

  function removeInternal(tree, key, node) {
    if (tree.compare(key, node.key) < 0) {
      if (node.left) {
        return removeInternal(tree, key, node.left);
      }
      return false;
    }

    if (tree.compare(key, node.key) > 0) {
      if (node.right) {
        return removeInternal(tree, key, node.right);
      }
      return false;
    }

    return removeInternal2(tree, node);
  }

  function removeInternal2(tree, node) {
    if (!node.left && !node.right) {
      removeNodeWithNoChildren(tree, node);
      return true;
    }

    if (node.left && !node.right) {
      removeNodeWithLeftOnly(tree, node);
      return true;
    }

    if (node.right && !node.left) {
      removeNodeWithRightOnly(tree, node);
      return true;
    }

    // both exist, replace with node minimum from right sub-tree and delete the
    // node from the right sub-tree
    var minParent = findParentOfMinimum(node.right, node);
    var minNode = minParent.left ? minParent.left : minParent.right;
    var newKey = minNode.key;
    removeInternal2(tree, minNode);
    node.key = newKey;

    return true;
  }

  function removeNodeWithNoChildren(tree, node) {
    if (node.parent) {
      node.parent.removeChild(node);
    } else {
      tree.root = undefined;
    }
    tree.nodeCount--;
  }

  function removeNodeWithLeftOnly(tree, node) {
    node.key = node.left.key;
    node.right = node.left.right;
    if (node.right) {
      node.right.parent = node;
    }
    node.left = node.left.left;
    if (node.left) {
      node.left.parent = node;
    }
    tree.nodeCount--;
  }

  function removeNodeWithRightOnly(tree, node) {
    node.key = node.right.key;
    node.left = node.right.left;
    if (node.left) {
      node.left.parent = node;
    }
    node.right = node.right.right;
    if (node.right) {
      node.right.parent = node;
    }
    tree.nodeCount--;
  }

  function splay(tree, node) {
    while (node.parent) {
      var parent = node.parent;
      if (!parent.parent) {
        if (parent.left === node) {
          rotateRight(tree, parent);
        } else {
          rotateLeft(tree, parent);
        }
      } else {
        var gparent = parent.parent;
        if (parent.left === node && gparent.left === parent) {
          rotateRight(tree, gparent);
          rotateRight(tree, node.parent);
        } else if (parent.right === node && gparent.right === parent) {
          rotateLeft(tree, gparent);
          rotateLeft(tree, node.parent);
        } else if (parent.left === node && gparent.right === parent) {
          rotateRight(tree, parent);
          rotateLeft(tree, node.parent);
        } else {
          rotateLeft(tree, parent);
          rotateRight(tree, node.parent);
        }
      }
    }
  }

  function findParentOfMinimum(node, parent) {
    if (!node.left) {
      return parent;
    }

    return findParentOfMinimum(node.left, node);
  }

  module.exports = SplayTree;
});
<commit_msg>jsdoc<commit_after>/**
 * @license
 * js-data-structures <http://github.com/Tyriar/js-data-structures>
 * Copyright 2014 Daniel Imms <http://www.growingwiththeweb.com>
 * Released under the MIT license <http://github.com/Tyriar/js-data-structures/blob/master/LICENSE>
 */
'use strict';

if (typeof exports === 'object' && typeof define !== 'function') {
  var define = function (factory) {
    factory(require, exports, module);
  };
}

define(function (require, exports, module) {
  var BaseBinaryTree = require('./base-binary-tree');
  var BinaryTreeNode = require('./binary-tree-node');

  /**
   * Creates a splay tree.
   *
   * @constructor
   * @param {function} customCompare An optional custom node comparison
   * function.
   */
  var SplayTree = function (customCompare) {
    BaseBinaryTree.call(this);

    this.nodeCount = 0;

    if (customCompare) {
      this.compare = customCompare;
    }
  };

  SplayTree.prototype = Object.create(BaseBinaryTree.prototype);

  SplayTree.prototype.constructor = SplayTree;

  /**
   * Adds a key to the tree.
   *
   * @param {Object} key The key to add.
   * @return {boolean} Whether the node was added.
   */
  SplayTree.prototype.add = function (key) {
    if (!this.root) {
      this.root = new BinaryTreeNode(key);
      this.nodeCount++;
      return true;
    }

    var wasAdded = insertInternal(this, key, this.root);
    this.contains(key);
    return wasAdded;
  };

  /**
   * Determines whether the tree contains a key.
   *
   * @param {Object} key The key to check.
   * @return {boolean} Whether the node contains the key.
   */
  SplayTree.prototype.contains = function (key) {
    if (!this.root) {
      return false;
    }

    var node = containsInternal(this, key, this.root);
    if (node) {
      splay(this, node);
    }
    return !!node;
  };

  SplayTree.prototype.findMaximum = function () {
    if (!this.root) {
      return undefined;
    }

    var current = this.root;
    while (true) {
      if (current.right) {
        current = current.right;
      } else {
        return current.key;
      }
    }
  };

  SplayTree.prototype.findMinimum = function () {
    if (!this.root) {
      return undefined;
    }

    var current = this.root;
    while (true) {
      if (current.left) {
        current = current.left;
      } else {
        return current.key;
      }
    }
  };

  SplayTree.prototype.isEmpty = function () {
    return !this.root;
  };

  SplayTree.prototype.remove = function (key) {
    if (!this.root) {
      return false;
    }

    this.contains(key);
    return removeInternal(this, key, this.root);
  };

  SplayTree.prototype.size = function () {
    return this.nodeCount;
  };

  SplayTree.prototype.compare = function (a, b) {
    if (a > b) {
      return 1;
    }
    if (a < b) {
      return -1;
    }
    return 0;
  };

  function rotateLeft(tree, x) {
    var y = x.right;
    x.right = y.left;
    if (y.left) {
      y.left.parent = x;
    }
    y.parent = x.parent;
    if (!x.parent) {
      tree.root = y;
    } else {
      if (x === x.parent.left) {
        x.parent.left = y;
      } else {
        x.parent.right = y;
      }
    }
    y.left = x;
    x.parent = y;
  }

  function rotateRight(tree, x) {
    var y = x.left;
    x.left = y.right;
    if (y.right) {
      y.right.parent = x;
    }
    y.parent = x.parent;
    if (!x.parent) {
      tree.root = y;
    } else {
      if (x === x.parent.left) {
        x.parent.left = y;
      } else {
        x.parent.right = y;
      }
    }
    y.right = x;
    x.parent = y;
  }

  function insertInternal(tree, key, node) {
    if (tree.compare(key, node.key) < 0) {
      if (node.left) {
        return insertInternal(tree, key, node.left);
      } else {
        node.left = new BinaryTreeNode(key, node);
        tree.nodeCount++;
        return true;
      }
    }

    if (tree.compare(key, node.key) > 0) {
      if (node.right) {
        return insertInternal(tree, key, node.right);
      } else {
        node.right = new BinaryTreeNode(key, node);
        tree.nodeCount++;
        return true;
      }
    }

    return false;
  }

  function containsInternal(tree, key, node) {
    if (key === node.key) {
      return node;
    }

    if (tree.compare(key, node.key) < 0) {
      if (!node.left) {
        return undefined;
      }
      return containsInternal(tree, key, node.left);
    }

    if (tree.compare(key, node.key) > 0) {
      if (!node.right) {
        return undefined;
      }
      return containsInternal(tree, key, node.right);
    }

    return undefined;
  }

  function removeInternal(tree, key, node) {
    if (tree.compare(key, node.key) < 0) {
      if (node.left) {
        return removeInternal(tree, key, node.left);
      }
      return false;
    }

    if (tree.compare(key, node.key) > 0) {
      if (node.right) {
        return removeInternal(tree, key, node.right);
      }
      return false;
    }

    return removeInternal2(tree, node);
  }

  function removeInternal2(tree, node) {
    if (!node.left && !node.right) {
      removeNodeWithNoChildren(tree, node);
      return true;
    }

    if (node.left && !node.right) {
      removeNodeWithLeftOnly(tree, node);
      return true;
    }

    if (node.right && !node.left) {
      removeNodeWithRightOnly(tree, node);
      return true;
    }

    // both exist, replace with node minimum from right sub-tree and delete the
    // node from the right sub-tree
    var minParent = findParentOfMinimum(node.right, node);
    var minNode = minParent.left ? minParent.left : minParent.right;
    var newKey = minNode.key;
    removeInternal2(tree, minNode);
    node.key = newKey;

    return true;
  }

  function removeNodeWithNoChildren(tree, node) {
    if (node.parent) {
      node.parent.removeChild(node);
    } else {
      tree.root = undefined;
    }
    tree.nodeCount--;
  }

  function removeNodeWithLeftOnly(tree, node) {
    node.key = node.left.key;
    node.right = node.left.right;
    if (node.right) {
      node.right.parent = node;
    }
    node.left = node.left.left;
    if (node.left) {
      node.left.parent = node;
    }
    tree.nodeCount--;
  }

  function removeNodeWithRightOnly(tree, node) {
    node.key = node.right.key;
    node.left = node.right.left;
    if (node.left) {
      node.left.parent = node;
    }
    node.right = node.right.right;
    if (node.right) {
      node.right.parent = node;
    }
    tree.nodeCount--;
  }

  function splay(tree, node) {
    while (node.parent) {
      var parent = node.parent;
      if (!parent.parent) {
        if (parent.left === node) {
          rotateRight(tree, parent);
        } else {
          rotateLeft(tree, parent);
        }
      } else {
        var gparent = parent.parent;
        if (parent.left === node && gparent.left === parent) {
          rotateRight(tree, gparent);
          rotateRight(tree, node.parent);
        } else if (parent.right === node && gparent.right === parent) {
          rotateLeft(tree, gparent);
          rotateLeft(tree, node.parent);
        } else if (parent.left === node && gparent.right === parent) {
          rotateRight(tree, parent);
          rotateLeft(tree, node.parent);
        } else {
          rotateLeft(tree, parent);
          rotateRight(tree, node.parent);
        }
      }
    }
  }

  function findParentOfMinimum(node, parent) {
    if (!node.left) {
      return parent;
    }

    return findParentOfMinimum(node.left, node);
  }

  module.exports = SplayTree;
});
<|endoftext|>


<commit_before>'use strict';
const _ = require('lodash');
const path = require('path');
const globalModulesPath = require('global-modules');
const readPackageJson = require('../in/read-package-json');
const globalPackages = require('../in/get-installed-packages');
const emoji = require('../out/emoji');
const fs = require('fs');
const chalk = require('chalk');

function init(currentState, userOptions) {
    return new Promise((resolve, reject) => {
        _.each(userOptions, (value, key) => currentState.set(key, value));

        if (currentState.get('global')) {

            if (process.env.NODE_PATH && !fs.existsSync(process.env.NODE_PATH)) {
                throw new Error('process.env.NODE_PATH does not exist. Please check the environment variables.');
            }

            const modulesPath = process.env.NODE_PATH || globalModulesPath;

            console.log(chalk.green('The global path you are searching is: ' + modulesPath));

            currentState.set('cwd', globalModulesPath);
            currentState.set('nodeModulesPath', globalModulesPath);
            currentState.set('globalPackages', globalPackages(modulesPath));
        } else {
            const cwd = path.resolve(currentState.get('cwd'));
            const pkg = readPackageJson(path.join(cwd, 'package.json'));
            currentState.set('cwdPackageJson', pkg);
            currentState.set('cwd', cwd);
            currentState.set('nodeModulesPath', path.join(cwd, 'node_modules'));
        }

        emoji.enabled(currentState.get('emoji'));

        if (currentState.get('cwdPackageJson').error) {
            return reject(currentState.get('cwdPackageJson').error);
        }

        return resolve(currentState);
    });
}

module.exports = init;
<commit_msg>Fix resolution of NODE_PATH<commit_after>'use strict';
const _ = require('lodash');
const path = require('path');
const globalModulesPath = require('global-modules');
const readPackageJson = require('../in/read-package-json');
const globalPackages = require('../in/get-installed-packages');
const emoji = require('../out/emoji');
const fs = require('fs');
const chalk = require('chalk');

function init(currentState, userOptions) {
    return new Promise((resolve, reject) => {
        _.each(userOptions, (value, key) => currentState.set(key, value));

        if (currentState.get('global')) {
            let modulesPath = globalModulesPath;

            if (process.env.NODE_PATH) {
                if (process.env.NODE_PATH.indexOf(':') !== -1) {
                    modulesPath = process.env.NODE_PATH.split(':')[0];
                    console.log(chalk.yellow('warning: Using the first of multiple paths specified in NODE_PATH'));
                } else {
                    modulesPath = process.env.NODE_PATH;
                }
            }

            if (!fs.existsSync(modulesPath)) {
                throw new Error('Path "' + modulesPath + '" does not exist. Please check the NODE_PATH environment variable.');
            }

            console.log(chalk.green('The global path you are searching is: ' + modulesPath));

            currentState.set('cwd', globalModulesPath);
            currentState.set('nodeModulesPath', globalModulesPath);
            currentState.set('globalPackages', globalPackages(modulesPath));
        } else {
            const cwd = path.resolve(currentState.get('cwd'));
            const pkg = readPackageJson(path.join(cwd, 'package.json'));
            currentState.set('cwdPackageJson', pkg);
            currentState.set('cwd', cwd);
            currentState.set('nodeModulesPath', path.join(cwd, 'node_modules'));
        }

        emoji.enabled(currentState.get('emoji'));

        if (currentState.get('cwdPackageJson').error) {
            return reject(currentState.get('cwdPackageJson').error);
        }

        return resolve(currentState);
    });
}

module.exports = init;
<|endoftext|>


<commit_before>var LEVELS = require('./levels');

var SEP = '.';
var ROOT = 'root';

function parentNames(name) {
  var names = [];
  var parts = name.split(SEP);
  while(parts.length) {
    names.push(parts.join(SEP));
    parts.pop();
  }
  names.push(ROOT);
  return names;
}

/**
 * Produce log records. It could not be create manuall,
 * always use LoggerFactory instance to create loggers.
 *
 * @param {LoggerFactory} factory factory, holding this logger
 * @param {string} name    name of this logger
 * @class
 */
function Logger(factory, name) {
  this._names = parentNames(name);
  this._factory = factory;
}

Logger.prototype = {
  /**
   * Create log record with given level and arguments.
   * Usually not used.
   *
   * @param  {number} level Log level
   * @param  {Array} args   Arguments
   */
  log: function(level, args) {
    this._factory.log(this._names, level, args);
  }
}

var SLICE = Array.prototype.slice;

function defineLogLevelMethod(name, level) {
  Logger.prototype[name] = function() {
    this.log(level, SLICE.call(arguments));
  }
}

/**
 * Create log record with level trace
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last
 * @name trace
 */
defineLogLevelMethod('trace', LEVELS.TRACE);

/**
 * Create log record with level debug
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last
 * @name debug
 */
defineLogLevelMethod('debug', LEVELS.DEBUG);

/**
 * Create log record with level info
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last
 * @name info
 */
defineLogLevelMethod('info' , LEVELS.INFO );

/**
 * Create log record with level warn
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last
 * @name warn
 */
defineLogLevelMethod('warn' , LEVELS.WARN );

/**
 * Create log record with level error
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last
 * @name error
 */
defineLogLevelMethod('error', LEVELS.ERROR);

Logger.ROOT = ROOT;

module.exports = Logger;
<commit_msg>Add more docs for logger<commit_after>var LEVELS = require('./levels');

var SEP = '.';
var ROOT = 'root';

function parentNames(name) {
  var names = [];
  var parts = name.split(SEP);
  while(parts.length) {
    names.push(parts.join(SEP));
    parts.pop();
  }
  names.push(ROOT);
  return names;
}

/**
 * Produce log records. It could not be create manuall,
 * always use LoggerFactory instance to create loggers.
 *
 * @param {LoggerFactory} factory factory, holding this logger
 * @param {string} name    name of this logger
 * @class
 */
function Logger(factory, name) {
  this._names = parentNames(name);
  this._factory = factory;
}

Logger.prototype = {
  /**
   * Create log record with given level and arguments.
   * Usually not used.
   *
   * @param  {number} level Log level
   * @param  {Array} args   Arguments
   * @private
   */
  log: function(level, args) {
    this._factory.log(this._names, level, args);
  }
}

var SLICE = Array.prototype.slice;

function defineLogLevelMethod(name, level) {
  Logger.prototype[name] = function() {
    this.log(level, SLICE.call(arguments));
  }
}

/**
 * Create log record with level TRACE. If first argument is string, it is used as message format, like console.log do.
 * Supported modifiers %s, %d, %j, %%. If you want to output error, it must be one among all arguments and be last.
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last.
 * @name trace
 * @example
 *
 * logger.trace('User entered %s', userInput);
 *
 * logger.error('Error happen while sending email', err);
 */
defineLogLevelMethod('trace', LEVELS.TRACE);

/**
 * Create log record with level DEBUG. If first argument is string, it is used as message format, like console.log do.
 * Supported modifiers %s, %d, %j, %%. If you want to output error, it must be one among all arguments and be last.
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last.
 * @name trace
 * @example
 *
 * logger.trace('User entered %s', userInput);
 *
 * logger.error('Error happen while sending email', err);
 */
defineLogLevelMethod('debug', LEVELS.DEBUG);

/**
 * Create log record with level INFO. If first argument is string, it is used as message format, like console.log do.
 * Supported modifiers %s, %d, %j, %%. If you want to output error, it must be one among all arguments and be last.
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last.
 * @name trace
 * @example
 *
 * logger.trace('User entered %s', userInput);
 *
 * logger.error('Error happen while sending email', err);
 */
defineLogLevelMethod('info' , LEVELS.INFO );

/**
 * Create log record with level WARN. If first argument is string, it is used as message format, like console.log do.
 * Supported modifiers %s, %d, %j, %%. If you want to output error, it must be one among all arguments and be last.
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last.
 * @name trace
 * @example
 *
 * logger.trace('User entered %s', userInput);
 *
 * logger.error('Error happen while sending email', err);
 */
defineLogLevelMethod('warn' , LEVELS.WARN );

/**
 * Create log record with level ERROR. If first argument is string, it is used as message format, like console.log do.
 * Supported modifiers %s, %d, %j, %%. If you want to output error, it must be one among all arguments and be last.
 *
 * @memberof Logger
 * @instance
 * @param {...*} args Any arguments. Error must be one and last.
 * @name trace
 * @example
 *
 * logger.trace('User entered %s', userInput);
 *
 * logger.error('Error happen while sending email', err);
 */
defineLogLevelMethod('error', LEVELS.ERROR);

Logger.ROOT = ROOT;

module.exports = Logger;
<|endoftext|>


<commit_before>'use strict';
const debug         = require('debug')('mongo-pubsub:subscriber'),
      toFactory     = require('tofactory'),
      createEmitter = require('create-emitter'),
      axon          = require('axon'),
      Cache         = require('./cache');

module.exports = toFactory(Subscriber);

function Subscriber(spec) {
    let cache;

    const sub       = axon.socket('sub-emitter'),
          emitter   = createEmitter.create();

    const _return = {
        connect,
        on: emitter.on,
        off: emitter.off
    };

    init();

    return _return;

    function init() {
        cache = Cache.create(spec);

        sub.on('*:*:*', function (collection, operation, _id, data) {
            const route = `${collection}:${operation}:${_id}`;

            switch (operation) {
                case 'update':
                    cache.sync(collection, _id, data,
                        function (err, changes, doc) {
                            if (err) return debug(err);
                            emitter.emit(route, changes);
                            emitter.emit(route + ':$cache', changes, doc);
                        });
                    break;
                case 'insert':
                    cache.insert(collection, _id, data);
                    emitter.emit(route, data);
                    break;
                case 'remove':
                    cache.remove(collection, _id);
                    emitter.emit(route);
            }
        });
    }

    function connect(arg) {
        if (arg) {
            sub.connect(arg);
        } else {
            sub.connect(spec.connect);
        }
        return _return;
    }
}<commit_msg>changed route with cache<commit_after>'use strict';
const debug         = require('debug')('mongo-pubsub:subscriber'),
      toFactory     = require('tofactory'),
      createEmitter = require('create-emitter'),
      axon          = require('axon'),
      Cache         = require('./cache');

module.exports = toFactory(Subscriber);

function Subscriber(spec) {
    let cache;

    const sub       = axon.socket('sub-emitter'),
          emitter   = createEmitter.create();

    const _return = {
        connect,
        on: emitter.on,
        off: emitter.off
    };

    init();

    return _return;

    function init() {
        cache = Cache.create(spec);

        sub.on('*:*:*', function (collection, operation, _id, data) {
            const route             = `${collection}:${operation}:${_id}`,
                  routeWithCache    = route + `:$${collection}`;

            switch (operation) {
                case 'update':
                    cache.sync(collection, _id, data,
                        function (err, changes, doc) {
                            if (err) return debug(err);
                            emitter.emit(route, changes);
                            emitter.emit(routeWithCache, changes, doc);
                        });
                    break;
                case 'insert':
                    cache.insert(collection, _id, data);
                    emitter.emit(route, data);
                    break;
                case 'remove':
                    cache.remove(collection, _id);
                    emitter.emit(route);
            }
        });
    }

    function connect(arg) {
        if (arg) {
            sub.connect(arg);
        } else {
            sub.connect(spec.connect);
        }
        return _return;
    }
}<|endoftext|>


<commit_before>'use strict'

const
  Task = require('../Task'),
  helpers = require('../helpers'),
  chalk = require('chalk'),
  compiler = global.compiler || require('riot-compiler'),
  path = require('path'),
  sh = require('shelljs'),
  co = require('co'),
  constants = require('./../const'),
  START_FRAG = constants.MODULAR_START_FRAG,
  END_FRAG = constants.MODULAR_END_FRAG

/**
 * Compile the tags using the riot-compiler
 */
class Make extends Task {
  run(opt) {
    // Generate a list of input/output files
    const
      isStdin = opt.flow[0] == 's',
      isStdout = opt.flow[1] == 's',
      isInputFile = opt.flow[0] == 'f',
      isOutputFile = opt.flow[1] == 'f',
      from = isStdin ? null
        : isInputFile ? [opt.from]
        : helpers.find(this.extRegex, opt.from),
      base = isStdin ? process.cwd
        : isInputFile ? path.dirname(opt.from)
        : opt.from,
      to = isStdout ? null
        : isOutputFile ? [opt.to]
        : helpers.remap(this.extRegex, from, opt.to, base, opt.export)

    // Create any necessary dirs
    if (!isStdout) to.forEach(f => sh.mkdir('-p', path.dirname(f)))

    // extend the compiler parsers
    if (opt.parsers)
      helpers.extend(compiler.parsers, opt.parsers)

    // Process files
    if (isStdout)
      this.toStdout(from, opt)
    else if (isOutputFile)
      this.toFile(from, to, opt)
    else
      this.toDir(from, to, opt)

    /**
     * Print what's been done (unless --silent)
     * note that opt.compiler.silent is always true when opt.stdout is true
     */
    /* istanbul ignore next */
    if (!opt.compiler.silent) {
      from.forEach((src, i) => {
        helpers.log(
          chalk.blue(helpers.toRelative(src)) +
          chalk.cyan(' -> ') +
          chalk.green(helpers.toRelative(to[i] || to[0]))
        )
      })
    }

    return true
  }

  /**
   * Write all the tags compiled in a single file on the file system
   * @param { Array } from - source files array
   * @param { Object } opt - cli options
   * @returns { Promise } resolves when compilation has done
   */
  toStdout(from, opt) {
    return co(function* () {
      const compiled = from
        ? from.map(f => parse(helpers.readFile(f), opt, f)).join('\n')
        : parse(yield helpers.readStdin(), opt, '')
      const wrapped = encapsulate(compiled, opt)

      // Output to stdout
      process.stdout.write(wrapped)
    })
  }

  /**
   * Write all the tags compiled in a single file on the file system
   * @param { Array } from - source files array
   * @param { String } to - output path
   * @param { Object } opt - cli options
   * @returns { Promise } resolves when compilation has done
   */
  toFile(from, to, opt) {
    return co(function* () {
      const compiled = from
        ? from.map(f => parse(helpers.readFile(f), opt, f)).join('\n')
        : parse(yield helpers.readStdin(), opt, '')
      const wrapped = encapsulate(compiled, opt)

      // Save to a file
      sh.ShellString(wrapped).to(to[0])
    })
  }

  /**
   * Write all the tags compiled in several files on the file system
   * @param   { Array } from - source files array
   * @param   { Array } to - output folder
   * @param   { Object } opt - cli options
   */
  toDir(from, to, opt) {
    from.forEach((f, i) => {
      const compiled = parse(helpers.readFile(f), opt, f)
      const wrapped = encapsulate(compiled, opt)
      sh.ShellString(wrapped).to(to[i])
    })
  }
}

/**
 * Compile the source files using the riot-compiler
 * @param { String } tag - tag source
 * @param { Object } opt - cli options
 * @param { String } url - tag file path
 * @returns { String } riot-compiler output
 */
function parse (tag, opt, url) {
  let out
  try {
    out = compiler.compile(tag, opt.compiler, url)
  } catch (e) {
    helpers.err(e)
  }
  // take only the css
  if (opt.export)
    return out.reduce((prev, curr) => prev + curr[opt.export], '')
  else return out
}

/**
 * Wrap the generated tags using a default UMD wrapper
 * @param { String } from - source files array
 * @param { Object } opt - cli options
 * @returns { String } wrapped output
 */
function encapsulate (from, opt) {
  return !opt.compiler.modular ? from : `${START_FRAG}${from}${END_FRAG}`
}

module.exports = Make
<commit_msg>Partially restores to previous code<commit_after>'use strict'

const
  Task = require('../Task'),
  helpers = require('../helpers'),
  chalk = require('chalk'),
  compiler = global.compiler || require('riot-compiler'),
  path = require('path'),
  sh = require('shelljs'),
  co = require('co'),
  constants = require('./../const'),
  START_FRAG = constants.MODULAR_START_FRAG,
  END_FRAG = constants.MODULAR_END_FRAG

/**
 * Compile the tags using the riot-compiler
 */
class Make extends Task {
  run(opt) {
    // Generate a list of input/output files
    const
      isStdin = opt.flow[0] == 's',
      isStdout = opt.flow[1] == 's',
      isInputFile = opt.flow[0] == 'f',
      isOutputFile = opt.flow[1] == 'f',
      from = isStdin ? null
        : isInputFile ? [opt.from]
        : helpers.find(this.extRegex, opt.from),
      base = isStdin ? process.cwd
        : isInputFile ? path.dirname(opt.from)
        : opt.from,
      to = isStdout ? null
        : isOutputFile ? [opt.to]
        : helpers.remap(this.extRegex, from, opt.to, base, opt.export)

    // Create any necessary dirs
    if (!isStdout) to.forEach(f => sh.mkdir('-p', path.dirname(f)))

    // extend the compiler parsers
    if (opt.parsers)
      helpers.extend(compiler.parsers, opt.parsers)

    // Process files
    if (isStdout)
      this.toStdout(from, opt)
    else if (isOutputFile)
      this.toFile(from, to, opt)
    else
      this.toDir(from, to, opt)

    /**
     * Print what's been done (unless --silent)
     * note that opt.compiler.silent is always true when opt.stdout is true
     */
    /* istanbul ignore next */
    if (!opt.compiler.silent) {
      (from || [false]).forEach((src, i) => {
        helpers.log(
          chalk.blue(!src ? 'stdin' : helpers.toRelative(src)) +
          chalk.cyan(' -> ') +
          chalk.green(helpers.toRelative(to[i] || to[0]))
        )
      })
    }

    return true
  }

  /**
   * Write all the tags compiled in a single file on the file system
   * @param { Array } from - source files array
   * @param { Object } opt - cli options
   * @returns { Promise } resolves when compilation has done
   */
  toStdout(from, opt) {
    return co(function* () {
      const compiled = from
        ? from.map(f => parse(helpers.readFile(f), opt, f)).join('\n')
        : parse(yield helpers.readStdin(), opt, '')
      const wrapped = encapsulate(compiled, opt)

      // Output to stdout
      process.stdout.write(wrapped)
    })
  }

  /**
   * Write all the tags compiled in a single file on the file system
   * @param { Array } from - source files array
   * @param { String } to - output path
   * @param { Object } opt - cli options
   * @returns { Promise } resolves when compilation has done
   */
  toFile(from, to, opt) {
    return co(function* () {
      const compiled = from
        ? from.map(f => parse(helpers.readFile(f), opt, f)).join('\n')
        : parse(yield helpers.readStdin(), opt, '')
      const wrapped = encapsulate(compiled, opt)

      // Save to a file
      sh.ShellString(wrapped).to(to[0])
    })
  }

  /**
   * Write all the tags compiled in several files on the file system
   * @param   { Array } from - source files array
   * @param   { Array } to - output folder
   * @param   { Object } opt - cli options
   */
  toDir(from, to, opt) {
    from.forEach((f, i) => {
      const compiled = parse(helpers.readFile(f), opt, f)
      const wrapped = encapsulate(compiled, opt)
      sh.ShellString(wrapped).to(to[i])
    })
  }
}

/**
 * Compile the source files using the riot-compiler
 * @param { String } tag - tag source
 * @param { Object } opt - cli options
 * @param { String } url - tag file path
 * @returns { String } riot-compiler output
 */
function parse (tag, opt, url) {
  let out
  try {
    out = compiler.compile(tag, opt.compiler, url)
  } catch (e) {
    helpers.err(e)
  }
  // take only the css
  if (opt.export)
    return out.reduce((prev, curr) => prev + curr[opt.export], '')
  else return out
}

/**
 * Wrap the generated tags using a default UMD wrapper
 * @param { String } from - source files array
 * @param { Object } opt - cli options
 * @returns { String } wrapped output
 */
function encapsulate (from, opt) {
  return !opt.compiler.modular ? from : `${START_FRAG}${from}${END_FRAG}`
}

module.exports = Make
<|endoftext|>


<commit_before>'use strict';

var path         = require('path')
    fs           = require('fs'),
    gutil        = require('gulp-util'),
    through      = require('through2'),
    querystring  = require('querystring'),
    lodashMerge  = require('lodash.merge'),
    childProcess = require('child_process');

var yargs    = require('../util/yargs'),
    streams  = require('../config/streams'),
    platform = require('../config/platform');

var defaultReporterName = 'karma-angularity-reporter';

var basePathRegex               = /['"]?\s*\/\*+\s*ANGULARITY_BASE_PATH\s*\*+\/\s*['"]?/ ;
var filesAppendRegex            = /\/\*+\s*ANGULARITY_FILE_LIST\s*\*+\// ;
var reportersAppendRegex        = /\/\*+\s*ANGULARITY_REPORTER_LIST\s*\*+\// ;
var pluginsAppendRegex          = /\/\*+\s*ANGULARITY_PLUGIN_LIST\s*\*+\// ;
var karmaReporterMatchNameRegex = /^karma-(.+)-reporter$/ ;

/**
 * Determine the `require` path for a plugin.
 * Note that this require path must be absolute,
 * as it will not be required within this project,
 * but rather by the karma runner - and therefore the current directory
 * cannot be predicted.
 *
 * @param {string} reporterName Either a package name,
 *   *OR* an absolute path, for a karma reporter.
 * @return {string} In karma config file, `plugins` will be inline `require`d
 *   using this return value.
 */
function getKarmaReporterPluginPath(reporterName) {
  if (typeof reporterName !== 'string') {
    throw 'Reporter name is unspecified';
  }

  //Default reporter is a dependency of angularity
  var reporterPath = (reporterName === defaultReporterName) ?
    path.resolve(__dirname, '../../node_modules', defaultReporterName) :
    reporterName;
  //Specific reporters are expected to be dependencies of the local project
  reporterPath = (path.dirname(reporterPath) === '.') ?
    path.resolve('node_modules', 'karma-' + reporterName + '-reporter') :
    reporterPath;

  //Either way, the absolute path of the reporter is `require`d
  //Only to determine if it is indeed `require`able,
  //and enable fail fast if it is not.
  try {
    require(reporterPath);
  }
  catch (ex) {
    throw 'Attempt to require reporter from path ' + reporterPath + ' with no success.';
  }
  reporterPath = path.normalize(reporterPath);

  if (platform.isWindows()) {
    //Sanitise path for Windows
    //Replace any single backslash characters in file paths with
    //double backslash on windows; neither path.normalize nor path.resolve do this
    reporterPath = reporterPath.replace( /\\/g , '\\\\' );
  }
  return reporterPath;
}

/**
 * Determine the registered reporter name.
 *
 * @param {string} reporterName Either the registered reporter name, or an absolute path for a karma reporter.
 * @return {string} The registered reporter name for use in the `reporters` section of the karma config file.
 */
function getKarmaReporterName(reporterName) {
  if (typeof reporterName !== 'string') {
    throw 'Get Karma Reporter Name: Reporter name is unspecified';
  }

  var name = (path.dirname(reporterName) === '.') ?
    reporterName :
    path.basename(reporterName);
  var match = karmaReporterMatchNameRegex.exec(name);
  if (!!match && match.length === 2) {
    name = match[1];
  }
  return name;
}

/**
 * Create a through2 object stream.
 * Expects all the `*.js` files to be included as the files list in the karma conf
 * Creates a new karma config file, based on the karma config file name found in
 * the local project root, and augments its file list by replacing
 * `ANGULARITY_FILE_LIST` in ablock comment with the actual array of files.
 * The new karma config file is added to the stream,
 * All input `*.js` files are filtered out of the stream
 *
 * @param {Array.<string>} [reporters] The name of the karma reporter to use
 * @param {string} [configFileName] The project local karma config file to augment
 *   Defaults to "karma.conf.js"
 * @return {stream.Through} The output of this stream is expected to contain
 *   just one file: the augmented karma config file.
 */
function karmaCreateConfig(reporters, configFileName) {
  reporters = reporters || [];
  configFileName = configFileName || 'karma.conf.js';
  var files      = [ ];
  var additional = [
    {
      pattern : '**/*.js',
      included: false
    }, {
      pattern : '**/*.map',
      included: false
    }, {
      pattern : '**/*.spec.js',
      included: false
    }
  ];

  // add the bundles
  function transformFn(file, encoding, done) {
    if (!file || !file.path) {
      throw 'Files must have paths';
    }
    if (path.extname(file.path) === '.js') {
      files.push(file.relative);
    }
    done();
  }
  function flushFn(done) {
    function requirePlugins(reporter) {
      return 'require("' + getKarmaReporterPluginPath(reporter) + '")';
    }
    function encode(value) {
      return JSON.stringify(value, null, 2).replace(/\"/g, '\'');
    }
    var filePath = path.resolve(configFileName);
    var contents = fs.readFileSync(filePath).toString()
      .replace(basePathRegex,        encode(process.cwd()))
      .replace(filesAppendRegex,     encode(files.concat(additional)))
      .replace(reportersAppendRegex, encode(reporters.map(getKarmaReporterName)))
      .replace(pluginsAppendRegex,   '[\n' + reporters.map(requirePlugins).join(',\n') + '\n]');
    this.push(new gutil.File({
      path    : filePath,
      contents: new Buffer(contents)
    }));
    done();
  }
  return through.obj(transformFn, flushFn);
}

/**
 * Run karma once only with the karma config file present in the input stream.
 * No output. Ends when the Karma process ends.
 * Runs karma in a child process, to avoid `process.exit()` called by karma.
 *
 * @returns {stream.Through} A through stream intended to have a gulp stream piped through it
 */
function karmaRun() {
  var options = {
    configFile: undefined // populated from the input stream
  };
  function transformFn(file, encoding, done) {
    options.configFile = file.path;
    done();
  }
  function flushFn(done) {
    var appPath = path.join(__dirname, 'karma-background.js');
    var data    = querystring.escape(JSON.stringify(options));

    childProcess.spawn('node', [appPath, data], {
      cwd  : process.cwd(),
      stdio: 'inherit',
      env  : lodashMerge(process.env, {
        //NOTE this workaround is necessary, see issue:
        //https://github.com/sindresorhus/supports-color/issues/13
        //TODO @bguiz remove workaround when issue has been resolved
        SUPPORTS_COLOR: true
      })
    })
      .on('close', function() {
        done();
      });
  }
  return through.obj(transformFn, flushFn);
}

var yargsOptionDefinition = {
  key  : 'karma-reporter',
  value: {
    describe: 'Specify a custom Karma reporter to use. Either a locally npm installed module, or an asolute path to ' +
    'one.',
    alias   : ['k'],
    default : defaultReporterName,
    string  : true
  }
};
var checkKarmaReporter = yargs.createCheck()
  .withGate(function (argv) {
    return !argv.help;
  })
  .withTest({
    'karma-reporter': function(value) {
      if (typeof value !== 'undefined') {
        try {
          getKarmaReporterPluginPath(value);
        }
        catch (ex) {
          return 'Illegal value for "karma-reporter": ' + ex;
        }
      }
    }
  })
  .commit();

module.exports = {
  createConfig: karmaCreateConfig,
  run         : karmaRun,
  yargsCheck  : checkKarmaReporter,
  yargsOption : yargsOptionDefinition
};
<commit_msg>fix typo on require.<commit_after>'use strict';

var path         = require('path'),
    fs           = require('fs'),
    gutil        = require('gulp-util'),
    through      = require('through2'),
    querystring  = require('querystring'),
    lodashMerge  = require('lodash.merge'),
    childProcess = require('child_process');

var yargs    = require('../util/yargs'),
    streams  = require('../config/streams'),
    platform = require('../config/platform');

var defaultReporterName = 'karma-angularity-reporter';

var basePathRegex               = /['"]?\s*\/\*+\s*ANGULARITY_BASE_PATH\s*\*+\/\s*['"]?/ ;
var filesAppendRegex            = /\/\*+\s*ANGULARITY_FILE_LIST\s*\*+\// ;
var reportersAppendRegex        = /\/\*+\s*ANGULARITY_REPORTER_LIST\s*\*+\// ;
var pluginsAppendRegex          = /\/\*+\s*ANGULARITY_PLUGIN_LIST\s*\*+\// ;
var karmaReporterMatchNameRegex = /^karma-(.+)-reporter$/ ;

/**
 * Determine the `require` path for a plugin.
 * Note that this require path must be absolute,
 * as it will not be required within this project,
 * but rather by the karma runner - and therefore the current directory
 * cannot be predicted.
 *
 * @param {string} reporterName Either a package name,
 *   *OR* an absolute path, for a karma reporter.
 * @return {string} In karma config file, `plugins` will be inline `require`d
 *   using this return value.
 */
function getKarmaReporterPluginPath(reporterName) {
  if (typeof reporterName !== 'string') {
    throw 'Reporter name is unspecified';
  }

  //Default reporter is a dependency of angularity
  var reporterPath = (reporterName === defaultReporterName) ?
    path.resolve(__dirname, '../../node_modules', defaultReporterName) :
    reporterName;
  //Specific reporters are expected to be dependencies of the local project
  reporterPath = (path.dirname(reporterPath) === '.') ?
    path.resolve('node_modules', 'karma-' + reporterName + '-reporter') :
    reporterPath;

  //Either way, the absolute path of the reporter is `require`d
  //Only to determine if it is indeed `require`able,
  //and enable fail fast if it is not.
  try {
    require(reporterPath);
  }
  catch (ex) {
    throw 'Attempt to require reporter from path ' + reporterPath + ' with no success.';
  }
  reporterPath = path.normalize(reporterPath);

  if (platform.isWindows()) {
    //Sanitise path for Windows
    //Replace any single backslash characters in file paths with
    //double backslash on windows; neither path.normalize nor path.resolve do this
    reporterPath = reporterPath.replace( /\\/g , '\\\\' );
  }
  return reporterPath;
}

/**
 * Determine the registered reporter name.
 *
 * @param {string} reporterName Either the registered reporter name, or an absolute path for a karma reporter.
 * @return {string} The registered reporter name for use in the `reporters` section of the karma config file.
 */
function getKarmaReporterName(reporterName) {
  if (typeof reporterName !== 'string') {
    throw 'Get Karma Reporter Name: Reporter name is unspecified';
  }

  var name = (path.dirname(reporterName) === '.') ?
    reporterName :
    path.basename(reporterName);
  var match = karmaReporterMatchNameRegex.exec(name);
  if (!!match && match.length === 2) {
    name = match[1];
  }
  return name;
}

/**
 * Create a through2 object stream.
 * Expects all the `*.js` files to be included as the files list in the karma conf
 * Creates a new karma config file, based on the karma config file name found in
 * the local project root, and augments its file list by replacing
 * `ANGULARITY_FILE_LIST` in ablock comment with the actual array of files.
 * The new karma config file is added to the stream,
 * All input `*.js` files are filtered out of the stream
 *
 * @param {Array.<string>} [reporters] The name of the karma reporter to use
 * @param {string} [configFileName] The project local karma config file to augment
 *   Defaults to "karma.conf.js"
 * @return {stream.Through} The output of this stream is expected to contain
 *   just one file: the augmented karma config file.
 */
function karmaCreateConfig(reporters, configFileName) {
  reporters = reporters || [];
  configFileName = configFileName || 'karma.conf.js';
  var files      = [ ];
  var additional = [
    {
      pattern : '**/*.js',
      included: false
    }, {
      pattern : '**/*.map',
      included: false
    }, {
      pattern : '**/*.spec.js',
      included: false
    }
  ];

  // add the bundles
  function transformFn(file, encoding, done) {
    if (!file || !file.path) {
      throw 'Files must have paths';
    }
    if (path.extname(file.path) === '.js') {
      files.push(file.relative);
    }
    done();
  }
  function flushFn(done) {
    function requirePlugins(reporter) {
      return 'require("' + getKarmaReporterPluginPath(reporter) + '")';
    }
    function encode(value) {
      return JSON.stringify(value, null, 2).replace(/\"/g, '\'');
    }
    var filePath = path.resolve(configFileName);
    var contents = fs.readFileSync(filePath).toString()
      .replace(basePathRegex,        encode(process.cwd()))
      .replace(filesAppendRegex,     encode(files.concat(additional)))
      .replace(reportersAppendRegex, encode(reporters.map(getKarmaReporterName)))
      .replace(pluginsAppendRegex,   '[\n' + reporters.map(requirePlugins).join(',\n') + '\n]');
    this.push(new gutil.File({
      path    : filePath,
      contents: new Buffer(contents)
    }));
    done();
  }
  return through.obj(transformFn, flushFn);
}

/**
 * Run karma once only with the karma config file present in the input stream.
 * No output. Ends when the Karma process ends.
 * Runs karma in a child process, to avoid `process.exit()` called by karma.
 *
 * @returns {stream.Through} A through stream intended to have a gulp stream piped through it
 */
function karmaRun() {
  var options = {
    configFile: undefined // populated from the input stream
  };
  function transformFn(file, encoding, done) {
    options.configFile = file.path;
    done();
  }
  function flushFn(done) {
    var appPath = path.join(__dirname, 'karma-background.js');
    var data    = querystring.escape(JSON.stringify(options));

    childProcess.spawn('node', [appPath, data], {
      cwd  : process.cwd(),
      stdio: 'inherit',
      env  : lodashMerge(process.env, {
        //NOTE this workaround is necessary, see issue:
        //https://github.com/sindresorhus/supports-color/issues/13
        //TODO @bguiz remove workaround when issue has been resolved
        SUPPORTS_COLOR: true
      })
    })
      .on('close', function() {
        done();
      });
  }
  return through.obj(transformFn, flushFn);
}

var yargsOptionDefinition = {
  key  : 'karma-reporter',
  value: {
    describe: 'Specify a custom Karma reporter to use. Either a locally npm installed module, or an asolute path to ' +
    'one.',
    alias   : ['k'],
    default : defaultReporterName,
    string  : true
  }
};
var checkKarmaReporter = yargs.createCheck()
  .withGate(function (argv) {
    return !argv.help;
  })
  .withTest({
    'karma-reporter': function(value) {
      if (typeof value !== 'undefined') {
        try {
          getKarmaReporterPluginPath(value);
        }
        catch (ex) {
          return 'Illegal value for "karma-reporter": ' + ex;
        }
      }
    }
  })
  .commit();

module.exports = {
  createConfig: karmaCreateConfig,
  run         : karmaRun,
  yargsCheck  : checkKarmaReporter,
  yargsOption : yargsOptionDefinition
};
<|endoftext|>