<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

(function () {

// Test for equality any JavaScript type.
// Discussions and reference: http://philrathe.com/articles/equiv
// Test suites: http://philrathe.com/tests/equiv
// Author: Philippe Rathé <prathe@gmail.com>

// About passing arguments:
//      when < 2   : return true
//      when 2     : return true if 1st equals 2nd
//      when > 2   : return true 1st equals 2nd, and 2nd equals 3rd,
//                      and 3rd equals 4th ... ans so on (by transition)
//

// Stack of constructors that enables us to skip or abort on functions value.
var objectCallerConstructorStack = [];
function equiv() {
    // we will need to use the array splice method,
    // so we need to convert arguments into a true array.
    var args = Array.prototype.slice.apply(arguments);
    var a, b; // compares a and b (1st and 2nd argument)
    var i; // for iterating over objects convenience
    var len; // for iterating array's length memoization
    // Memoized objects' properties.
    // Allow us to test for equivalence only in one way,
    // then to compare properties to make sure no one is missing.
    var aProperties, bProperties;

    if (args.length < 2) {
        return true; // nothing to compare together
    }

    a = args[0];
    b = args[1];

    return (function (a, b) {

        // Try to optimize the algo speed if ever both a and b are references
        // pointing to the same object (e..g. only for functions, arrays and objects)
        if (a === b) {
            return true;
        }

        // Must test for the null value before testing for the type of an object,
        // because null is also an object. Trapping null or undefined values here
        // is a good to avoid to much validations further in the code.
        if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined") {
            return false; // Anyway (a === b) would have already caught it.
        }

        // Don't lose time and prevent further wrong type manipulation or unexpected results.
        if (typeof a !== typeof b) {
            return false;
        }

        // Must test if it's an array before testing for the type of an object,
        // because an array is also an object.
        if (a instanceof Array) {

            // Make sure b is also an array.
            // At this point b can be an object.
            // Prevent further arrays operation on object.
            if ( ! (b instanceof Array)) {
                return false;
            }

            len = a.length;
            if (len !== b.length) { // safe and faster
                return false;
            }
            for (i = 0; i < len; i++) {
                if( ! equiv(a[i], b[i])) {
                    return false;
                }
            }
            return true;
        }

        // NOTE:
        //      Must test if it's a date before testing if it is an object,
        //      because a date is also an object.
        if (a instanceof Date) {
            return b instanceof Date && a.valueOf() === b.valueOf();
        }

        // NOTE:
        //      Using toSource() to compare regexp only works in FF. It was working as well as the above.
        //      Must verify the constructor of a regexp before verifying it is an object.
        //      Notice those confusing true statements:
        //          var a = /./;
        //          a instanceof Object; // => true
        //          a instanceof RegExp; // => true
        //          typeof a === "function"; // => false in IE and Opera, true in FF and Safari
        //
        // There is 3 possible modifier for regular expressions (g, m and i)
        // The source property only returns the regular expression string without the modifier.
        if (a instanceof RegExp) {
            return b instanceof RegExp &&
                a.source === b.source &&
                a.global === b.global &&
                a.ignoreCase === b.ignoreCase &&
                a.multiline === b.multiline;
        }

        // typeof on some types returns sometimes unexpected type that we deals with.
        // We could have used instanceof instead of typeof but it comes with
        // other problems as mentioned above when testing for the RegExp constructor.
        // We explicitely don't use hasOwnProperty when iterating on the properties of
        // an object to allow a deeper equivalence (e.g. for instances particularly)
        if (typeof a === "object") {
            // Different constructors means a and b can't be equivalent instances.
            // We don't have any choice of comparing them in both ways because of inheritance
            // otherwise {} could be mistaken with []
            // NOTE this:
            //      var a = [];
            //      a instanceof Array;  // true
            //      a instanceof Object; // true
            if ( a.constructor !== b.constructor) {
                return false;
            }

            // Stack constructors before iterating over its properties
            objectCallerConstructorStack.push(a.constructor);

            aProperties = [];
            bProperties = [];

            // NOTE:
            //      We only need to compare propertie's equivalence in one way
            //      and ensures that all properties of a and b are the same.

            // Verify a's properties with b's properties equivalence.
            // Stack a's properties

            for (i in a) {
                aProperties.push(i);
                if (!equiv(a[i], b[i])) {
                    // Unstack current constructor when finished with the object
                    objectCallerConstructorStack.pop();
                    return false;
                }
            }

            // Stack also b's properties
            for (i in b) {
                bProperties.push(i);
            }

            // Unstack current constructor when finished with the object
            objectCallerConstructorStack.pop();

            // Ensures properties's name in both ways.
            // Must sort them because they may not be always in the same order!
            return equiv(aProperties.sort(), bProperties.sort());
        }

        // NOTE:
        //      Using the typeof operator will also catch a RegExp instance.
        //      Take no risk.
        if (a instanceof Function) {
            // BEHAVIOR when comparing functions.
            //      Being here means that a and b were were not the same references.
            //      At this level, functions won't be compared at all.
            //      - skip when they are properties of instances (not instantiates from the Object construtor)
            //      - abort otherwise
            //
            //      To Determine if a function is anonymous we use a regexp on the function sources.
            var currentObjectCallerConstructor =
                    objectCallerConstructorStack[objectCallerConstructorStack.length - 1];
            return currentObjectCallerConstructor !== Object &&
                    typeof currentObjectCallerConstructor !== "undefined";
        }

        // NaN is a number in JavaScript.
        // Because this statement is false: 0/0 === 0/0,
        // we must use the isNaN function which is the only way to know a number is NaN.
        // Note that it isn't the case with the Infinity number, and that 1/0 === 2/0.
        if (typeof a === "number" && isNaN(a)) {
            return isNaN(b);
        }

        // Compares Number, String or Boolean
        // Because sooner we have already tried:
        //          a === b (then return if it is the case)
        //            and
        //  typeof a !== typeof b (then return false if it is the case)
        // at this time a and b should be of the same type, but hold different values.
        // We can safely return false instead of returning a === b
        return false;

    }(a, b)) && equiv.apply(this, args.splice(1, args.length -1)); // apply transition with (1..n) arguments
}

this.TestHarness = function TestHarness() {
  this.tests = [];
  this.asserts_failed = 0;
  this.total_asserts = 0;
  this.tests_failed = 0;
  this.total_tests = 0;
  this.outputStream = IO.stdout;
}

this.TestHarness.prototype = {
  constructor: TestHarness,

  colourize: true,

  same: function() {
    var args = Array.prototype.slice.call(arguments);

    var msg;
    if (args.length > 2)
      msg = args.pop();

    return this.do_assert( {
      type: 'same',
      when: new Date(),
      ok: !!equiv.apply(equiv, args),
      message: msg,
      default_msg: "arguments are the same"
    });
  },

  instance_of: function(obj, type, msg) {
    var test = obj instanceof type;
    return this.do_assert( {
      type: 'instance_of',
      ok: !!test,
      when: new Date(),
      message: msg,
      default_msg: "object is instance of type"
    });
  },

  ok: function ok(test, msg) {
    if (arguments.length == 0) {
      test = true; // If nothing is passed in, then assume its successful
    }
    return this.do_assert( {
      type: 'ok',
      ok: !!test,
      when: new Date(),
      message: msg,
    } );
  },

  // Handle/print the assert
  do_assert: function do_assert(a) {
    this.current_test.asserts.push(a);
    a.num = this.current_test.asserts.length;

    // Padding to make numbers line up.
    var padd = "  ";
    var plan = this.current_test.plan;

    if (a.num === 1) {
      // First assert this test
      if (isNaN(plan)) {
        // Just print the newline
        this.outputStream.print();
      }
    }

    if (plan === undefined || isNaN(plan))
      plan = a.num;

    let len = plan.toString().length - a.num.toString().length;
    if (len > 0)
      padd += Array(len+1).join(' ');

    let data = [padd + a.num];
    data.push(a.ok ? this.green('ok') : this.red('not ok'));

    if (a.message !== undefined)
      data.push('-', a.message)
    else if ('default_msg' in a)
      data.push('-', a.default_msg)

    if (a.ok)
      this.current_test.asserts_passed++;
    else
      this.current_test.asserts_failed++;

    this.outputStream.print(data);
    return a.ok;
  },

  expect: function expect(count) {
    if (this.current_test.asserts.length)
      throw new Error('expect called after an assertion');
    this.current_test.plan = new Number(count).valueOf();
    if (isNaN(this.current_test.plan))
      throw new Error('invalid plan - not a number');
    this.outputStream.print(" 1.." + this.current_test.plan);
  },

  run: function run(name) {
    this.current_test = {
      name: name,
      asserts: [],
      asserts_passed: 0,
      asserts_failed: 0,
    };

    if (this[name] instanceof Function === false) {
      throw new Error(name + " is not a function");
    }

    this.tests.push(this.current_test);

    this.outputStream.write(name + ":");

    // If there's a 'plan' property of the function object, use it as the plan
    if ('expect' in this[name]) {
      this.expect(this[name].expect)
    }

    try {
        this[name].apply(this);
    }
    catch (e) {
      this.current_test.error = e;
    }
    this.finalize_test();
    delete this.current_test;
  },

  go: function go() {
    for (var n in this) {
      if (this.hasOwnProperty(n) == false)
        continue;
      n = n.toString();

      if (n.substr(0,5) === "test_")
        this.run(n);
    }
    this.finalize();
  },

  green: function() {
    var a = Array.prototype.slice.apply(arguments);
    if (a.length == 0 && a[0] instanceof Array)
      a = a[0];

    a = a.join(' ');
    if (!this.colourize || !a.length)
      return a;
    return '\x1b[32m' + a + '\x1b[0m';
  },

  red: function() {
    var a = Array.prototype.slice.apply(arguments);
    if (a.length == 0 && a[0] instanceof Array)
      a = a[0];

    a = a.join(' ');
    if (!this.colourize || !a.length)
      return a;
    return '\x1b[31m' + a + '\x1b[0m';
  },

  finalize_test: function finalize_test() {
    var test = this.current_test;
    var msg = [];
    this.asserts_failed += test.asserts_failed;

    if (test.plan !== null && !isNaN(test.plan)) {
      // Check the plan.
      let plural = test.plan == 1 ? 'assert' : 'asserts';

      if (test.plan > test.asserts.length) {
        // too many
        test.passed = false;
        msg = [test.name, 'expected', test.plan, plural, 'only got',
               test.asserts.length];
        this.total_asserts += test.plan;
        this.asserts_failed += test.plan - test.asserts.length;
      } else if (test.plan < test.asserts.length) {
        test.passed = false;
        msg = [test.name, 'expected', test.plan, plural, 'but got',
               test.asserts.length];
        this.total_asserts += test.asserts.length;
        this.asserts_failed += test.asserts.length - test.plan;
      }
      else {
        test.passed = test.asserts_failed == 0;
        this.total_asserts += test.plan;
      }
    }

    if (test.error) {
      // The test died.

      // Possibly before it could plan, so add a \n
      if (isNaN(test.plan) && test.asserts.length == 0)
        this.outputStream.print();

      let e = this.current_test.error;
      this.outputStream.print( this.red(test.name, 'died:') );
      var e_msg = e.toString().replace(/\n/g, "\n  ");
      let a = ['  ' + e_msg];
      if (e.fileName) {
        a.push('at', e.fileName + ':' + e.lineNumber);
      }
      msg = this.red(a);
      test.passed = false;
    }
    else {
      // No plan, no error.
      test.passed = test.asserts_failed == 0;
    }
    if (msg.length) {
      this.outputStream.print(msg);
    }

    this.total_tests++;
    if (!test.passed)
      this.tests_failed++;
  },

  // Print summary
  finalize: function finalize() {
    if (this.tests_failed == 0) {
      this.outputStream.print(this.green('All tests successful'))
      return;
    }

    var msg = [this.tests_failed + "/" + this.total_tests, "tests",
              "(" + this.asserts_failed + "/" + this.total_asserts,
              "asserts)", "failed"];

    this.outputStream.print(this.red(msg))
  }
}

})()

/*
t = new TestHarness;
t.test_expect_prop = function() {
  with(this) {
    ok(true, "foo")
  }
}
t.test_expect_prop.expect = 6;

t.test_die = function() {
  throw new Error("foo\nbar");
}

t.test_noplan = function() {
  this.ok("no plan");
  this.same(1,new Number("1"), "numbers are the same");
}

t.test_gt_ten = function () {
  this.expect(12);
  [this.ok(1, i) for (i in Range(0,12) )];
}

t.test_gt = function() {
  this.expect(1);
  this.ok();
  this.ok();
  this.ok();
}

t.go();
*/
<commit_msg>JS/TestHarness: Fix small bug in colourizing<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

(function () {

// Test for equality any JavaScript type.
// Discussions and reference: http://philrathe.com/articles/equiv
// Test suites: http://philrathe.com/tests/equiv
// Author: Philippe Rathé <prathe@gmail.com>

// About passing arguments:
//      when < 2   : return true
//      when 2     : return true if 1st equals 2nd
//      when > 2   : return true 1st equals 2nd, and 2nd equals 3rd,
//                      and 3rd equals 4th ... ans so on (by transition)
//

// Stack of constructors that enables us to skip or abort on functions value.
var objectCallerConstructorStack = [];
function equiv() {
    // we will need to use the array splice method,
    // so we need to convert arguments into a true array.
    var args = Array.prototype.slice.apply(arguments);
    var a, b; // compares a and b (1st and 2nd argument)
    var i; // for iterating over objects convenience
    var len; // for iterating array's length memoization
    // Memoized objects' properties.
    // Allow us to test for equivalence only in one way,
    // then to compare properties to make sure no one is missing.
    var aProperties, bProperties;

    if (args.length < 2) {
        return true; // nothing to compare together
    }

    a = args[0];
    b = args[1];

    return (function (a, b) {

        // Try to optimize the algo speed if ever both a and b are references
        // pointing to the same object (e..g. only for functions, arrays and objects)
        if (a === b) {
            return true;
        }

        // Must test for the null value before testing for the type of an object,
        // because null is also an object. Trapping null or undefined values here
        // is a good to avoid to much validations further in the code.
        if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined") {
            return false; // Anyway (a === b) would have already caught it.
        }

        // Don't lose time and prevent further wrong type manipulation or unexpected results.
        if (typeof a !== typeof b) {
            return false;
        }

        // Must test if it's an array before testing for the type of an object,
        // because an array is also an object.
        if (a instanceof Array) {

            // Make sure b is also an array.
            // At this point b can be an object.
            // Prevent further arrays operation on object.
            if ( ! (b instanceof Array)) {
                return false;
            }

            len = a.length;
            if (len !== b.length) { // safe and faster
                return false;
            }
            for (i = 0; i < len; i++) {
                if( ! equiv(a[i], b[i])) {
                    return false;
                }
            }
            return true;
        }

        // NOTE:
        //      Must test if it's a date before testing if it is an object,
        //      because a date is also an object.
        if (a instanceof Date) {
            return b instanceof Date && a.valueOf() === b.valueOf();
        }

        // NOTE:
        //      Using toSource() to compare regexp only works in FF. It was working as well as the above.
        //      Must verify the constructor of a regexp before verifying it is an object.
        //      Notice those confusing true statements:
        //          var a = /./;
        //          a instanceof Object; // => true
        //          a instanceof RegExp; // => true
        //          typeof a === "function"; // => false in IE and Opera, true in FF and Safari
        //
        // There is 3 possible modifier for regular expressions (g, m and i)
        // The source property only returns the regular expression string without the modifier.
        if (a instanceof RegExp) {
            return b instanceof RegExp &&
                a.source === b.source &&
                a.global === b.global &&
                a.ignoreCase === b.ignoreCase &&
                a.multiline === b.multiline;
        }

        // typeof on some types returns sometimes unexpected type that we deals with.
        // We could have used instanceof instead of typeof but it comes with
        // other problems as mentioned above when testing for the RegExp constructor.
        // We explicitely don't use hasOwnProperty when iterating on the properties of
        // an object to allow a deeper equivalence (e.g. for instances particularly)
        if (typeof a === "object") {
            // Different constructors means a and b can't be equivalent instances.
            // We don't have any choice of comparing them in both ways because of inheritance
            // otherwise {} could be mistaken with []
            // NOTE this:
            //      var a = [];
            //      a instanceof Array;  // true
            //      a instanceof Object; // true
            if ( a.constructor !== b.constructor) {
                return false;
            }

            // Stack constructors before iterating over its properties
            objectCallerConstructorStack.push(a.constructor);

            aProperties = [];
            bProperties = [];

            // NOTE:
            //      We only need to compare propertie's equivalence in one way
            //      and ensures that all properties of a and b are the same.

            // Verify a's properties with b's properties equivalence.
            // Stack a's properties

            for (i in a) {
                aProperties.push(i);
                if (!equiv(a[i], b[i])) {
                    // Unstack current constructor when finished with the object
                    objectCallerConstructorStack.pop();
                    return false;
                }
            }

            // Stack also b's properties
            for (i in b) {
                bProperties.push(i);
            }

            // Unstack current constructor when finished with the object
            objectCallerConstructorStack.pop();

            // Ensures properties's name in both ways.
            // Must sort them because they may not be always in the same order!
            return equiv(aProperties.sort(), bProperties.sort());
        }

        // NOTE:
        //      Using the typeof operator will also catch a RegExp instance.
        //      Take no risk.
        if (a instanceof Function) {
            // BEHAVIOR when comparing functions.
            //      Being here means that a and b were were not the same references.
            //      At this level, functions won't be compared at all.
            //      - skip when they are properties of instances (not instantiates from the Object construtor)
            //      - abort otherwise
            //
            //      To Determine if a function is anonymous we use a regexp on the function sources.
            var currentObjectCallerConstructor =
                    objectCallerConstructorStack[objectCallerConstructorStack.length - 1];
            return currentObjectCallerConstructor !== Object &&
                    typeof currentObjectCallerConstructor !== "undefined";
        }

        // NaN is a number in JavaScript.
        // Because this statement is false: 0/0 === 0/0,
        // we must use the isNaN function which is the only way to know a number is NaN.
        // Note that it isn't the case with the Infinity number, and that 1/0 === 2/0.
        if (typeof a === "number" && isNaN(a)) {
            return isNaN(b);
        }

        // Compares Number, String or Boolean
        // Because sooner we have already tried:
        //          a === b (then return if it is the case)
        //            and
        //  typeof a !== typeof b (then return false if it is the case)
        // at this time a and b should be of the same type, but hold different values.
        // We can safely return false instead of returning a === b
        return false;

    }(a, b)) && equiv.apply(this, args.splice(1, args.length -1)); // apply transition with (1..n) arguments
}

this.TestHarness = function TestHarness() {
  this.tests = [];
  this.asserts_failed = 0;
  this.total_asserts = 0;
  this.tests_failed = 0;
  this.total_tests = 0;
  this.outputStream = IO.stdout;
}

this.TestHarness.prototype = {
  constructor: TestHarness,

  colourize: true,

  same: function() {
    var args = Array.prototype.slice.call(arguments);

    var msg;
    if (args.length > 2)
      msg = args.pop();

    return this.do_assert( {
      type: 'same',
      when: new Date(),
      ok: !!equiv.apply(equiv, args),
      message: msg,
      default_msg: "arguments are the same"
    });
  },

  instance_of: function(obj, type, msg) {
    var test = obj instanceof type;
    return this.do_assert( {
      type: 'instance_of',
      ok: !!test,
      when: new Date(),
      message: msg,
      default_msg: "object is instance of type"
    });
  },

  ok: function ok(test, msg) {
    if (arguments.length == 0) {
      test = true; // If nothing is passed in, then assume its successful
    }
    return this.do_assert( {
      type: 'ok',
      ok: !!test,
      when: new Date(),
      message: msg,
    } );
  },

  // Handle/print the assert
  do_assert: function do_assert(a) {
    this.current_test.asserts.push(a);
    a.num = this.current_test.asserts.length;

    // Padding to make numbers line up.
    var padd = "  ";
    var plan = this.current_test.plan;

    if (a.num === 1) {
      // First assert this test
      if (isNaN(plan)) {
        // Just print the newline
        this.outputStream.print();
      }
    }

    if (plan === undefined || isNaN(plan))
      plan = a.num;

    let len = plan.toString().length - a.num.toString().length;
    if (len > 0)
      padd += Array(len+1).join(' ');

    let data = [padd + a.num];
    data.push(a.ok ? this.green('ok') : this.red('not ok'));

    if (a.message !== undefined)
      data.push('-', a.message)
    else if ('default_msg' in a)
      data.push('-', a.default_msg)

    if (a.ok)
      this.current_test.asserts_passed++;
    else
      this.current_test.asserts_failed++;

    this.outputStream.print(data);
    return a.ok;
  },

  expect: function expect(count) {
    if (this.current_test.asserts.length)
      throw new Error('expect called after an assertion');
    this.current_test.plan = new Number(count).valueOf();
    if (isNaN(this.current_test.plan))
      throw new Error('invalid plan - not a number');
    this.outputStream.print(" 1.." + this.current_test.plan);
  },

  run: function run(name) {
    this.current_test = {
      name: name,
      asserts: [],
      asserts_passed: 0,
      asserts_failed: 0,
    };

    if (this[name] instanceof Function === false) {
      throw new Error(name + " is not a function");
    }

    this.tests.push(this.current_test);

    this.outputStream.write(name + ":");

    // If there's a 'plan' property of the function object, use it as the plan
    if ('expect' in this[name]) {
      this.expect(this[name].expect)
    }

    try {
        this[name].apply(this);
    }
    catch (e) {
      this.current_test.error = e;
    }
    this.finalize_test();
    delete this.current_test;
  },

  go: function go() {
    for (var n in this) {
      if (this.hasOwnProperty(n) == false)
        continue;
      n = n.toString();

      if (n.substr(0,5) === "test_")
        this.run(n);
    }
    this.finalize();
  },

  green: function() {
    var a = Array.prototype.slice.apply(arguments);
    if (a.length == 0 && a[0] instanceof Array)
      a = a[0];

    a = a.join(' ');
    if (!this.colourize || !a.length)
      return a;
    return '\x1b[32m' + a + '\x1b[0m';
  },

  red: function() {
    var a = Array.prototype.slice.apply(arguments);
    if (a.length == 1 && a[0] instanceof Array)
      a = a[0];

    a = a.join(' ');
    if (!this.colourize || !a.length)
      return a;
    return '\x1b[31m' + a + '\x1b[0m';
  },

  finalize_test: function finalize_test() {
    var test = this.current_test;
    var msg = [];
    this.asserts_failed += test.asserts_failed;

    if (test.plan !== null && !isNaN(test.plan)) {
      // Check the plan.
      let plural = test.plan == 1 ? 'assert' : 'asserts';

      if (test.plan > test.asserts.length) {
        // too many
        test.passed = false;
        msg = [test.name, 'expected', test.plan, plural, 'only got',
               test.asserts.length];
        this.total_asserts += test.plan;
        this.asserts_failed += test.plan - test.asserts.length;
      } else if (test.plan < test.asserts.length) {
        test.passed = false;
        msg = [test.name, 'expected', test.plan, plural, 'but got',
               test.asserts.length];
        this.total_asserts += test.asserts.length;
        this.asserts_failed += test.asserts.length - test.plan;
      }
      else {
        test.passed = test.asserts_failed == 0;
        this.total_asserts += test.plan;
      }
    }

    if (test.error) {
      // The test died.

      // Possibly before it could plan, so add a \n
      if (isNaN(test.plan) && test.asserts.length == 0)
        this.outputStream.print();

      let e = this.current_test.error;
      this.outputStream.print( this.red(test.name, 'died:') );
      var e_msg = e.toString().replace(/\n/g, "\n  ");
      let a = ['  ' + e_msg];
      if (e.fileName) {
        var stack = e.stack;
        a.push("\n  ", stack.replace(/\n/g, "\n  "));
      }
      msg = this.red(a);
      test.passed = false;
    }
    else {
      // No plan, no error.
      test.passed = test.asserts_failed == 0;
    }
    if (msg.length) {
      this.outputStream.print(msg);
    }

    this.total_tests++;
    if (!test.passed)
      this.tests_failed++;
  },

  // Print summary
  finalize: function finalize() {
    if (this.tests_failed == 0) {
      this.outputStream.print(this.green('All tests successful'))
      return;
    }

    var msg = [this.tests_failed + "/" + this.total_tests, "tests",
              "(" + this.asserts_failed + "/" + this.total_asserts,
              "asserts)", "failed"];

    this.outputStream.print(this.red(msg))
  }
}

})()

/*
t = new TestHarness;
t.test_expect_prop = function() {
  with(this) {
    ok(true, "foo")
  }
}
t.test_expect_prop.expect = 6;

t.test_die = function() {
  throw new Error("foo\nbar");
}

t.test_noplan = function() {
  this.ok("no plan");
  this.same(1,new Number("1"), "numbers are the same");
}

t.test_gt_ten = function () {
  this.expect(12);
  [this.ok(1, i) for (i in Range(0,12) )];
}

t.test_gt = function() {
  this.expect(1);
  this.ok();
  this.ok();
  this.ok();
}

t.go();
*/
<|endoftext|>


<commit_before>(function(){
    'use strict';

    angular
        .module('ngUnderscore', [])
        .factory('_',ngUnderscore);

        function ngUnderscore($window){
            return $window._;
        };
})();
<commit_msg>ngUnderscore module<commit_after>(function(){
    'use strict';

    angular
        .module('ngUnderscore', [])

        .factory('_',ngUnderscore);

        function ngUnderscore($window){
            return $window._;
        };
})();
<|endoftext|>


<commit_before>if(typeof translations == 'undefined'){
    translations = {};
}

translations.fr_FR = {
// header
    'Search': 'Rechercher',
    // Nav menu
    'Add': 'Ajouter',
    'By URIs': 'Par URIs',
    'By Torrents': 'Par Torrents',
    'By Metalinks': 'Par Metaliens',
    'Manage': 'Gérer',
    'Pause All': 'Tout suspendre',
    'Resume Paused': 'Reprendre',
    'Purge Completed': 'Nettoyer les fichiers complétés',
    'Settings': 'Paramètres',
    'Connection Settings': 'Paramètres de connexion',
    'Global Settings': 'Paramètres globaux',
    'Server info': 'Informations serveur',
    'About and contribute': 'À propos et contribuer',
    'Toggle navigation': 'Basculer la navigation',
// body
// nav side bar
    'Miscellaneous': 'Autres',
    'Global Statistics': 'Statistiques globales',
    'About': 'À propos',
    'Displaying': 'Affichage de',
    'of': 'parmi',
    'downloads': 'téléchargements',
    'Language': 'Langue',
// download filters
    'Download Filters': 'Filtres de téléchargement',
    'Running': 'En cours',
    'Active': 'Actifs',
    'Waiting': 'En attente',
    'Complete': 'Complétés',
    'Error': 'Erreurs',
    'Paused': 'En pause',
    'Removed': 'Supprimés',
    'Hide linked meta-data': 'Cacher les métadonnées liées',
    'Toggle': 'Basculer',
    'Reset filters': 'Réinitialiser les filtres',
// starred properties
    'Quick Access Settings': 'Paramètres d\'accès rapide',
    'Save settings': 'Sauvegarder les paramètres',
    'Currently no download in line to display, use the': 'Aucun téléchargement dans la file d\'attente, utilisez le bouton de téléchargement',
    'download button to start downloading files!': 'pour commencer à télécharger des fichiers!',
    'Peers': 'Pairs',
    'More Info': 'Plus d\'infos',
    'Remove': 'Supprimer',
    '# of': '# parmi',
    'Length': 'Longueur',
// modals
    'Add Downloads By URIs': 'Ajouter des téléchargements depuis des URIs',
    '- You can add multiple downloads (files) at the same time by putting URIs for each file on a separate line.':
        'Vous pouvez ajouter plusieurs téléchargements (fichiers) en même temps, en mettant une URI pour chaque fichier sur une nouvelle ligne',
    '- You can also add multiple URIs (mirrors) for the *same* file. To do this, separate the URIs by a space.':
        'Vous pouvez aussi ajouter plusieurs URIs (mirroirs) pour le *même* fichier. Pour ce faire, séparez les URIs par un espace.',
    '- A URI can be HTTP(S)/FTP/BitTorrent-Magnet.': 'Une URI peut être HTTP(S)/FTP/BitTorrent-Magnet.',
    'Download settings': 'Paramètres de téléchargement',
    'Advanced settings': 'Paramètres avancés',
    'Cancel': 'Annuler',
    'Start': 'Démarrer',
    'Choose': 'Choisir',
    'Quick Access (shown on the main page)': 'Accès rapide (affiché sur la page principale',
// add torrent modal
    'Add Downloads By Torrents': 'Ajouter des téléchargements à partir de fichiers Torrent',
    '- Select the torrent from the local filesystem to start the download.': '- Sélectionnez le torrent depuis votre système de fichier local pour commencer le téléchargement.',
    '- You can select multiple torrents to start multiple downloads.': 'Vous pouvez sélectionner plusieurs torrents pour commencer plusieurs téléchargements.',
    '- To add a BitTorrent-Magnet URL, use the Add By URI option and add it there.': 'Pour ajouter une URL BitTorrent-Magnet, utilisez l\'option Ajouter par URIs et ajoutez-la à ce niveau.',
    'Select Torrents': 'Sélectionner des Torrents',
    'Select a Torrent': 'Sélectionner un Torrent',
// add metalink modal
    'Add Downloads By Metalinks': 'Ajouter des téléchargements par Metaliens',
    'Select Metalinks': 'Sélectionner des Métaliens',
    '- Select the Metalink from the local filesystem to start the download.': 'Sélectionner le Métalien depuis votre système de fichier local pour commencer le téléchargement.',
    '- You can select multiple Metalinks to start multiple downloads.': 'Vous pouvez sélectionner plusieurs Métaliens pour commencer plusieurs téléchargements.',
    'Select a Metalink': 'Sélectionner un Métalien',
// select file modal
    'Choose files to start download for': 'Sélectionner les fichiers pour lesquels commencer le téléchargement.',
    'Select to download': 'Sélectionner pour télécharger',
// settings modal
    'Aria2 RPC host and port': 'Hôte et ports Aria2 RPC',
    'Enter the host': 'Entrer l\'hôte',
    'Enter the IP or DNS name of the server on which the RPC for Aria2 is running (default: localhost)':
        'Entrer l\'IP ou le nom DNS du serveur sur lequel est lancé le RPC pour Aria2 (défaut : localhost)',
    'Enter the port': 'Entrer le port',
    'Enter the port of the server on which the RPC for Aria2 is running (default: 6800)':
        'Entrer le port du serveur sur lequel tourne le RPC pour Aria2 (défaut : 6800)',
    'Enter the RPC path': 'Entrer le chemin vers le RPC',
    'Enter the path for the Aria2 RPC endpoint (default: /jsonrpc)': 'Entrer le chemin final pour le RPC Aria2 (défaut : /jsonrpc)',
    'SSL/TLS encryption': 'Chiffrage SSL/TLS',
    'Enable SSL/TLS encryption': 'Activer le chiffrage SSL/TLS',
    'Enter the secret token (optional)': 'Entrer le token secret (optionnel)',
    'Enter the Aria2 RPC secret token (leave empty if authentication is not enabled)':
        'Entrer le token secret pour le RPC Aria2 (laisser vide si l\'authentification n\'est pas activée)',
    'Enter the username (optional)': 'Entrer le nom d\'utilisateur (optionnel)',
    'Enter the Aria2 RPC username (empty if authentication not enabled)':
        'Entrer le nom d\'utilisateur RPC Aria2 (laisser vide si l\authentification n\'est pas activée)',
    'Enter the password (optional)': 'Entrer le mot de passe (optionnel)',
    'Enter the Aria2 RPC password (empty if authentication not enabled)': 'Entrer le mot de passe RPC Aria2 (laisser vide si l\'authentification n\'est pas activée)',
    'Enter base URL (optional)': 'Entrez l\'URL de base',
    'Direct Download': 'Téléchargement direct',
    'If supplied, links will be created to enable direct download from the Aria2 server.':
        'S\'ils sont fournis, les liens seront créés pour activer le téléchargement direct depuis le serveur Aria2',
    '(Requires appropriate webserver to be configured.)': '(Nécessite un serveur web approprié pour être configuré)',
    'Save Connection configuration': 'Sauvegarder la configuration de connexion',
// server info modal
    'Aria2 server info': 'Infos serveur Aria2',
    'Aria2 Version': 'Version Aria2',
    'Features Enabled': 'Fonctionnalités activées',
// about modal
    'To download the latest version of the project, add issues or to contribute back, head on to':
        'Pour télécharger la dernière version du projet, signaler des problèmes ou pour contribuer, aller à l'adresse',
    'Or you can open the latest version in the browser through': 'Ou vous pouvez ouvrir la dernière version dans le navigateur depuis',
    'Close': 'Fermer',
// lables
    'Download status':'Statut de téléchargement',
    'Download Speed':'Vitesse de téléchargement',
    'Upload Speed':'Vitesse d\'envoi',
    'Estimated time':'Temps estimé',
    'Download Size':'Taille du téléchargement',
    'Downloaded':'Téléchargé',
    'Progress':'Avancement',
    'Download Path':'Chemin de téléchargement',
    'Uploaded':'Envoyé',
    'Download GID':'GID du téléchargement',
    'Number of Pieces':'Nombre de pièces',
    'Piece Length':'Taille de la pièce'
};
<commit_msg>fixed fr language bug<commit_after>if(typeof translations == 'undefined'){
    translations = {};
}

translations.fr_FR = {
// header
    'Search': 'Rechercher',
    // Nav menu
    'Add': 'Ajouter',
    'By URIs': 'Par URIs',
    'By Torrents': 'Par Torrents',
    'By Metalinks': 'Par Metaliens',
    'Manage': 'Gérer',
    'Pause All': 'Tout suspendre',
    'Resume Paused': 'Reprendre',
    'Purge Completed': 'Nettoyer les fichiers complétés',
    'Settings': 'Paramètres',
    'Connection Settings': 'Paramètres de connexion',
    'Global Settings': 'Paramètres globaux',
    'Server info': 'Informations serveur',
    'About and contribute': 'À propos et contribuer',
    'Toggle navigation': 'Basculer la navigation',
// body
// nav side bar
    'Miscellaneous': 'Autres',
    'Global Statistics': 'Statistiques globales',
    'About': 'À propos',
    'Displaying': 'Affichage de',
    'of': 'parmi',
    'downloads': 'téléchargements',
    'Language': 'Langue',
// download filters
    'Download Filters': 'Filtres de téléchargement',
    'Running': 'En cours',
    'Active': 'Actifs',
    'Waiting': 'En attente',
    'Complete': 'Complétés',
    'Error': 'Erreurs',
    'Paused': 'En pause',
    'Removed': 'Supprimés',
    'Hide linked meta-data': 'Cacher les métadonnées liées',
    'Toggle': 'Basculer',
    'Reset filters': 'Réinitialiser les filtres',
// starred properties
    'Quick Access Settings': 'Paramètres d\'accès rapide',
    'Save settings': 'Sauvegarder les paramètres',
    'Currently no download in line to display, use the': 'Aucun téléchargement dans la file d\'attente, utilisez le bouton de téléchargement',
    'download button to start downloading files!': 'pour commencer à télécharger des fichiers!',
    'Peers': 'Pairs',
    'More Info': 'Plus d\'infos',
    'Remove': 'Supprimer',
    '# of': '# parmi',
    'Length': 'Longueur',
// modals
    'Add Downloads By URIs': 'Ajouter des téléchargements depuis des URIs',
    '- You can add multiple downloads (files) at the same time by putting URIs for each file on a separate line.':
        'Vous pouvez ajouter plusieurs téléchargements (fichiers) en même temps, en mettant une URI pour chaque fichier sur une nouvelle ligne',
    '- You can also add multiple URIs (mirrors) for the *same* file. To do this, separate the URIs by a space.':
        'Vous pouvez aussi ajouter plusieurs URIs (mirroirs) pour le *même* fichier. Pour ce faire, séparez les URIs par un espace.',
    '- A URI can be HTTP(S)/FTP/BitTorrent-Magnet.': 'Une URI peut être HTTP(S)/FTP/BitTorrent-Magnet.',
    'Download settings': 'Paramètres de téléchargement',
    'Advanced settings': 'Paramètres avancés',
    'Cancel': 'Annuler',
    'Start': 'Démarrer',
    'Choose': 'Choisir',
    'Quick Access (shown on the main page)': 'Accès rapide (affiché sur la page principale',
// add torrent modal
    'Add Downloads By Torrents': 'Ajouter des téléchargements à partir de fichiers Torrent',
    '- Select the torrent from the local filesystem to start the download.': '- Sélectionnez le torrent depuis votre système de fichier local pour commencer le téléchargement.',
    '- You can select multiple torrents to start multiple downloads.': 'Vous pouvez sélectionner plusieurs torrents pour commencer plusieurs téléchargements.',
    '- To add a BitTorrent-Magnet URL, use the Add By URI option and add it there.': 'Pour ajouter une URL BitTorrent-Magnet, utilisez l\'option Ajouter par URIs et ajoutez-la à ce niveau.',
    'Select Torrents': 'Sélectionner des Torrents',
    'Select a Torrent': 'Sélectionner un Torrent',
// add metalink modal
    'Add Downloads By Metalinks': 'Ajouter des téléchargements par Metaliens',
    'Select Metalinks': 'Sélectionner des Métaliens',
    '- Select the Metalink from the local filesystem to start the download.': 'Sélectionner le Métalien depuis votre système de fichier local pour commencer le téléchargement.',
    '- You can select multiple Metalinks to start multiple downloads.': 'Vous pouvez sélectionner plusieurs Métaliens pour commencer plusieurs téléchargements.',
    'Select a Metalink': 'Sélectionner un Métalien',
// select file modal
    'Choose files to start download for': 'Sélectionner les fichiers pour lesquels commencer le téléchargement.',
    'Select to download': 'Sélectionner pour télécharger',
// settings modal
    'Aria2 RPC host and port': 'Hôte et ports Aria2 RPC',
    'Enter the host': 'Entrer l\'hôte',
    'Enter the IP or DNS name of the server on which the RPC for Aria2 is running (default: localhost)':
        'Entrer l\'IP ou le nom DNS du serveur sur lequel est lancé le RPC pour Aria2 (défaut : localhost)',
    'Enter the port': 'Entrer le port',
    'Enter the port of the server on which the RPC for Aria2 is running (default: 6800)':
        'Entrer le port du serveur sur lequel tourne le RPC pour Aria2 (défaut : 6800)',
    'Enter the RPC path': 'Entrer le chemin vers le RPC',
    'Enter the path for the Aria2 RPC endpoint (default: /jsonrpc)': 'Entrer le chemin final pour le RPC Aria2 (défaut : /jsonrpc)',
    'SSL/TLS encryption': 'Chiffrage SSL/TLS',
    'Enable SSL/TLS encryption': 'Activer le chiffrage SSL/TLS',
    'Enter the secret token (optional)': 'Entrer le token secret (optionnel)',
    'Enter the Aria2 RPC secret token (leave empty if authentication is not enabled)':
        'Entrer le token secret pour le RPC Aria2 (laisser vide si l\'authentification n\'est pas activée)',
    'Enter the username (optional)': 'Entrer le nom d\'utilisateur (optionnel)',
    'Enter the Aria2 RPC username (empty if authentication not enabled)':
        'Entrer le nom d\'utilisateur RPC Aria2 (laisser vide si l\authentification n\'est pas activée)',
    'Enter the password (optional)': 'Entrer le mot de passe (optionnel)',
    'Enter the Aria2 RPC password (empty if authentication not enabled)': 'Entrer le mot de passe RPC Aria2 (laisser vide si l\'authentification n\'est pas activée)',
    'Enter base URL (optional)': 'Entrez l\'URL de base',
    'Direct Download': 'Téléchargement direct',
    'If supplied, links will be created to enable direct download from the Aria2 server.':
        'S\'ils sont fournis, les liens seront créés pour activer le téléchargement direct depuis le serveur Aria2',
    '(Requires appropriate webserver to be configured.)': '(Nécessite un serveur web approprié pour être configuré)',
    'Save Connection configuration': 'Sauvegarder la configuration de connexion',
// server info modal
    'Aria2 server info': 'Infos serveur Aria2',
    'Aria2 Version': 'Version Aria2',
    'Features Enabled': 'Fonctionnalités activées',
// about modal
    'To download the latest version of the project, add issues or to contribute back, head on to':
        'Pour télécharger la dernière version du projet, signaler des problèmes ou pour contribuer, aller à l\'adresse',
    'Or you can open the latest version in the browser through': 'Ou vous pouvez ouvrir la dernière version dans le navigateur depuis',
    'Close': 'Fermer',
// lables
    'Download status':'Statut de téléchargement',
    'Download Speed':'Vitesse de téléchargement',
    'Upload Speed':'Vitesse d\'envoi',
    'Estimated time':'Temps estimé',
    'Download Size':'Taille du téléchargement',
    'Downloaded':'Téléchargé',
    'Progress':'Avancement',
    'Download Path':'Chemin de téléchargement',
    'Uploaded':'Envoyé',
    'Download GID':'GID du téléchargement',
    'Number of Pieces':'Nombre de pièces',
    'Piece Length':'Taille de la pièce'
};
<|endoftext|>


<commit_before>var has = Object.prototype.hasOwnProperty

exports.log = function(err, data) {
  err ? console.warn(err) : console.log(data)
}

exports.extend = function(attrs) {
  for (var name in attrs) {
    if (has.call(attrs, name)) {
      this[name] = attrs[name]
    }
  }
}<commit_msg>don't need these<commit_after><|endoftext|>


<commit_before>'use strict';

var last         = require('es5-ext/array/#/last')
  , defineLength = require('es5-ext/function/_define-length')
  , callable     = require('es5-ext/object/valid-callable')
  , d            = require('d')
  , memoize      = require('memoizee')
  , fs           = require('fs')

  , max = Math.max, slice = Array.prototype.slice
  , limit = Infinity, count = 0, queue = [], release
  , wrap;

release = function () {
	var data, cb;
	while ((count < limit) && (data = queue.shift())) {
		try {
			data.fn.apply(data.context, data.args);
		} catch (e) {
			cb = last.call(data.args);
			if (typeof cb === 'function') cb(e);
		}
	}
};

wrap = function (asyncFn) {
	var self;
	callable(asyncFn);
	return (self = defineLength(function () {
		var openCount, args = arguments, context, cb = last.call(args);
		if (!exports.initialized || (typeof cb !== 'function')) return asyncFn.apply(this, arguments);
		if (count >= limit) {
			queue.push({ fn: self, context: this, args: arguments });
			return;
		}
		openCount = count++;
		context = this;
		args = slice.call(args, 0, -1);
		args.push(function (err, result) {
			--count;
			if (err && (err.code === 'EMFILE')) {
				if (limit > openCount) limit = openCount;
				queue.push({ fn: self, context: context, args: args });
				release();
				return;
			}
			release();
			if (typeof cb === 'function') cb.apply(this, arguments);
		});
		return asyncFn.apply(this, args);
	}, asyncFn.length));
};

module.exports = exports = memoize(function () {
	var open = fs.open, openSync = fs.openSync, close = fs.close, closeSync = fs.closeSync;

	if (exports.initialized) return;

	fs.open = function (path, flags, mode, cb) {
		var openCount, args;
		if (count >= limit) {
			queue.push({ fn: fs.open, context: this, args: arguments });
			return;
		}
		openCount = count++;
		args = arguments;
		cb = last.call(args);
		open(path, flags, mode, function (err, fd) {
			if (err) {
				--count;
				if (err.code === 'EMFILE') {
					if (limit > openCount) limit = openCount;
					queue.push({ fn: fs.open, context: this, args: args });
					release();
					return;
				}
				release();
			}
			if (typeof cb === 'function') cb(err, fd);
		});
	};

	fs.openSync = function (path, flags, mode) {
		var result = openSync.apply(this, arguments);
		++count;
		return result;
	};

	fs.close = function (fd, cb) {
		close(fd, function (err) {
			if (!err) {
				--count;
				release();
			}
			if (typeof cb === 'function') cb(err);
		});
	};

	fs.closeSync = function (fd) {
		var result;
		result = closeSync(fd);
		--count;
		release();
		return result;
	};

	fs.readdir = wrap(fs.readdir);

	Object.defineProperty(exports, 'initialized', d('e', true));
});

Object.defineProperties(exports, {
	initialized: d('ce', false),
	limit: d.gs(function () { return limit; }, function (nLimit) {
		if (limit >= nLimit) limit = max(nLimit, 5);
	}),
	available: d.gs(function () { return max(limit - count, 0); }),
	taken: d.gs(function () { return count; }),
	open: d(function () { ++count; }),
	close: d(function () {
		--count;
		if (release) release();
	}),
	wrap: d(wrap)
});
<commit_msg>Fix descriptor limiter for Node.js v1.2 and greater<commit_after>'use strict';

var last         = require('es5-ext/array/#/last')
  , defineLength = require('es5-ext/function/_define-length')
  , callable     = require('es5-ext/object/valid-callable')
  , d            = require('d')
  , memoize      = require('memoizee')
  , fs           = require('fs')

  , max = Math.max, slice = Array.prototype.slice
  , limit = Infinity, count = 0, queue = [], release
  , wrap;

release = function () {
	var data, cb;
	while ((count < limit) && (data = queue.shift())) {
		try {
			data.fn.apply(data.context, data.args);
		} catch (e) {
			cb = last.call(data.args);
			if (typeof cb === 'function') cb(e);
		}
	}
};

wrap = function (asyncFn) {
	var self;
	callable(asyncFn);
	return (self = defineLength(function () {
		var openCount, args = arguments, context, cb = last.call(args);
		if (!exports.initialized || (typeof cb !== 'function')) return asyncFn.apply(this, arguments);
		if (count >= limit) {
			queue.push({ fn: self, context: this, args: arguments });
			return;
		}
		openCount = count++;
		context = this;
		args = slice.call(args, 0, -1);
		args.push(function (err, result) {
			--count;
			if (err && (err.code === 'EMFILE')) {
				if (limit > openCount) limit = openCount;
				queue.push({ fn: self, context: context, args: args });
				release();
				return;
			}
			release();
			if (typeof cb === 'function') cb.apply(this, arguments);
		});
		return asyncFn.apply(this, args);
	}, asyncFn.length));
};

module.exports = exports = memoize(function () {
	var open = fs.open, openSync = fs.openSync, close = fs.close, closeSync = fs.closeSync;

	if (exports.initialized) return;

	fs.open = function (path, flags, mode, cb) {
		var openCount, args;
		if (count >= limit) {
			queue.push({ fn: fs.open, context: this, args: arguments });
			return;
		}
		openCount = count++;
		args = arguments;
		cb = last.call(args);
		open(path, flags, mode, function (err, fd) {
			if (err) {
				--count;
				if (err.code === 'EMFILE') {
					if (limit > openCount) limit = openCount;
					queue.push({ fn: fs.open, context: this, args: args });
					release();
					return;
				}
				release();
			}
			if (typeof cb === 'function') cb(err, fd);
		});
	};

	fs.openSync = function (path, flags, mode) {
		var result = openSync.apply(this, arguments);
		++count;
		return result;
	};

	fs.close = function (fd, cb) {
		close(fd, function (err) {
			if (!err) {
				--count;
				release();
			}
			if (typeof cb === 'function') cb(err);
		});
	};

	fs.closeSync = function (fd) {
		var result;
		result = closeSync(fd);
		--count;
		release();
		return result;
	};

	fs.readdir = wrap(fs.readdir);
	fs.readFile = wrap(fs.readFile); // Needed for Node >=1.2 because of commit e65308053c

	Object.defineProperty(exports, 'initialized', d('e', true));
});

Object.defineProperties(exports, {
	initialized: d('ce', false),
	limit: d.gs(function () { return limit; }, function (nLimit) {
		if (limit >= nLimit) limit = max(nLimit, 5);
	}),
	available: d.gs(function () { return max(limit - count, 0); }),
	taken: d.gs(function () { return count; }),
	open: d(function () { ++count; }),
	close: d(function () {
		--count;
		if (release) release();
	}),
	wrap: d(wrap)
});
<|endoftext|>


<commit_before>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Styles needed to determine a stroked line shape.
 *
 * @author Jonathan Olson <olsonsjc@gmail.com>
 */

define( function( require ) {
  'use strict';

  var assert = require( 'ASSERT/assert' )( 'kite' );

  var kite = require( 'KITE/kite' );

  kite.LineStyles = function( args ) {
    if ( args === undefined ) {
      args = {};
    }
    this.lineWidth = args.lineWidth !== undefined ? args.lineWidth : 1;
    this.lineCap = args.lineCap !== undefined ? args.lineCap : 'butt'; // butt, round, square
    this.lineJoin = args.lineJoin !== undefined ? args.lineJoin : 'miter'; // miter, round, bevel
    this.lineDash = args.lineDash !== undefined ? args.lineDash : null; // null is default, otherwise an array of numbers
    this.lineDashOffset = args.lineDashOffset !== undefined ? args.lineDashOffset : 0; // 0 default, any number
    this.miterLimit = args.miterLimit !== undefined ? args.miterLimit : 10; // see https://svgwg.org/svg2-draft/painting.html for miterLimit computations
  };
  var LineStyles = kite.LineStyles;
  LineStyles.prototype = {
    constructor: LineStyles,

    equals: function( other ) {
      var typical = this.lineWidth === other.lineWidth &&
                    this.lineCap === other.lineCap &&
                    this.lineJoin === other.lineJoin &&
                    this.miterLimit === other.miterLimit &&
                    this.lineDashOffset === other.lineDashOffset;
      if ( !typical ) {
        return false;
      }

      // now we need to compare the line dashes
      /* jshint -W018 */
      //jshint -W018
      if ( !this.lineDash !== !other.lineDash ) {
        // one is defined, the other is not
        return false;
      }

      if ( this.lineDash ) {
        if ( this.lineDash.length !== other.lineDash.length ) {
          return false;
        }
        for ( var i = 0; i < this.lineDash.length; i++ ) {
          if ( this.lineDash[i] !== other.lineDash[i] ) {
            return false;
          }
        }
        return true;
      } else {
        // both have no line dash, so they are equal
        return true;
      }
    }
  };

  return kite.LineStyles;
} );
<commit_msg>Initializing lineDash to [], fixes #2<commit_after>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Styles needed to determine a stroked line shape.
 *
 * @author Jonathan Olson <olsonsjc@gmail.com>
 */

define( function( require ) {
  'use strict';

  var assert = require( 'ASSERT/assert' )( 'kite' );

  var kite = require( 'KITE/kite' );

  kite.LineStyles = function( args ) {
    if ( args === undefined ) {
      args = {};
    }
    this.lineWidth = args.lineWidth !== undefined ? args.lineWidth : 1;
    this.lineCap = args.lineCap !== undefined ? args.lineCap : 'butt'; // butt, round, square
    this.lineJoin = args.lineJoin !== undefined ? args.lineJoin : 'miter'; // miter, round, bevel
    this.lineDash = args.lineDash !== undefined ? args.lineDash : []; // null is default, otherwise an array of numbers
    this.lineDashOffset = args.lineDashOffset !== undefined ? args.lineDashOffset : 0; // 0 default, any number
    this.miterLimit = args.miterLimit !== undefined ? args.miterLimit : 10; // see https://svgwg.org/svg2-draft/painting.html for miterLimit computations
  };
  var LineStyles = kite.LineStyles;
  LineStyles.prototype = {
    constructor: LineStyles,

    equals: function( other ) {
      var typical = this.lineWidth === other.lineWidth &&
                    this.lineCap === other.lineCap &&
                    this.lineJoin === other.lineJoin &&
                    this.miterLimit === other.miterLimit &&
                    this.lineDashOffset === other.lineDashOffset;
      if ( !typical ) {
        return false;
      }

      if ( this.lineDash.length === other.lineDash.length ) {
        for ( var i = 0; i < this.lineDash.length; i++ ) {
          if ( this.lineDash[i] !== other.lineDash[i] ) {
            return false;
          }
        }
      } else {
        // line dashes must be different
        return false;
      }

      return true;
    }
  };

  return kite.LineStyles;
} );
<|endoftext|>


<commit_before>
'use strict';
// Storing multiple constant values inside of an object
// Keep in mind the values in the object mean they can be modified
// Which makes no sense for a constant, use wisely if you do this
var app = angular.module('retailerStock', ['ui.router', 'ngStorage', 'ngCookies', 'oitozero.ngSweetAlert', 'ui.bootstrap', /*'ui.calendar',
    */'ngAnimate', 'ngMessages'/*,'ngValidate','ngFileUpload', 'angular-confirm','textAngular' ,'chart.js' ,'angularMoment','uiSwitch'*/])
        .constant({
          'SERVER_URL': location.protocol+'//'+((location.hostname === "localhost" || location.hostname === "127.0.0.1") ? 'localhost:3000' : 'retailerstock.herokuapp.com')+'/'

});

app.run(['$rootScope', 'SERVER_URL', '$templateCache', '$httpPreConfig',
  function($rootScope, SERVER_URL, $templateCache, $httpPreConfig) {

    $rootScope.TEMPLATE_URL = SERVER_URL+'views/';
    $rootScope.IMG_URL      = SERVER_URL+'images/';
    $rootScope.FILE_URL     = SERVER_URL+'files/';

    var clearTemplateCache = function () {
      $templateCache.removeAll();
    };

    var httpRequest = function () {
      $rootScope.loader = !$rootScope.loader ? true : false;console.log($rootScope.loader);
    };

    $rootScope.$on('httpCallStarted', httpRequest);
    $rootScope.$on('httpCallCompleted', httpRequest);

    $rootScope.$on('$stateChangeStart', clearTemplateCache);
    $rootScope.$on('$stateChangeSuccess', clearTemplateCache);
    $rootScope.$on('$viewContentLoaded', clearTemplateCache);

}]);
<commit_msg>Additional Changes<commit_after>
'use strict';
// Storing multiple constant values inside of an object
// Keep in mind the values in the object mean they can be modified
// Which makes no sense for a constant, use wisely if you do this
var app = angular.module('retailerStock', ['ui.router', 'ngStorage', 'ngCookies', 'oitozero.ngSweetAlert', 'ui.bootstrap', /*'ui.calendar',
    */'ngAnimate', 'ngMessages'/*,'ngValidate','ngFileUpload', 'angular-confirm','textAngular' ,'chart.js' ,'angularMoment','uiSwitch'*/])
        .constant({
          'SERVER_URL': location.protocol+'//'+((location.hostname === "localhost" || location.hostname === "127.0.0.1") ? 'localhost:3000' : 'retailerstock.herokuapp.com')+'/'

});

app.run(['$rootScope', 'SERVER_URL', '$templateCache', '$httpPreConfig',
  function($rootScope, SERVER_URL, $templateCache, $httpPreConfig) {

    $rootScope.TEMPLATE_URL = SERVER_URL+'views/';
    $rootScope.IMG_URL      = SERVER_URL+'images/';
    $rootScope.FILE_URL     = SERVER_URL+'files/';

    var clearTemplateCache = function () {
      $templateCache.removeAll();
    };

    var httpRequest = function () {
      $rootScope.loader = !$rootScope.loader ? true : false;console.log($rootScope.loader);
    };

    $rootScope.$on('httpCallStarted', httpRequest);
    $rootScope.$on('httpCallCompleted', httpRequest);

    $rootScope.$on('$stateChangeStart', clearTemplateCache);
    $rootScope.$on('$stateChangeSuccess', clearTemplateCache);
    $rootScope.$on('$viewContentLoaded', clearTemplateCache);

}]);
<|endoftext|>


<commit_before>'use strict';

var util = require('util');
var gutil = require('generator-util');
var utils = require('lazy-cache')(require);
var fn = require;
require = utils;

/**
 * Lazily required module dependencies
 */

utils.gutil = gutil;

// plugins
require('base-argv', 'argv');
require('base-config', 'config');
require('base-questions', 'ask');

// misc
require('empty-dir');
require('opn');
require('try-open');

// data/object utils
require('ansi-colors', 'colors');
require('define-property', 'define');
require('extend-shallow', 'extend');
require('fancy-log', 'timestamp');
require('is-affirmative');
require('kind-of', 'typeOf');
require('get-value', 'get');
require('set-value', 'set');
require('arr-union', 'union');
require('map-schema', 'Schema');
require('minimist');
require('mixin-deep', 'merge');
require('question-match', 'match');

// naming
require('namify');
require('load-pkg', 'pkg');
require('project-name', 'project');
require('write-json');
require = fn;

utils.cyan = utils.colors.cyan;
utils.green = utils.colors.green;
utils.magenta = utils.colors.magenta;
utils.tableize = gutil.tableize;
utils.homeRelative = gutil.homeRelative;

// logger noop
utils.white = function(msg) {
  return msg;
};

/**
 * Format a value to be displayed in the command line
 */

utils.formatValue = function(val) {
  var res = utils.cyan(util.inspect(val, null, 10));
  if (utils.isObject(val) && Object.keys(val).length > 1) {
    return '\n' + res;
  }
  return res;
};

/**
 * Returns true if `val` is true or is an object with `show: true`
 *
 * @param {String} `val`
 * @return {Boolean}
 * @api public
 */

utils.show = function(val) {
  return utils.isObject(val) && val.show === true;
};

/**
 * Return true if a filepath exists on the file system
 */

utils.exists = function(fp) {
  return fp && (typeof utils.tryOpen(fp, 'r') === 'number');
};

/**
 * Cast `val` to an array
 *
 * @param {String|Array} `val`
 * @return {Array}
 */

utils.arrayify = function(val) {
  return val ? (Array.isArray(val) ? val : [val]) : [];
};

/**
 * Return true if a value is an object.
 */

utils.isObject = function(val) {
  return utils.typeOf(val) === 'object';
};

/**
 * Return true if a directory exists and is empty.
 *
 * @param  {*} val
 * @return {Array}
 */

utils.isEmpty = function(dir) {
  return utils.emptyDir(dir, function(fp) {
    return !/\.DS_Store/i.test(fp);
  });
};

/**
 * File-related properties. Passed to [expand-args]
 * to ensure that no undesired escaping or processing
 * is done on filepath arguments.
 */

utils.fileKeys = [
  'base', 'basename', 'cwd', 'dir',
  'dirname', 'ext', 'extname', 'f',
  'file', 'filename', 'path', 'root',
  'stem'
];

/**
 * Whitelisted flags: these flags can be passed along with task
 * arguments. To run tasks with any flags, pass `--run`
 */

utils.whitelist = [
  'ask',
  'data',
  'emit',
  'force',
  'init',
  'layout',
  'option',
  'options',
  'readme',
  'set',
  'toc',
  'verbose'
].concat(utils.fileKeys);

/**
 * Aliases to pass to minimist. Defined here
 * so that it's available to any method.
 */

utils.aliases = {
  config: 'c',
  dirname: 'dir',
  extname: 'ext',
  file: 'f',
  filename: 'stem',
  global: 'g',
  save: 's',
  verbose: 'v',
  version: 'V'
};

/**
 * Expose `utils`
 */

module.exports = utils;
<commit_msg>adds `stores` util for setting a value on stores chosen by the user (not used yet)<commit_after>'use strict';

var util = require('util');
var gutil = require('generator-util');
var utils = require('lazy-cache')(require);
var fn = require;
require = utils;

/**
 * Lazily required module dependencies
 */

utils.gutil = gutil;

// plugins
require('base-argv', 'argv');
require('base-config', 'config');
require('base-questions', 'ask');

// misc
require('empty-dir');
require('opn');
require('try-open');

// data/object utils
require('ansi-colors', 'colors');
require('arr-union', 'union');
require('define-property', 'define');
require('extend-shallow', 'extend');
require('fancy-log', 'timestamp');
require('get-value', 'get');
require('is-affirmative');
require('kind-of', 'typeOf');
require('map-schema', 'Schema');
require('minimist');
require('mixin-deep', 'merge');
require('question-match', 'match');
require('set-value', 'set');

// naming
require('namify');
require('load-pkg', 'pkg');
require('project-name', 'project');
require('write-json');
require = fn;

utils.cyan = utils.colors.cyan;
utils.green = utils.colors.green;
utils.magenta = utils.colors.magenta;
utils.tableize = gutil.tableize;
utils.homeRelative = gutil.homeRelative;

// logger noop
utils.white = function(msg) {
  return msg;
};

/**
 * Format a value to be displayed in the command line
 */

utils.formatValue = function(val) {
  var res = utils.cyan(util.inspect(val, null, 10));
  if (utils.isObject(val) && Object.keys(val).length > 1) {
    return '\n' + res;
  }
  return res;
};

/**
 * Save a value to, or delete a value from the specified stores.
 */

utils.stores = function(app, stores, val, method) {
  if (!Array.isArray(stores)) return;
  method = method || 'set';

  var len = stores.length;
  var idx = -1;

  if (utils.isObject(val)) {
    delete val.stores;
  }

  while (++idx < len) {
    var name = stores[idx];
    if (name === 'pkg') {
      app[name][method](app._name, val);
    } else {
      app[name][method](val);
    }
  }
};

/**
 * Returns true if `val` is true or is an object with `show: true`
 *
 * @param {String} `val`
 * @return {Boolean}
 * @api public
 */

utils.show = function(val) {
  return utils.isObject(val) && val.show === true;
};

/**
 * Return true if a filepath exists on the file system
 */

utils.exists = function(fp) {
  return fp && (typeof utils.tryOpen(fp, 'r') === 'number');
};

/**
 * Cast `val` to an array
 *
 * @param {String|Array} `val`
 * @return {Array}
 */

utils.arrayify = function(val) {
  return val ? (Array.isArray(val) ? val : [val]) : [];
};

/**
 * Return true if a value is an object.
 */

utils.isObject = function(val) {
  return utils.typeOf(val) === 'object';
};

/**
 * Return true if a directory exists and is empty.
 *
 * @param  {*} val
 * @return {Array}
 */

utils.isEmpty = function(dir) {
  return utils.emptyDir(dir, function(fp) {
    return !/\.DS_Store/i.test(fp);
  });
};

/**
 * File-related properties. Passed to [expand-args]
 * to ensure that no undesired escaping or processing
 * is done on filepath arguments.
 */

utils.fileKeys = [
  'base', 'basename', 'cwd', 'dir',
  'dirname', 'ext', 'extname', 'f',
  'file', 'filename', 'path', 'root',
  'stem'
];

/**
 * Whitelisted flags: these flags can be passed along with task
 * arguments. To run tasks with any flags, pass `--run`
 */

utils.whitelist = [
  'ask',
  'data',
  'emit',
  'force',
  'init',
  'layout',
  'option',
  'options',
  'readme',
  'set',
  'toc',
  'verbose'
].concat(utils.fileKeys);

/**
 * Aliases to pass to minimist. Defined here
 * so that it's available to any method.
 */

utils.aliases = {
  config: 'c',
  dirname: 'dir',
  extname: 'ext',
  file: 'f',
  filename: 'stem',
  global: 'g',
  save: 's',
  verbose: 'v',
  version: 'V'
};

/**
 * Expose `utils`
 */

module.exports = utils;
<|endoftext|>


<commit_before>/**
 * Random utility functions
 */

/**
Mixes _supplier_'s properties into _receiver_.

Properties on _receiver_ or _receiver_'s prototype will not be overwritten or
shadowed unless the _overwrite_ parameter is `true`, and will not be merged
unless the _merge_ parameter is `true`.

In the default mode (0), only properties the supplier owns are copied (prototype
properties are not copied). The following copying modes are available:

  * `0`: _Default_. Object to object.
  * `1`: Prototype to prototype.
  * `2`: Prototype to prototype and object to object.
  * `3`: Prototype to object.
  * `4`: Object to prototype.

@method mix
@param {Function|Object} receiver The object or function to receive the mixed
  properties.
@param {Function|Object} supplier The object or function supplying the
  properties to be mixed.
@param {Boolean} [overwrite=false] If `true`, properties that already exist
  on the receiver will be overwritten with properties from the supplier.
@param {String[]} [whitelist] An array of property names to copy. If
  specified, only the whitelisted properties will be copied, and all others
  will be ignored.
@param {Number} [mode=0] Mix mode to use. See above for available modes.
@param {Boolean} [merge=false] If `true`, objects and arrays that already
  exist on the receiver will have the corresponding object/array from the
  supplier merged into them, rather than being skipped or overwritten. When
  both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
@return {Function|Object|YUI} The receiver, or the YUI instance if the
  specified receiver is falsy.
**/
Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
    var alwaysOverwrite, exists, from, i, key, len, to;

    // If no supplier is given, we return the receiver. If no receiver is given,
    // we return Y. Returning Y doesn't make much sense to me, but it's
    // grandfathered in for backcompat reasons.
    if (!receiver || !supplier) {
        return receiver || Y;
    }

    if (mode) {
        // In mode 2 (prototype to prototype and object to object), we recurse
        // once to do the proto to proto mix. The object to object mix will be
        // handled later on.
        if (mode === 2) {
            Y.mix(receiver.prototype, supplier.prototype, overwrite,
                    whitelist, 0, merge);
        }

        // Depending on which mode is specified, we may be copying from or to
        // the prototypes of the supplier and receiver.
        from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
        to   = mode === 1 || mode === 4 ? receiver.prototype : receiver;

        // If either the supplier or receiver doesn't actually have a
        // prototype property, then we could end up with an undefined `from`
        // or `to`. If that happens, we abort and return the receiver.
        if (!from || !to) {
            return receiver;
        }
    } else {
        from = supplier;
        to   = receiver;
    }

    // If `overwrite` is truthy and `merge` is falsy, then we can skip a
    // property existence check on each iteration and save some time.
    alwaysOverwrite = overwrite && !merge;

    if (whitelist) {
        for (i = 0, len = whitelist.length; i < len; ++i) {
            key = whitelist[i];

            // We call `Object.prototype.hasOwnProperty` instead of calling
            // `hasOwnProperty` on the object itself, since the object's
            // `hasOwnProperty` method may have been overridden or removed.
            // Also, some native objects don't implement a `hasOwnProperty`
            // method.
            if (!hasOwn.call(from, key)) {
                continue;
            }

            // The `key in to` check here is (sadly) intentional for backwards
            // compatibility reasons. It prevents undesired shadowing of
            // prototype members on `to`.
            exists = alwaysOverwrite ? false : key in to;

            if (merge && exists && isObject(to[key], true)
                    && isObject(from[key], true)) {
                // If we're in merge mode, and the key is present on both
                // objects, and the value on both objects is either an object or
                // an array (but not a function), then we recurse to merge the
                // `from` value into the `to` value instead of overwriting it.
                //
                // Note: It's intentional that the whitelist isn't passed to the
                // recursive call here. This is legacy behavior that lots of
                // code still depends on.
                Y.mix(to[key], from[key], overwrite, null, 0, merge);
            } else if (overwrite || !exists) {
                // We're not in merge mode, so we'll only copy the `from` value
                // to the `to` value if we're in overwrite mode or if the
                // current key doesn't exist on the `to` object.
                to[key] = from[key];
            }
        }
    } else {
        for (key in from) {
            // The code duplication here is for runtime performance reasons.
            // Combining whitelist and non-whitelist operations into a single
            // loop or breaking the shared logic out into a function both result
            // in worse performance, and Y.mix is critical enough that the byte
            // tradeoff is worth it.
            if (!hasOwn.call(from, key)) {
                continue;
            }

            // The `key in to` check here is (sadly) intentional for backwards
            // compatibility reasons. It prevents undesired shadowing of
            // prototype members on `to`.
            exists = alwaysOverwrite ? false : key in to;

            if (merge && exists && isObject(to[key], true)
                    && isObject(from[key], true)) {
                Y.mix(to[key], from[key], overwrite, null, 0, merge);
            } else if (overwrite || !exists) {
                to[key] = from[key];
            }
        }

        // If this is an IE browser with the JScript enumeration bug, force
        // enumeration of the buggy properties by making a recursive call with
        // the buggy properties as the whitelist.
        if (Y.Object._hasEnumBug) {
            Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
        }
    }

    return receiver;
};

exports.mix = mix;
<commit_msg>Remove unused lib/utils.js<commit_after><|endoftext|>


<commit_before>var template = require( '../templates/dirPicker.html' );
var _ = require( 'underscore' );
var open = require( 'open' );
var path = require( 'path' );

//noinspection JSUnusedGlobalSymbols
module.exports = Backbone.Marionette.LayoutView.extend( {
  className      : "js-view-dir-picker",
  template       : template,
  /**
   * @type {ModelsDirPickerAppState}
   */
  model          : require( '../models/dirPickerAppState' ),
  modelEvents    : {
    'change': 'render'
  },
  ui             : {
    selectTemplate: '#selectTemplate',
    resultPanel   : '.js-result-panel',
    variableInput : '.js-variable-input',
    variableSelect: '.js-variable-select',
    openBtn       : '.js-open-btn',
    createBtn     : '.js-create-btn',
    clipBtn       : '.js-clip-btn',
    pathSeg       : '.js-result-path-seg'
  },
  events         : {
    'change @ui.selectTemplate': 'onChangeTemplate',
    //'change @ui.variableSelect': 'onChangeSelect',
    'change @ui.variableInput' : 'onChangeVariable',
    'keyup @ui.variableInput'  : 'onKeyUpVariable',
    'click @ui.openBtn'        : 'onClickOpen',
    'click @ui.createBtn'      : 'onClickCreate',
    'click @ui.clipBtn'        : 'onClickClip',
    'dblclick @ui.pathSeg'     : 'onClickPathSeg'
  },
  templateHelpers: function () {
    var _self = this;
    //noinspection JSUnusedGlobalSymbols
    return {
      getTemplates        : function () {
        return _self.model.getTemplates();
      },
      getUsedVariablesList: function () {
        return _self.model.getUsedVariablesList();
      },
      getEvaluatedPath    : function () {
        return _self.model.getEvaluatedPath();
      },
      getSubDirLinkedPath : function () {
        var pathString = _self.model.getEvaluatedPath().path;
        var sepPathArray = pathString.split( path.sep );
        var resPathArray = [];
        while (sepPathArray.length) {
          resPathArray.unshift( sepPathArray.join( path.sep ) );
          sepPathArray.pop();
        }
        return _.map( _.zip( pathString.split( path.sep ), resPathArray ), function ( raw ) {
          return '' + raw[0] + ''
        } ).join( path.sep );

      }
    }
  },

  onRender: function () {

    //ここじゃない気もする....
    document.ondragover = document.ondrop = function ( e ) {
      // イベントの伝搬を止めて、アプリケーションのHTMLとファイルが差し替わらないようにする
      e.preventDefault();
      return false;
    };

    this.model.save();

    //templateのautoComplete
    if (this.ui.selectTemplate.typeahead) {
      this.ui.selectTemplate.typeahead( 'destroy' );
    }
    this.ui.selectTemplate.typeahead( {
      source         : this.model.getTemplates(),
      items          : 'all',
      showHintOnFocus: true,
      minLength      : 0
    } );

    //VariableのautoComplete
    var usedVariablesList = this.model.getUsedVariablesList();
    var _self = this;
    _.each( this.ui.variableSelect, function ( element ) {
      if ($( element ).typeahead) {
        $( element ).typeahead( 'destroy' );
      }
      //js-variable-select
      var targetUid = $( element ).attr( "id" );
      var targetListRow = _.find( usedVariablesList, {uid: targetUid} );
      $( element ).typeahead( {
        source         : targetListRow.list,
        items          : 'all',
        showHintOnFocus: true,
        minLength      : 0,
        displayText    : function ( item ) {return item.label},
        afterSelect    : function ( item ) {
          element.dataset.variableValue = item.val;
          _self.setValues();
          _self.render();
        }
      } );

    } );
  },

  onChangeTemplate: function () {
    this.model.set( {'template': this.ui.selectTemplate.val()}, {validate: true} );
  },
  onChangeSelect  : function () {
    console.log( 'onChangeSelect' );
    this.render();
  },

  onChangeVariable: function ( e ) {
    var element = e.target;
    element.dataset.variableValue = element.value;
    this.setValues();
    this.render();
  },

  onKeyUpVariable: function ( e ) {
    var difference = 0;
    var element = e.target;

    if (e.keyCode == 38) {
      difference = 1;
    } else if (e.keyCode == 40) {
      difference = -1;
    } else if (e.keyCode == 13) {
      this.render();
    } else {
      return;
    }
    var targetVal = element.value;
    //console.log( "targetVal:", targetVal );
    var lastPaddingRegexp = /\d+$/;
    var lastPadding = lastPaddingRegexp.exec( targetVal );
    //console.log( "lastPadding:", lastPadding );
    if (lastPadding) {
      var dstPadding = parseInt( lastPadding ) + difference;
      //console.log( "dst:", targetVal.replace( lastPaddingRegexp, dstPadding ) );
      if (dstPadding >= 0) {
        element.dataset.variableValue = targetVal.replace( lastPaddingRegexp, dstPadding );
        this.setValues();
        $( element ).val( targetVal.replace( lastPaddingRegexp, dstPadding ) )
      }
    }
  },

  onClickPathSeg: function ( e ) {
    open( e.target.dataset.path );
  },

  onClickOpen  : function () {
    this.model.openPath();
  },
  onClickCreate: function () {
    this.model.createPath();
    this.render();
  },
  onClickClip  : function () {
    this.model.clipPath();
  },
  setValues    : function () {
    console.log( 'setValues' );
    var _self = this;
    var targetElement = this.ui.variableSelect.add( this.ui.variableInput );
    _.each( targetElement, function ( element ) {
      //noinspection JSUnresolvedVariable
      _self.model.setValue( element.dataset.variableName, element.dataset.variableValue );
    } );
  }

} );<commit_msg>Fix #1 getSubDirLinkedPath<commit_after>var template = require( '../templates/dirPicker.html' );
var _ = require( 'underscore' );
var open = require( 'open' );
var path = require( 'path' );

//noinspection JSUnusedGlobalSymbols
module.exports = Backbone.Marionette.LayoutView.extend( {
  className      : "js-view-dir-picker",
  template       : template,
  /**
   * @type {ModelsDirPickerAppState}
   */
  model          : require( '../models/dirPickerAppState' ),
  modelEvents    : {
    'change': 'render'
  },
  ui             : {
    selectTemplate: '#selectTemplate',
    resultPanel   : '.js-result-panel',
    variableInput : '.js-variable-input',
    variableSelect: '.js-variable-select',
    openBtn       : '.js-open-btn',
    createBtn     : '.js-create-btn',
    clipBtn       : '.js-clip-btn',
    pathSeg       : '.js-result-path-seg'
  },
  events         : {
    'change @ui.selectTemplate': 'onChangeTemplate',
    //'change @ui.variableSelect': 'onChangeSelect',
    'change @ui.variableInput' : 'onChangeVariable',
    'keyup @ui.variableInput'  : 'onKeyUpVariable',
    'click @ui.openBtn'        : 'onClickOpen',
    'click @ui.createBtn'      : 'onClickCreate',
    'click @ui.clipBtn'        : 'onClickClip',
    'dblclick @ui.pathSeg'     : 'onClickPathSeg'
  },
  templateHelpers: function () {
    var _self = this;
    //noinspection JSUnusedGlobalSymbols
    return {
      getTemplates        : function () {
        return _self.model.getTemplates();
      },
      getUsedVariablesList: function () {
        return _self.model.getUsedVariablesList();
      },
      getEvaluatedPath    : function () {
        return _self.model.getEvaluatedPath();
      },
      getSubDirLinkedPath : function () {
        var pathString = _self.model.getEvaluatedPath().path;
        var sepPathArray = pathString.split( path.sep );
        var resPathArray = [];
        while (sepPathArray.length) {
          resPathArray.unshift( sepPathArray.join( path.sep ) );
          sepPathArray.pop();
        }
        return _.map( _.zip( pathString.split( path.sep ), resPathArray ), function ( raw ) {
          return '' + _.escape(raw[0]) + ''
        } ).join( path.sep );

      }
    }
  },

  onRender: function () {

    //ここじゃない気もする....
    document.ondragover = document.ondrop = function ( e ) {
      // イベントの伝搬を止めて、アプリケーションのHTMLとファイルが差し替わらないようにする
      e.preventDefault();
      return false;
    };

    this.model.save();

    //templateのautoComplete
    if (this.ui.selectTemplate.typeahead) {
      this.ui.selectTemplate.typeahead( 'destroy' );
    }
    this.ui.selectTemplate.typeahead( {
      source         : this.model.getTemplates(),
      items          : 'all',
      showHintOnFocus: true,
      minLength      : 0
    } );

    //VariableのautoComplete
    var usedVariablesList = this.model.getUsedVariablesList();
    var _self = this;
    _.each( this.ui.variableSelect, function ( element ) {
      if ($( element ).typeahead) {
        $( element ).typeahead( 'destroy' );
      }
      //js-variable-select
      var targetUid = $( element ).attr( "id" );
      var targetListRow = _.find( usedVariablesList, {uid: targetUid} );
      $( element ).typeahead( {
        source         : targetListRow.list,
        items          : 'all',
        showHintOnFocus: true,
        minLength      : 0,
        displayText    : function ( item ) {return item.label},
        afterSelect    : function ( item ) {
          element.dataset.variableValue = item.val;
          _self.setValues();
          _self.render();
        }
      } );

    } );
  },

  onChangeTemplate: function () {
    this.model.set( {'template': this.ui.selectTemplate.val()}, {validate: true} );
  },
  onChangeSelect  : function () {
    console.log( 'onChangeSelect' );
    this.render();
  },

  onChangeVariable: function ( e ) {
    var element = e.target;
    element.dataset.variableValue = element.value;
    this.setValues();
    this.render();
  },

  onKeyUpVariable: function ( e ) {
    var difference = 0;
    var element = e.target;

    if (e.keyCode == 38) {
      difference = 1;
    } else if (e.keyCode == 40) {
      difference = -1;
    } else if (e.keyCode == 13) {
      this.render();
    } else {
      return;
    }
    var targetVal = element.value;
    //console.log( "targetVal:", targetVal );
    var lastPaddingRegexp = /\d+$/;
    var lastPadding = lastPaddingRegexp.exec( targetVal );
    //console.log( "lastPadding:", lastPadding );
    if (lastPadding) {
      var dstPadding = parseInt( lastPadding ) + difference;
      //console.log( "dst:", targetVal.replace( lastPaddingRegexp, dstPadding ) );
      if (dstPadding >= 0) {
        element.dataset.variableValue = targetVal.replace( lastPaddingRegexp, dstPadding );
        this.setValues();
        $( element ).val( targetVal.replace( lastPaddingRegexp, dstPadding ) )
      }
    }
  },

  onClickPathSeg: function ( e ) {
    open( e.target.dataset.path );
  },

  onClickOpen  : function () {
    this.model.openPath();
  },
  onClickCreate: function () {
    this.model.createPath();
    this.render();
  },
  onClickClip  : function () {
    this.model.clipPath();
  },
  setValues    : function () {
    console.log( 'setValues' );
    var _self = this;
    var targetElement = this.ui.variableSelect.add( this.ui.variableInput );
    _.each( targetElement, function ( element ) {
      //noinspection JSUnresolvedVariable
      _self.model.setValue( element.dataset.variableName, element.dataset.variableValue );
    } );
  }

} );<|endoftext|>


<commit_before>import DS from 'ember-data';

export default DS.Model.extend({
  app: DS.belongsTo('app', {inverse: 'builds'}),

  sha: DS.attr('string'),
  job: DS.attr('string'),
  branch: DS.attr('string'),
  createdAt: DS.attr('date'),

  isLive: function() {
    return this === this.get('app.liveBuild');
  }.property('app.liveBuild'),

  activate: function() {
    return this.get('app').set('liveBuild', this).save();
  },

  shortSha: function() {
    return this.get('sha').slice(0, 6);
  }.property('sha'),

  location: function() {
    var base = this.get('app.location');
    var isLive = this.get('isLive');
    var sha = this.get('sha');

    return isLive ? base : `${base}?sha=${sha}`;
  }.property('app.location', 'isLive', 'sha')
});
<commit_msg>[#49] Ember, link to builds by id<commit_after>import DS from 'ember-data';

export default DS.Model.extend({
  app: DS.belongsTo('app', {inverse: 'builds'}),

  sha: DS.attr('string'),
  job: DS.attr('string'),
  branch: DS.attr('string'),
  createdAt: DS.attr('date'),

  isLive: function() {
    return this === this.get('app.liveBuild');
  }.property('app.liveBuild'),

  activate: function() {
    return this.get('app').set('liveBuild', this).save();
  },

  shortSha: function() {
    return this.get('sha').slice(0, 6);
  }.property('sha'),

  location: function() {
    var base = this.get('app.location');
    var isLive = this.get('isLive');
    var id = this.get('id');

    return isLive ? base : `${base}?id=${id}`;
  }.property('app.location', 'isLive', 'id')
});
<|endoftext|>


<commit_before>const sqlString = require('sqlstring');

/*
 * Pluralize a word based on count
 */
exports.pluralize = (word, count) => {
  return count === 1 ? word : `${word}s`;
};

/*
 * Calculate seconds from midnight for HH:mm:ss / H:m:s
 */
exports.calculateHourTimestamp = time => {
  const split = time.split(':').map(d => Number.parseInt(d, 10));
  if (split.length !== 3) {
    return null;
  }

  return (split[0] * 3600) + (split[1] * 60) + split[2];
};

exports.formatSelectClause = fields => {
  let selectClause = 'SELECT ';
  if (fields.length > 1) {
    selectClause += fields.map(fieldName => sqlString.escapeId(fieldName)).join(', ');
  } else {
    selectClause += '*';
  }

  return selectClause;
};

exports.formatWhereClause = (key, value) => {
  if (Array.isArray(value)) {
    return `${sqlString.escapeId(key)} IN (${value.map(v => sqlString.escape(v)).join(', ')})`;
  }

  if (value === null) {
    return `${sqlString.escapeId(key)} IS NULL`;
  }

  return `${sqlString.escapeId(key)} = ${sqlString.escape(value)}`;
};

exports.formatWhereClauses = query => {
  if (Object.keys(query).length === 0) {
    return '';
  }

  const whereClauses = Object.entries(query).map(([key, value]) => exports.formatWhereClause(key, value));
  return `WHERE ${whereClauses.join(' AND ')}`;
};

exports.formatOrderByClause = orderBy => {
  let orderByClause = '';

  if (orderBy.length > 0) {
    orderByClause += 'ORDER BY ';

    orderByClause += orderBy.map(([key, value]) => {
      const direction = value === 'DESC' ? 'DESC' : 'ASC';
      return `${sqlString.escapeId(key)} ${direction}`;
    }).join(', ');
  }

  return orderByClause;
};
<commit_msg>Fix for selecting a single field.<commit_after>const sqlString = require('sqlstring');

/*
 * Pluralize a word based on count
 */
exports.pluralize = (word, count) => {
  return count === 1 ? word : `${word}s`;
};

/*
 * Calculate seconds from midnight for HH:mm:ss / H:m:s
 */
exports.calculateHourTimestamp = time => {
  const split = time.split(':').map(d => Number.parseInt(d, 10));
  if (split.length !== 3) {
    return null;
  }

  return (split[0] * 3600) + (split[1] * 60) + split[2];
};

exports.formatSelectClause = fields => {
  let selectClause = 'SELECT ';
  if (fields.length > 0) {
    selectClause += fields.map(fieldName => sqlString.escapeId(fieldName)).join(', ');
  } else {
    selectClause += '*';
  }

  return selectClause;
};

exports.formatWhereClause = (key, value) => {
  if (Array.isArray(value)) {
    return `${sqlString.escapeId(key)} IN (${value.map(v => sqlString.escape(v)).join(', ')})`;
  }

  if (value === null) {
    return `${sqlString.escapeId(key)} IS NULL`;
  }

  return `${sqlString.escapeId(key)} = ${sqlString.escape(value)}`;
};

exports.formatWhereClauses = query => {
  if (Object.keys(query).length === 0) {
    return '';
  }

  const whereClauses = Object.entries(query).map(([key, value]) => exports.formatWhereClause(key, value));
  return `WHERE ${whereClauses.join(' AND ')}`;
};

exports.formatOrderByClause = orderBy => {
  let orderByClause = '';

  if (orderBy.length > 0) {
    orderByClause += 'ORDER BY ';

    orderByClause += orderBy.map(([key, value]) => {
      const direction = value === 'DESC' ? 'DESC' : 'ASC';
      return `${sqlString.escapeId(key)} ${direction}`;
    }).join(', ');
  }

  return orderByClause;
};
<|endoftext|>


<commit_before>/*
 * vim: ts=4:sw=4:expandtab
 */
(function () {
    'use strict';
    window.Whisper = window.Whisper || {};

    /*
    * Generic list view that watches a given collection, wraps its members in
    * a given child view and adds the child view elements to its own element.
    */
    Whisper.ListView = Backbone.View.extend({
        tagName: 'ul',
        itemView: Backbone.View,
        initialize: function(options) {
            this.options = options || {};
            this.listenTo(this.collection, 'add', this.addOne);
            this.listenTo(this.collection, 'reset', this.addAll);
        },

        addOne: function(model) {
            if (this.itemView) {
                var options = Object.assign({}, this.options.toInclude, {model: model});
                var view = new this.itemView(options);
                this.$el.append(view.render().el);
                this.$el.trigger('add');
            }
        },

        addAll: function() {
            this.$el.html('');
            this.collection.each(this.addOne, this);
        },

        render: function() {
            this.addAll();
            return this;
        }
    });
})();
<commit_msg>Object.assign -> _.extend(), for to make Chrome 45 and below work<commit_after>/*
 * vim: ts=4:sw=4:expandtab
 */
(function () {
    'use strict';
    window.Whisper = window.Whisper || {};

    /*
    * Generic list view that watches a given collection, wraps its members in
    * a given child view and adds the child view elements to its own element.
    */
    Whisper.ListView = Backbone.View.extend({
        tagName: 'ul',
        itemView: Backbone.View,
        initialize: function(options) {
            this.options = options || {};
            this.listenTo(this.collection, 'add', this.addOne);
            this.listenTo(this.collection, 'reset', this.addAll);
        },

        addOne: function(model) {
            if (this.itemView) {
                var options = _.extend({}, this.options.toInclude, {model: model});
                var view = new this.itemView(options);
                this.$el.append(view.render().el);
                this.$el.trigger('add');
            }
        },

        addAll: function() {
            this.$el.html('');
            this.collection.each(this.addOne, this);
        },

        render: function() {
            this.addAll();
            return this;
        }
    });
})();
<|endoftext|>


<commit_before>/**
 * Exposing useful utilities.
 */
 module.exports.getDateString = getDateString;
 module.exports.getUserHome = getUserHome;

/**
 * Formatting date into a better form.
 *
 * @return {String} date string
 * @api public
 */
function getDateString() {
  var today = new Date();
  var dd = today.getDate();
  var mm = today.getMonth()+1; //January is 0!
  var yyyy = today.getFullYear();

  if (dd < 10) {
      dd = '0' + dd;
  }
  if (mm < 10) {
      mm = '0' + mm;
  }

  today = mm+'/'+dd+'/'+yyyy;
  return today;
}

/**
 * Standard way of getting user's home directory.
 *
 * @return {String} home directory
 * @api public
 */
function getUserHome() {
  return process.env[(process.platform === 'win32') ?
    'USERPROFILE' : 'HOME'];
}
<commit_msg>Codesmithing<commit_after>/**
 * Exposing useful utilities.
 */
 module.exports.getDateString = getDateString;
 module.exports.getUserHome = getUserHome;

/**
 * Formatting date into a better form.
 *
 * @return {String} date string
 * @api public
 */
function getDateString() {
  var today = new Date();
  var dd = today.getDate();
  var mm = today.getMonth()+1; //January is 0!
  var yyyy = today.getFullYear();

  if (dd < 10) {
    dd = '0' + dd;
  }
  if (mm < 10) {
    mm = '0' + mm;
  }

  today = mm + '/' + dd + '/' + yyyy;
  return today;
}

/**
 * Standard way of getting user's home directory.
 *
 * @return {String} home directory
 * @api public
 */
function getUserHome() {
  return process.env[(process.platform === 'win32') ?
    'USERPROFILE' : 'HOME'];
}
<|endoftext|>


<commit_before>/* vim: ts=4:sw=4:expandtab
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
var Whisper = Whisper || {};

(function () {
    'use strict';

    /*
    * Generic list view that watches a given collection, wraps its members in
    * a given child view and adds the child view elements to its own element.
    */
    Whisper.ListView = Backbone.View.extend({
        tagName: 'ul',
        itemView: Backbone.View,
        initialize: function() {
            this.listenTo(this.collection, 'change', this.render); // auto update
            this.listenTo(this.collection, 'add', this.addOne);
            this.listenTo(this.collection, 'reset', this.addAll);
            this.listenTo(this.collection, 'all', this.render);
        },

        addOne: function(model) {
        if (this.itemView) {
                var view = new this.itemView({model: model});
                this.$el.append(view.render().el);
                this.$el.trigger('add');
            }
        },

        addAll: function() {
            this.$el.html('');
            this.collection.each(this.addOne, this);
            this.resize();
        },

        resize: function() {
            var height = window.innerHeight - $('#header').height() - $('#footer').height();
            if (this.$el.height() > height) {
                this.$el.css('height', height + 'px');
                this.$el.css('overflow-y', 'scroll');
            } else {
                this.$el.css('height', 'auto');
                this.$el.css('overflow-y', 'auto');
            }
        },

        render: function() {
            this.addAll();
            return this;
        }
    });
})();
<commit_msg>Simplify list view resizing<commit_after>/* vim: ts=4:sw=4:expandtab
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
var Whisper = Whisper || {};

(function () {
    'use strict';

    /*
    * Generic list view that watches a given collection, wraps its members in
    * a given child view and adds the child view elements to its own element.
    */
    Whisper.ListView = Backbone.View.extend({
        tagName: 'ul',
        itemView: Backbone.View,
        initialize: function() {
            this.listenTo(this.collection, 'change', this.render); // auto update
            this.listenTo(this.collection, 'add', this.addOne);
            this.listenTo(this.collection, 'reset', this.addAll);
            this.listenTo(this.collection, 'all', this.render);
        },

        addOne: function(model) {
        if (this.itemView) {
                var view = new this.itemView({model: model});
                this.$el.append(view.render().el);
                this.$el.trigger('add');
            }
        },

        addAll: function() {
            this.$el.html('');
            this.collection.each(this.addOne, this);
            this.resize();
        },

        resize: function() {
            var height = window.innerHeight - $('#header').height() - $('#footer').height();
            this.$el.css('height', height + 'px');
        },

        render: function() {
            this.addAll();
            return this;
        }
    });
})();
<|endoftext|>