<commit_before>/** section: Language
 * class Function
 *
 *  Extensions to the built-in `Function` object.
**/
Object.extend(Function.prototype, (function() {
  var slice = Array.prototype.slice;

  function update(array, args) {
    var arrayLength = array.length, length = args.length;
    while (length--) array[arrayLength + length] = args[length];
    return array;
  }

  function merge(array, args) {
    array = slice.call(array, 0);
    return update(array, args);
  }

  /**
   *  Function#argumentNames() -> Array
   *
   *  Reads the argument names as stated in the function definition and returns
   *  the values as an array of strings (or an empty array if the function is
   *  defined without parameters).
   *
   *  ##### Examples
   *
   *      function fn(foo, bar) {
   *        return foo + bar;
   *      }
   *      fn.argumentNames();
   *      //-> ['foo', 'bar']
   *
   *      Prototype.emptyFunction.argumentNames();
   *      //-> []
  **/
  function argumentNames() {
    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
      .replace(/\s+/g, '').split(',');
    return names.length == 1 && !names[0] ? [] : names;
  }

  /** related to: Function#bindAsEventListener
   *  Function#bind(context[, args...]) -> Function
   *  - context (Object): The object to bind to.
   *  - args (?): Optional additional arguments to curry for the function.
   *
   *  Binds this function to the given `context` by wrapping it in another
   *  function and returning the wrapper. Whenever the resulting "bound"
   *  function is called, it will call the original ensuring that `this` is set
   *  to `context`. Also optionally curries arguments for the function.
   *
   *  ##### Examples
   *
   *  A typical use of [[Function#bind]] is to ensure that a callback (event
   *  handler, etc.) that is an object method gets called with the correct
   *  object as its context (`this` value):
   *
   *      var AlertOnClick = Class.create({
   *        initialize: function(msg) {
   *          this.msg = msg;
   *        },
   *        handleClick: function(event) {
   *          event.stop();
   *          alert(this.msg);
   *        }
   *      });
   *      var myalert = new AlertOnClick("Clicked!");
   *      $('foo').observe('click', myalert.handleClick); // <= WRONG
   *      // -> If 'foo' is clicked, the alert will be blank; "this" is wrong
   *      $('bar').observe('click', myalert.handleClick.bind(myalert)); // <= RIGHT
   *      // -> If 'bar' is clicked, the alert will be "Clicked!"
   *
   *  `bind` can also *curry* (burn in) arguments for the function if you
   *  provide them after the `context` argument:
   *
   *      var Averager = Class.create({
   *        initialize: function() {
   *          this.count = 0;
   *          this.total = 0;
   *        },
   *        add: function(addend) {
   *          ++this.count;
   *          this.total += addend;
   *        },
   *        getAverage: function() {
   *          return this.count == 0 ? NaN : this.total / this.count;
   *        }
   *      });
   *      var a = new Averager();
   *      var b = new Averager();
   *      var aAdd5 = a.add.bind(a, 5);   // Bind to a, curry 5
   *      var aAdd10 = a.add.bind(a, 10); // Bind to a, curry 10
   *      var bAdd20 = b.add.bind(b, 20); // Bind to b, curry 20
   *      aAdd5();
   *      aAdd10();
   *      bAdd20();
   *      bAdd20();
   *      alert(a.getAverage());
   *      // -> Alerts "7.5" (average of [5, 10])
   *      alert(b.getAverage());
   *      // -> Alerts "20" (average of [20, 20])
   *
   *  (To curry without binding, see [[Function#curry]].)
  **/

  function bind(context) {
    if (arguments.length < 2 && Object.isUndefined(arguments[0]))
      return this;

    if (!Object.isFunction(this))
      throw new TypeError("The object is not callable.");

    var nop = function() {};
    var __method = this, args = slice.call(arguments, 1);

    var bound = function() {
      var a = merge(args, arguments), c = context;
      // Ignore the supplied context when the bound function is called with
      // the "new" keyword.
      var c = this instanceof bound ? this : context || window;
      return __method.apply(c, a);
    };

    nop.prototype   = this.prototype;
    bound.prototype = new nop();

    return bound;
  }

  /** related to: Function#bind
   *  Function#bindAsEventListener(context[, args...]) -> Function
   *  - context (Object): The object to bind to.
   *  - args (?): Optional arguments to curry after the event argument.
   *
   *  An event-specific variant of [[Function#bind]] which ensures the function
   *  will recieve the current event object as the first argument when
   *  executing.
   *
   *  It is not necessary to use `bindAsEventListener` for all bound event
   *  handlers; [[Function#bind]] works well for the vast majority of cases.
   *  `bindAsEventListener` is only needed when:
   *
   *  - Using old-style DOM0 handlers rather than handlers hooked up via
   *    [[Event.observe]], because `bindAsEventListener` gets the event object
   *    from the right place (even on MSIE). (If you're using `Event.observe`,
   *    that's already handled.)
   *  - You want to bind an event handler and curry additional arguments but
   *    have those arguments appear after, rather than before, the event object.
   *    This mostly happens if the number of arguments will vary, and so you
   *    want to know the event object is the first argument.
   *
   *  ##### Example
   *
   *      var ContentUpdater = Class.create({
   *        initialize: function(initialData) {
   *          this.data = Object.extend({}, initialData);
   *        },
   *        // On an event, update the content in the elements whose
   *        // IDs are passed as arguments from our data
   *        updateTheseHandler: function(event) {
   *          var argIndex, id, element;
   *          event.stop();
   *          for (argIndex = 1; argIndex < arguments.length; ++argIndex) {
   *            id = arguments[argIndex];
   *            element = $(id);
   *            if (element) {
   *              element.update(String(this.data[id]).escapeHTML());
   *            }
   *          }
   *        }
   *      });
   *      var cu = new ContentUpdater({
   *        dispName: 'Joe Bloggs',
   *        dispTitle: 'Manager <provisional>',
   *        dispAge: 47
   *      });
   *      // Using bindAsEventListener because of the variable arg lists:
   *      $('btnUpdateName').observe('click',
   *        cu.updateTheseHandler.bindAsEventListener(cu, 'dispName')
   *      );
   *      $('btnUpdateAll').observe('click',
   *        cu.updateTheseHandler.bindAsEventListener(cu, 'dispName', 'dispTitle', 'dispAge')
   *      );
  **/
  function bindAsEventListener(context) {
    var __method = this, args = slice.call(arguments, 1);
    return function(event) {
      var a = update([event || window.event], args);
      return __method.apply(context, a);
    }
  }

  /**
   *  Function#curry(args...) -> Function
   *  - args (?): The arguments to curry.
   *
   *  *Curries* (burns in) arguments to a function, returning a new function
   *  that when called with call the original passing in the curried arguments
   *  (along with any new ones):
   *
   *      function showArguments() {
   *        alert($A(arguments).join(', '));
   *      }
   *      showArguments(1, 2,, 3);
   *      // -> alerts "1, 2, 3"
   *
   *      var f = showArguments.curry(1, 2, 3);
   *      f('a', 'b');
   *      // -> alerts "1, 2, 3, a, b"
   *
   *  [[Function#curry]] works just like [[Function#bind]] without the initial
   *  context argument. Use `bind` if you need to curry arguments _and_ set
   *  context at the same time.
   *
   *  The name "curry" comes from [mathematics](http://en.wikipedia.org/wiki/Currying).
  **/
  function curry() {
    if (!arguments.length) return this;
    var __method = this, args = slice.call(arguments, 0);
    return function() {
      var a = merge(args, arguments);
      return __method.apply(this, a);
    }
  }

  /**
   *  Function#delay(timeout[, args...]) -> Number
   *  - timeout (Number): The time, in seconds, to wait before calling the
   *    function.
   *  - args (?): Optional arguments to pass to the function when calling it.
   *
   *  Schedules the function to run after the specified amount of time, passing
   *  any arguments given.
   *
   *  Behaves much like `window.setTimeout`, but the timeout is in seconds
   *  rather than milliseconds. Returns an integer ID that can be used to
   *  clear the timeout with `window.clearTimeout` before it runs.
   *
   *  To schedule a function to run as soon as the interpreter is idle, use
   *  [[Function#defer]].
   *
   *  ##### Example
   *
   *      function showMsg(msg) {
   *        alert(msg);
   *      }
   *      showMsg.delay(0.1, "Hi there!");
   *      // -> Waits a 10th of a second, then alerts "Hi there!"
  **/
  function delay(timeout) {
    var __method = this, args = slice.call(arguments, 1);
    timeout = timeout * 1000;
    return window.setTimeout(function() {
      return __method.apply(__method, args);
    }, timeout);
  }

  /**
   *  Function#defer(args...) -> Number
   *  - args (?): Optional arguments to pass into the function.
   *
   *  Schedules the function to run as soon as the interpreter is idle.
   *
   *  A "deferred" function will not run immediately; rather, it will run as soon
   *  as the interpreter's call stack is empty.
   *
   *  Behaves much like `window.setTimeout` with a delay set to `0`. Returns an
   *  ID that can be used to clear the timeout with `window.clearTimeout` before
   *  it runs.
   *
   *  ##### Example
   *
   *      function showMsg(msg) {
   *        alert(msg);
   *      }
   *
   *      showMsg("One");
   *      showMsg.defer("Two");
   *      showMsg("Three");
   *      // Alerts "One", then "Three", then (after a brief pause) "Two"
   *      // Note that "Three" happens before "Two"
  **/
  function defer() {
    var args = update([0.01], arguments);
    return this.delay.apply(this, args);
  }

  /**
   *  Function#wrap(wrapper) -> Function
   *  - wrapper (Function): The function to use as a wrapper.
   *
   *  Returns a function "wrapped" around the original function.
   *
   *  [[Function#wrap]] distills the essence of aspect-oriented programming into
   *  a single method, letting you easily build on existing functions by
   *  specifying before and after behavior, transforming the return value, or
   *  even preventing the original function from being called.
   *
   *  The wraper function is called with this signature:
   *
   *      function wrapper(callOriginal[, args...])
   *
   *  ...where `callOriginal` is a function that can be used to call the
   *  original (wrapped) function (or not, as appropriate). (`callOriginal` is
   *  not a direct reference to the original function, there's a layer of
   *  indirection in-between that sets up the proper context \[`this` value\] for
   *  it.)
   *
   *  ##### Example
   *
   *      // Wrap String#capitalize so it accepts an additional argument
   *      String.prototype.capitalize = String.prototype.capitalize.wrap(
   *        function(callOriginal, eachWord) {
   *          if (eachWord && this.include(" ")) {
   *            // capitalize each word in the string
   *            return this.split(" ").invoke("capitalize").join(" ");
   *          } else {
   *            // proceed using the original function
   *            return callOriginal();
   *          }
   *        });
   *
   *      "hello world".capitalize();
   *      // -> "Hello world" (only the 'H' is capitalized)
   *      "hello world".capitalize(true);
   *      // -> "Hello World" (both 'H' and 'W' are capitalized)
  **/
  function wrap(wrapper) {
    var __method = this;
    return function() {
      var a = update([__method.bind(this)], arguments);
      return wrapper.apply(this, a);
    }
  }

  /**
   *  Function#methodize() -> Function
   *
   *  Wraps the function inside another function that, when called, pushes
   *  `this` to the original function as the first argument (with any further
   *  arguments following it).
   *
   *  The `methodize` method transforms the original function that has an
   *  explicit first argument to a function that passes `this` (the current
   *  context) as an implicit first argument at call time. It is useful when we
   *  want to transform a function that takes an object to a method of that
   *  object or its prototype, shortening its signature by one argument.
   *
   *  ##### Example
   *
   *      // A function that sets a name on a target object
   *      function setName(target, name) {
   *        target.name = name;
   *      }
   *
   *      // Use it
   *      obj = {};
   *      setName(obj, 'Fred');
   *      obj.name;
   *      // -> "Fred"
   *
   *      // Make it a method of the object
   *      obj.setName = setName.methodize();
   *
   *      // Use the method instead
   *      obj.setName('Barney');
   *      obj.name;
   *      // -> "Barney"
   *
   *  The example above is quite simplistic. It's more useful to copy methodized
   *  functions to object prototypes so that new methods are immediately shared
   *  among instances. In the Prototype library, `methodize` is used in various
   *  places such as the DOM module, so that (for instance) you can hide an
   *  element either by calling the static version of `Element.hide` and passing in
   *  an element reference or ID, like so:
   *
   *      Element.hide('myElement');
   *
   *  ...or if you already have an element reference, just calling the
   *  methodized form instead:
   *
   *      myElement.hide();
  **/
  function methodize() {
    if (this._methodized) return this._methodized;
    var __method = this;
    return this._methodized = function() {
      var a = update([this], arguments);
      return __method.apply(null, a);
    };
  }

  return {
    argumentNames:       argumentNames,
    bind:                bind,
    bindAsEventListener: bindAsEventListener,
    curry:               curry,
    delay:               delay,
    defer:               defer,
    wrap:                wrap,
    methodize:           methodize
  }
})());

<commit_msg>Don't overwrite `Function.prototype.bind` if it's already defined, whether by the native version of `bind` or by a pre-existing polyfill.<commit_after>/** section: Language
 * class Function
 *
 *  Extensions to the built-in `Function` object.
**/
Object.extend(Function.prototype, (function() {
  var slice = Array.prototype.slice;

  function update(array, args) {
    var arrayLength = array.length, length = args.length;
    while (length--) array[arrayLength + length] = args[length];
    return array;
  }

  function merge(array, args) {
    array = slice.call(array, 0);
    return update(array, args);
  }

  /**
   *  Function#argumentNames() -> Array
   *
   *  Reads the argument names as stated in the function definition and returns
   *  the values as an array of strings (or an empty array if the function is
   *  defined without parameters).
   *
   *  ##### Examples
   *
   *      function fn(foo, bar) {
   *        return foo + bar;
   *      }
   *      fn.argumentNames();
   *      //-> ['foo', 'bar']
   *
   *      Prototype.emptyFunction.argumentNames();
   *      //-> []
  **/
  function argumentNames() {
    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
      .replace(/\s+/g, '').split(',');
    return names.length == 1 && !names[0] ? [] : names;
  }

  /** related to: Function#bindAsEventListener
   *  Function#bind(context[, args...]) -> Function
   *  - context (Object): The object to bind to.
   *  - args (?): Optional additional arguments to curry for the function.
   *
   *  Binds this function to the given `context` by wrapping it in another
   *  function and returning the wrapper. Whenever the resulting "bound"
   *  function is called, it will call the original ensuring that `this` is set
   *  to `context`. Also optionally curries arguments for the function.
   *
   *  ##### Examples
   *
   *  A typical use of [[Function#bind]] is to ensure that a callback (event
   *  handler, etc.) that is an object method gets called with the correct
   *  object as its context (`this` value):
   *
   *      var AlertOnClick = Class.create({
   *        initialize: function(msg) {
   *          this.msg = msg;
   *        },
   *        handleClick: function(event) {
   *          event.stop();
   *          alert(this.msg);
   *        }
   *      });
   *      var myalert = new AlertOnClick("Clicked!");
   *      $('foo').observe('click', myalert.handleClick); // <= WRONG
   *      // -> If 'foo' is clicked, the alert will be blank; "this" is wrong
   *      $('bar').observe('click', myalert.handleClick.bind(myalert)); // <= RIGHT
   *      // -> If 'bar' is clicked, the alert will be "Clicked!"
   *
   *  `bind` can also *curry* (burn in) arguments for the function if you
   *  provide them after the `context` argument:
   *
   *      var Averager = Class.create({
   *        initialize: function() {
   *          this.count = 0;
   *          this.total = 0;
   *        },
   *        add: function(addend) {
   *          ++this.count;
   *          this.total += addend;
   *        },
   *        getAverage: function() {
   *          return this.count == 0 ? NaN : this.total / this.count;
   *        }
   *      });
   *      var a = new Averager();
   *      var b = new Averager();
   *      var aAdd5 = a.add.bind(a, 5);   // Bind to a, curry 5
   *      var aAdd10 = a.add.bind(a, 10); // Bind to a, curry 10
   *      var bAdd20 = b.add.bind(b, 20); // Bind to b, curry 20
   *      aAdd5();
   *      aAdd10();
   *      bAdd20();
   *      bAdd20();
   *      alert(a.getAverage());
   *      // -> Alerts "7.5" (average of [5, 10])
   *      alert(b.getAverage());
   *      // -> Alerts "20" (average of [20, 20])
   *
   *  (To curry without binding, see [[Function#curry]].)
  **/

  function bind(context) {
    if (arguments.length < 2 && Object.isUndefined(arguments[0]))
      return this;

    if (!Object.isFunction(this))
      throw new TypeError("The object is not callable.");

    var nop = function() {};
    var __method = this, args = slice.call(arguments, 1);

    var bound = function() {
      var a = merge(args, arguments), c = context;
      // Ignore the supplied context when the bound function is called with
      // the "new" keyword.
      var c = this instanceof bound ? this : context || window;
      return __method.apply(c, a);
    };

    nop.prototype   = this.prototype;
    bound.prototype = new nop();

    return bound;
  }

  /** related to: Function#bind
   *  Function#bindAsEventListener(context[, args...]) -> Function
   *  - context (Object): The object to bind to.
   *  - args (?): Optional arguments to curry after the event argument.
   *
   *  An event-specific variant of [[Function#bind]] which ensures the function
   *  will recieve the current event object as the first argument when
   *  executing.
   *
   *  It is not necessary to use `bindAsEventListener` for all bound event
   *  handlers; [[Function#bind]] works well for the vast majority of cases.
   *  `bindAsEventListener` is only needed when:
   *
   *  - Using old-style DOM0 handlers rather than handlers hooked up via
   *    [[Event.observe]], because `bindAsEventListener` gets the event object
   *    from the right place (even on MSIE). (If you're using `Event.observe`,
   *    that's already handled.)
   *  - You want to bind an event handler and curry additional arguments but
   *    have those arguments appear after, rather than before, the event object.
   *    This mostly happens if the number of arguments will vary, and so you
   *    want to know the event object is the first argument.
   *
   *  ##### Example
   *
   *      var ContentUpdater = Class.create({
   *        initialize: function(initialData) {
   *          this.data = Object.extend({}, initialData);
   *        },
   *        // On an event, update the content in the elements whose
   *        // IDs are passed as arguments from our data
   *        updateTheseHandler: function(event) {
   *          var argIndex, id, element;
   *          event.stop();
   *          for (argIndex = 1; argIndex < arguments.length; ++argIndex) {
   *            id = arguments[argIndex];
   *            element = $(id);
   *            if (element) {
   *              element.update(String(this.data[id]).escapeHTML());
   *            }
   *          }
   *        }
   *      });
   *      var cu = new ContentUpdater({
   *        dispName: 'Joe Bloggs',
   *        dispTitle: 'Manager <provisional>',
   *        dispAge: 47
   *      });
   *      // Using bindAsEventListener because of the variable arg lists:
   *      $('btnUpdateName').observe('click',
   *        cu.updateTheseHandler.bindAsEventListener(cu, 'dispName')
   *      );
   *      $('btnUpdateAll').observe('click',
   *        cu.updateTheseHandler.bindAsEventListener(cu, 'dispName', 'dispTitle', 'dispAge')
   *      );
  **/
  function bindAsEventListener(context) {
    var __method = this, args = slice.call(arguments, 1);
    return function(event) {
      var a = update([event || window.event], args);
      return __method.apply(context, a);
    }
  }

  /**
   *  Function#curry(args...) -> Function
   *  - args (?): The arguments to curry.
   *
   *  *Curries* (burns in) arguments to a function, returning a new function
   *  that when called with call the original passing in the curried arguments
   *  (along with any new ones):
   *
   *      function showArguments() {
   *        alert($A(arguments).join(', '));
   *      }
   *      showArguments(1, 2,, 3);
   *      // -> alerts "1, 2, 3"
   *
   *      var f = showArguments.curry(1, 2, 3);
   *      f('a', 'b');
   *      // -> alerts "1, 2, 3, a, b"
   *
   *  [[Function#curry]] works just like [[Function#bind]] without the initial
   *  context argument. Use `bind` if you need to curry arguments _and_ set
   *  context at the same time.
   *
   *  The name "curry" comes from [mathematics](http://en.wikipedia.org/wiki/Currying).
  **/
  function curry() {
    if (!arguments.length) return this;
    var __method = this, args = slice.call(arguments, 0);
    return function() {
      var a = merge(args, arguments);
      return __method.apply(this, a);
    }
  }

  /**
   *  Function#delay(timeout[, args...]) -> Number
   *  - timeout (Number): The time, in seconds, to wait before calling the
   *    function.
   *  - args (?): Optional arguments to pass to the function when calling it.
   *
   *  Schedules the function to run after the specified amount of time, passing
   *  any arguments given.
   *
   *  Behaves much like `window.setTimeout`, but the timeout is in seconds
   *  rather than milliseconds. Returns an integer ID that can be used to
   *  clear the timeout with `window.clearTimeout` before it runs.
   *
   *  To schedule a function to run as soon as the interpreter is idle, use
   *  [[Function#defer]].
   *
   *  ##### Example
   *
   *      function showMsg(msg) {
   *        alert(msg);
   *      }
   *      showMsg.delay(0.1, "Hi there!");
   *      // -> Waits a 10th of a second, then alerts "Hi there!"
  **/
  function delay(timeout) {
    var __method = this, args = slice.call(arguments, 1);
    timeout = timeout * 1000;
    return window.setTimeout(function() {
      return __method.apply(__method, args);
    }, timeout);
  }

  /**
   *  Function#defer(args...) -> Number
   *  - args (?): Optional arguments to pass into the function.
   *
   *  Schedules the function to run as soon as the interpreter is idle.
   *
   *  A "deferred" function will not run immediately; rather, it will run as soon
   *  as the interpreter's call stack is empty.
   *
   *  Behaves much like `window.setTimeout` with a delay set to `0`. Returns an
   *  ID that can be used to clear the timeout with `window.clearTimeout` before
   *  it runs.
   *
   *  ##### Example
   *
   *      function showMsg(msg) {
   *        alert(msg);
   *      }
   *
   *      showMsg("One");
   *      showMsg.defer("Two");
   *      showMsg("Three");
   *      // Alerts "One", then "Three", then (after a brief pause) "Two"
   *      // Note that "Three" happens before "Two"
  **/
  function defer() {
    var args = update([0.01], arguments);
    return this.delay.apply(this, args);
  }

  /**
   *  Function#wrap(wrapper) -> Function
   *  - wrapper (Function): The function to use as a wrapper.
   *
   *  Returns a function "wrapped" around the original function.
   *
   *  [[Function#wrap]] distills the essence of aspect-oriented programming into
   *  a single method, letting you easily build on existing functions by
   *  specifying before and after behavior, transforming the return value, or
   *  even preventing the original function from being called.
   *
   *  The wraper function is called with this signature:
   *
   *      function wrapper(callOriginal[, args...])
   *
   *  ...where `callOriginal` is a function that can be used to call the
   *  original (wrapped) function (or not, as appropriate). (`callOriginal` is
   *  not a direct reference to the original function, there's a layer of
   *  indirection in-between that sets up the proper context \[`this` value\] for
   *  it.)
   *
   *  ##### Example
   *
   *      // Wrap String#capitalize so it accepts an additional argument
   *      String.prototype.capitalize = String.prototype.capitalize.wrap(
   *        function(callOriginal, eachWord) {
   *          if (eachWord && this.include(" ")) {
   *            // capitalize each word in the string
   *            return this.split(" ").invoke("capitalize").join(" ");
   *          } else {
   *            // proceed using the original function
   *            return callOriginal();
   *          }
   *        });
   *
   *      "hello world".capitalize();
   *      // -> "Hello world" (only the 'H' is capitalized)
   *      "hello world".capitalize(true);
   *      // -> "Hello World" (both 'H' and 'W' are capitalized)
  **/
  function wrap(wrapper) {
    var __method = this;
    return function() {
      var a = update([__method.bind(this)], arguments);
      return wrapper.apply(this, a);
    }
  }

  /**
   *  Function#methodize() -> Function
   *
   *  Wraps the function inside another function that, when called, pushes
   *  `this` to the original function as the first argument (with any further
   *  arguments following it).
   *
   *  The `methodize` method transforms the original function that has an
   *  explicit first argument to a function that passes `this` (the current
   *  context) as an implicit first argument at call time. It is useful when we
   *  want to transform a function that takes an object to a method of that
   *  object or its prototype, shortening its signature by one argument.
   *
   *  ##### Example
   *
   *      // A function that sets a name on a target object
   *      function setName(target, name) {
   *        target.name = name;
   *      }
   *
   *      // Use it
   *      obj = {};
   *      setName(obj, 'Fred');
   *      obj.name;
   *      // -> "Fred"
   *
   *      // Make it a method of the object
   *      obj.setName = setName.methodize();
   *
   *      // Use the method instead
   *      obj.setName('Barney');
   *      obj.name;
   *      // -> "Barney"
   *
   *  The example above is quite simplistic. It's more useful to copy methodized
   *  functions to object prototypes so that new methods are immediately shared
   *  among instances. In the Prototype library, `methodize` is used in various
   *  places such as the DOM module, so that (for instance) you can hide an
   *  element either by calling the static version of `Element.hide` and passing in
   *  an element reference or ID, like so:
   *
   *      Element.hide('myElement');
   *
   *  ...or if you already have an element reference, just calling the
   *  methodized form instead:
   *
   *      myElement.hide();
  **/
  function methodize() {
    if (this._methodized) return this._methodized;
    var __method = this;
    return this._methodized = function() {
      var a = update([this], arguments);
      return __method.apply(null, a);
    };
  }

  var extensions = {
    argumentNames:       argumentNames,
    bindAsEventListener: bindAsEventListener,
    curry:               curry,
    delay:               delay,
    defer:               defer,
    wrap:                wrap,
    methodize:           methodize
  };

  if (!Function.prototype.bind)
    extensions.bind = bind;

  return extensions;
})());

<|endoftext|>


<commit_before>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Reboot from 'material-ui/Reboot';
import {withStyles} from 'material-ui/styles';
import withRoot from '../components/withRoot';
import Paper from 'material-ui/Paper';

import TopNavigation from '../containers/TopNavigation';
import PasteBin from '../containers/Pastebin';
const styles = {
  root: {
    height: '99.9%'
  },
};

class Index extends Component {
  render() {
    const {classes} = this.props;
    return (

        <Reboot/>
        <Paper className={classes.root}>
          <TopNavigation/>
          <PasteBin/>
        </Paper>

    );
  }
}

Index.propTypes = {
  classes: PropTypes.object.isRequired
};

Index.contextTypes = {
  store: PropTypes.object.isRequired
};

export default withRoot(withStyles(styles)(Index));
<commit_msg>Firebase-functions: Adds getPastebinId, now user getContent races server's.<commit_after>import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Reboot from 'material-ui/Reboot';
import {withStyles} from 'material-ui/styles';
import withRoot from '../components/withRoot';
import Paper from 'material-ui/Paper';

import TopNavigation from '../containers/TopNavigation';
import PasteBin from '../containers/Pastebin';
const styles = {
  root: {
    height: '99.9%'
  },
};

class Index extends Component {
  render() {
    const {classes} = this.props;
    return (

        <Reboot/>
        <Paper className={classes.root}>
          <TopNavigation/>
          <PasteBin/>
        </Paper>

    );
  }
}

Index.propTypes = {
  classes: PropTypes.object.isRequired
};
Index.contextTypes = {
  store: PropTypes.object.isRequired
};

export default withRoot(withStyles(styles)(Index));
<|endoftext|>


<commit_before>/**
 * A currency conversion module.
 */
// TODO: this API endpoint is deprecated, use a new one

const axios = require('axios');

const fns = {
    /**
     * Fetches the currency conversion rate.
     *
     * @async
     * @param from The currency to convert from.
     * @param to The currency to convert to.
     * @returns {Promise} A promise that resolves with the rate.
     */
    rate: async (from, to) => {
        const url = `http://api.fixer.io/latest?base=${from}&symbols=${to}`;
        let response = await axios.get(url);
        return response.data.rates[to];
    },
    /**
     * Converts an amount of one currency into another.
     *
     * @async
     * @param from The currency to convert from.
     * @param to The currency to convert to.
     * @param amount The amount to convert.
     * @returns {Promise} A promise that resolves with the amount in the new currency.
     */
    convert: async (amount, from, to) => {
        let exRate = await fns.rate(from, to);
        return exRate * amount;
    }
};

module.exports = fns;<commit_msg>Fix currency conversion<commit_after>/**
 * A currency conversion module.
 */

const axios = require('axios');

const fns = {
    /**
     * Fetches the currency conversion rate.
     *
     * @async
     * @param from The currency to convert from.
     * @param to The currency to convert to.
     * @returns {Promise} A promise that resolves with the rate.
     */
    rate: async (from, to) => {
        const query = `${from}_${to}`,
            url = `https://free.currencyconverterapi.com/api/v6/convert?q=${query}&compact=y`,
            response = await axios.get(url);
        return response.data[query].val;
    },
    /**
     * Converts an amount of one currency into another.
     *
     * @async
     * @param from The currency to convert from.
     * @param to The currency to convert to.
     * @param amount The amount to convert.
     * @returns {Promise} A promise that resolves with the amount in the new currency.
     */
    convert: async (amount, from, to) => {
        let exRate = await fns.rate(from, to);
        return exRate * amount;
    }
};

module.exports = fns;<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011, Yahoo! Inc.  All rights reserved.
 * Copyright (c) 2012, Log-Normal, Inc.  All rights reserved.
 * Copyrights licensed under the BSD License. See the accompanying LICENSE.txt file for terms.
 */

/**
\file boomerang.js
boomerang measures various performance characteristics of your user's browsing
experience and beacons it back to your server.

\details
To use this you'll need a web site, lots of users and the ability to do
something with the data you collect.  How you collect the data is up to
you, but we have a few ideas.
*/

// Measure the time the script started
// This has to be global so that we don't wait for the entire
// BOOMR function to download and execute before measuring the
// time.  We also declare it without `var` so that we can later
// `delete` it.  This is the only way that works on Internet Explorer
BOOMR_start = new Date().getTime();

// beaconing section
// the parameter is the window
(function(w) {

var impl, boomr, k, d=w.document;

// Short namespace because I don't want to keep typing BOOMERANG
if(typeof BOOMR === "undefined") {
	BOOMR = {};
}
// don't allow this code to be included twice
if(BOOMR.version) {
	return;
}

BOOMR.version = "0.9";

// impl is a private object not reachable from outside the BOOMR object
// users can set properties by passing in to the init() method
impl = {
	// properties
	beacon_url: "",
	// strip out everything except last two parts of hostname.
	// This doesn't work well for domains that end with a country tld,
	// but we allow the developer to override site_domain for that.
	site_domain: w.location.hostname.
				replace(/.*?([^.]+\.[^.]+)\.?$/, '$1').
				toLowerCase(),
	//! User's ip address determined on the server.  Used for the BA cookie
	user_ip: '',

	events: {
		"page_ready": [],
		"page_unload": [],
		"dom_loaded": [],
		"visibility_changed": [],
		"before_beacon": []
	},

	vars: {},

	disabled_plugins: {},

	fireEvent: function(e_name, data) {
		var i, h, e;
		if(!this.events.hasOwnProperty(e_name)) {
			return false;
		}

		e = this.events[e_name];

		for(i=0; i<e.length; i++) {
			h = e[i];
			h[0].call(h[2], data, h[1]);
		}

		return true;
	},

	addListener: function(el, sType, fn) {
		if(el.addEventListener) {
			el.addEventListener(sType, fn, false);
		}
		else if(el.attachEvent) {
			el.attachEvent("on" + sType, fn);
		}
	}
};

// We create a boomr object and then copy all its properties to BOOMR so that
// we don't overwrite anything additional that was added to BOOMR before this
// was called... for example, a plugin.
boomr = {
	t_start: BOOMR_start,
	t_end: null,

	// Utility functions
	utils: {
		getCookie: function(name) {
			if(!name) {
				return null;
			}

			name = ' ' + name + '=';

			var i, cookies;
			cookies = ' ' + d.cookie + ';';
			if ( (i=cookies.indexOf(name)) >= 0 ) {
				i += name.length;
				cookies = cookies.substring(i, cookies.indexOf(';', i));
				return cookies;
			}

			return null;
		},

		setCookie: function(name, subcookies, max_age) {
			var value=[], k, nameval, c, exp;

			if(!name) {
				return false;
			}

			for(k in subcookies) {
				if(subcookies.hasOwnProperty(k)) {
					value.push(encodeURIComponent(k) + '=' + encodeURIComponent(subcookies[k]));
				}
			}

			value = value.join('&');

			nameval = name + '=' + value;

			c = [nameval, "path=/", "domain=" + impl.site_domain];
			if(max_age) {
				exp = new Date();
				exp.setTime(exp.getTime() + max_age*1000);
				exp = exp.toGMTString();
				c.push("expires=" + exp);
			}

			if ( nameval.length < 4000 ) {
				d.cookie = c.join('; ');
				// confirm cookie was set (could be blocked by user's settings, etc.)
				return ( value === this.getCookie(name) );
			}

			return false;
		},

		getSubCookies: function(cookie) {
			var cookies_a,
			    i, l, kv,
			    cookies={};

			if(!cookie) {
				return null;
			}

			cookies_a = cookie.split('&');

			if(cookies_a.length === 0) {
				return null;
			}

			for(i=0, l=cookies_a.length; i<l; i++) {
				kv = cookies_a[i].split('=');
				kv.push("");	// just in case there's no value
				cookies[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);
			}

			return cookies;
		},

		removeCookie: function(name) {
			return this.setCookie(name, {}, 0);
		},

		pluginConfig: function(o, config, plugin_name, properties) {
			var i, props=0;

			if(!config || !config[plugin_name]) {
				return false;
			}

			for(i=0; i<properties.length; i++) {
				if(typeof config[plugin_name][properties[i]] !== "undefined") {
					o[properties[i]] = config[plugin_name][properties[i]];
					props++;
				}
			}

			return (props>0);
		}
	},

	init: function(config) {
		var i, k,
		    properties = ["beacon_url", "site_domain", "user_ip"];

		if(!config) {
			config = {};
		}

		for(i=0; i<properties.length; i++) {
			if(typeof config[properties[i]] !== "undefined") {
				impl[properties[i]] = config[properties[i]];
			}
		}

		if(typeof config.log  !== "undefined") {
			this.log = config.log;
		}
		if(!this.log) {
			this.log = function(m,l,s) { };
		}

		for(k in this.plugins) {
			// config[pugin].enabled has been set to false
			if( config[k]
				&& ("enabled" in config[k])
				&& config[k].enabled === false
			) {
				impl.disabled_plugins[k] = 1;
				continue;
			}
			else if(impl.disabled_plugins[k]) {
				delete impl.disabled_plugins[k];
			}

			// plugin exists and has an init method
			if(this.plugins.hasOwnProperty(k)
				&& typeof this.plugins[k].init === "function"
			) {
				this.plugins[k].init(config);
			}
		}

		// The developer can override onload by setting autorun to false
		if(!("autorun" in config) || config.autorun !== false) {
			if("onpagehide" in w) {
				impl.addListener(w, "pageshow", BOOMR.page_ready);
			}
			else {
				impl.addListener(w, "load", BOOMR.page_ready);
			}
		}

		impl.addListener(w, "DOMContentLoaded", function() { impl.fireEvent("dom_loaded"); });

		// visibilitychange is useful to detect if the page loaded through prerender
		// or if the page never became visible
		// http://www.w3.org/TR/2011/WD-page-visibility-20110602/
		// http://www.nczonline.net/blog/2011/08/09/introduction-to-the-page-visibility-api/
		var fire_visible = function() { impl.fireEvent("visibility_changed"); }
		if(d.webkitVisibilityState)
			impl.addListener(d, "webkitvisibilitychange", fire_visible);
		else if(d.msVisibilityState)
			impl.addListener(d, "msvisibilitychange", fire_visible);
		else if(d.visibilityState)
			impl.addListener(d, "visibilitychange", fire_visible);

		if(!("onpagehide" in w)) {
			// This must be the last one to fire
			// We only clear w on browsers that don't support onpagehide because
			// those that do are new enough to not have memory leak problems of
			// some older browsers
			impl.addListener(w, "unload", function() { w=null; });
		}

		return this;
	},

	// The page dev calls this method when they determine the page is usable.
	// Only call this if autorun is explicitly set to false
	page_ready: function() {
		impl.fireEvent("page_ready");
		return this;
	},

	subscribe: function(e_name, fn, cb_data, cb_scope) {
		var i, h, e;

		if(!impl.events.hasOwnProperty(e_name)) {
			return this;
		}

		e = impl.events[e_name];

		// don't allow a handler to be attached more than once to the same event
		for(i=0; i<e.length; i++) {
			h = e[i];
			if(h[0] === fn && h[1] === cb_data && h[2] === cb_scope) {
				return this;
			}
		}
		e.push([ fn, cb_data || {}, cb_scope || null ]);

		// Attach unload handlers directly to the window.onunload and
		// window.onbeforeunload events. The first of the two to fire will clear
		// fn so that the second doesn't fire. We do this because technically
		// onbeforeunload is the right event to fire, but all browsers don't
		// support it.  This allows us to fall back to onunload when onbeforeunload
		// isn't implemented
		if(e_name === 'page_unload') {
			var unload_handler = function() {
							if(fn) {
								fn.call(cb_scope, null, cb_data);
							}
							fn=cb_scope=cb_data=null;
						};
			// pagehide is for iOS devices
			// see http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/
			if("onpagehide" in w) {
				impl.addListener(w, "pagehide", unload_handler);
			}
			else {
				impl.addListener(w, "unload", unload_handler);
				impl.addListener(w, "beforeunload", unload_handler);
			}
		}

		return this;
	},

	addVar: function(name, value) {
		if(typeof name === "string") {
			impl.vars[name] = value;
		}
		else if(typeof name === "object") {
			var o = name, k;
			for(k in o) {
				if(o.hasOwnProperty(k)) {
					impl.vars[k] = o[k];
				}
			}
		}
		return this;
	},

	removeVar: function() {
		var i, params;
		if(!arguments.length) {
			return this;
		}

		if(arguments.length === 1
				&& Object.prototype.toString.apply(arguments[0]) === "[object Array]") {
			params = arguments[0];
		}
		else {
			params = arguments;
		}

		for(i=0; i<params.length; i++) {
			if(impl.vars.hasOwnProperty(params[i])) {
				delete impl.vars[params[i]];
			}
		}

		return this;
	},

	sendBeacon: function() {
		var k, url, img, nparams=0;

		// At this point someone is ready to send the beacon.  We send
		// the beacon only if all plugins have finished doing what they
		// wanted to do
		for(k in this.plugins) {
			if(this.plugins.hasOwnProperty(k)) {
				if(impl.disabled_plugins[k]) {
					continue;
				}
				if(!this.plugins[k].is_complete()) {
					return this;
				}
			}
		}

		impl.vars.v = BOOMR.version;
		impl.vars.u = d.URL.replace(/#.*/, '');
		// use d.URL instead of location.href because of a safari bug

		// If we reach here, all plugins have completed
		impl.fireEvent("before_beacon", impl.vars);

		// Don't send a beacon if no beacon_url has been set
		// you would do this if you want to do some fancy beacon handling
		// in the `before_beacon` event instead of a simple GET request
		if(!impl.beacon_url) {
			return this;
		}

		// if there are already url parameters in the beacon url,
		// change the first parameter prefix for the boomerang url parameters to &

		url = impl.beacon_url + ((impl.beacon_url.indexOf('?') > -1)?'&':'?');

		for(k in impl.vars) {
			if(impl.vars.hasOwnProperty(k)) {
				nparams++;
				url += "&" + encodeURIComponent(k)
					+ "="
					+ (
						impl.vars[k]===undefined || impl.vars[k]===null
						? ''
						: encodeURIComponent(impl.vars[k])
					);
			}
		}

		// only send beacon if we actually have something to beacon back
		if(nparams) {
			img = new Image();
			img.src=url;
		}

		return this;
	}

};

delete BOOMR_start;

var make_logger = function(l) {
	return function(m, s) {
		this.log(m, l, "boomerang" + (s?"."+s:"")); return this;
	};
};

boomr.debug = make_logger("debug");
boomr.info = make_logger("info");
boomr.warn = make_logger("warn");
boomr.error = make_logger("error");

if(w.YAHOO && w.YAHOO.widget && w.YAHOO.widget.Logger) {
	boomr.log = w.YAHOO.log;
}
else if(typeof w.Y !== "undefined" && typeof w.Y.log !== "undefined") {
	boomr.log = w.Y.log;
}
else if(typeof console !== "undefined" && typeof console.log !== "undefined") {
	boomr.log = function(m,l,s) { console.log(s + ": [" + l + "] " + m); };
}

for(k in boomr) {
	if(boomr.hasOwnProperty(k)) {
		BOOMR[k] = boomr[k];
	}
}

BOOMR.plugins = BOOMR.plugins || {};

}(window));

// end of boomerang beaconing section
// Now we start built in plugins.

/*jslint white: false, devel: true, onevar: true, browser: true, undef: true, nomen: true, regexp: false, continue: true, plusplus: false, bitwise: false, newcap: true, maxerr: 50, indent: 4 */
<commit_msg>extra whitespace<commit_after>/*
 * Copyright (c) 2011, Yahoo! Inc.  All rights reserved.
 * Copyright (c) 2012, Log-Normal, Inc.  All rights reserved.
 * Copyrights licensed under the BSD License. See the accompanying LICENSE.txt file for terms.
 */

/**
\file boomerang.js
boomerang measures various performance characteristics of your user's browsing
experience and beacons it back to your server.

\details
To use this you'll need a web site, lots of users and the ability to do
something with the data you collect.  How you collect the data is up to
you, but we have a few ideas.
*/

// Measure the time the script started
// This has to be global so that we don't wait for the entire
// BOOMR function to download and execute before measuring the
// time.  We also declare it without `var` so that we can later
// `delete` it.  This is the only way that works on Internet Explorer
BOOMR_start = new Date().getTime();

// beaconing section
// the parameter is the window
(function(w) {

var impl, boomr, k, d=w.document;

// Short namespace because I don't want to keep typing BOOMERANG
if(typeof BOOMR === "undefined") {
	BOOMR = {};
}
// don't allow this code to be included twice
if(BOOMR.version) {
	return;
}

BOOMR.version = "0.9";

// impl is a private object not reachable from outside the BOOMR object
// users can set properties by passing in to the init() method
impl = {
	// properties
	beacon_url: "",
	// strip out everything except last two parts of hostname.
	// This doesn't work well for domains that end with a country tld,
	// but we allow the developer to override site_domain for that.
	site_domain: w.location.hostname.
				replace(/.*?([^.]+\.[^.]+)\.?$/, '$1').
				toLowerCase(),
	//! User's ip address determined on the server.  Used for the BA cookie
	user_ip: '',

	events: {
		"page_ready": [],
		"page_unload": [],
		"dom_loaded": [],
		"visibility_changed": [],
		"before_beacon": []
	},

	vars: {},

	disabled_plugins: {},

	fireEvent: function(e_name, data) {
		var i, h, e;
		if(!this.events.hasOwnProperty(e_name)) {
			return false;
		}

		e = this.events[e_name];

		for(i=0; i<e.length; i++) {
			h = e[i];
			h[0].call(h[2], data, h[1]);
		}

		return true;
	},

	addListener: function(el, sType, fn) {
		if(el.addEventListener) {
			el.addEventListener(sType, fn, false);
		}
		else if(el.attachEvent) {
			el.attachEvent("on" + sType, fn);
		}
	}
};

// We create a boomr object and then copy all its properties to BOOMR so that
// we don't overwrite anything additional that was added to BOOMR before this
// was called... for example, a plugin.
boomr = {
	t_start: BOOMR_start,
	t_end: null,

	// Utility functions
	utils: {
		getCookie: function(name) {
			if(!name) {
				return null;
			}

			name = ' ' + name + '=';

			var i, cookies;
			cookies = ' ' + d.cookie + ';';
			if ( (i=cookies.indexOf(name)) >= 0 ) {
				i += name.length;
				cookies = cookies.substring(i, cookies.indexOf(';', i));
				return cookies;
			}

			return null;
		},

		setCookie: function(name, subcookies, max_age) {
			var value=[], k, nameval, c, exp;

			if(!name) {
				return false;
			}

			for(k in subcookies) {
				if(subcookies.hasOwnProperty(k)) {
					value.push(encodeURIComponent(k) + '=' + encodeURIComponent(subcookies[k]));
				}
			}

			value = value.join('&');

			nameval = name + '=' + value;

			c = [nameval, "path=/", "domain=" + impl.site_domain];
			if(max_age) {
				exp = new Date();
				exp.setTime(exp.getTime() + max_age*1000);
				exp = exp.toGMTString();
				c.push("expires=" + exp);
			}

			if ( nameval.length < 4000 ) {
				d.cookie = c.join('; ');
				// confirm cookie was set (could be blocked by user's settings, etc.)
				return ( value === this.getCookie(name) );
			}

			return false;
		},

		getSubCookies: function(cookie) {
			var cookies_a,
			    i, l, kv,
			    cookies={};

			if(!cookie) {
				return null;
			}

			cookies_a = cookie.split('&');

			if(cookies_a.length === 0) {
				return null;
			}

			for(i=0, l=cookies_a.length; i<l; i++) {
				kv = cookies_a[i].split('=');
				kv.push("");	// just in case there's no value
				cookies[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);
			}

			return cookies;
		},

		removeCookie: function(name) {
			return this.setCookie(name, {}, 0);
		},

		pluginConfig: function(o, config, plugin_name, properties) {
			var i, props=0;

			if(!config || !config[plugin_name]) {
				return false;
			}

			for(i=0; i<properties.length; i++) {
				if(typeof config[plugin_name][properties[i]] !== "undefined") {
					o[properties[i]] = config[plugin_name][properties[i]];
					props++;
				}
			}

			return (props>0);
		}
	},

	init: function(config) {
		var i, k,
		    properties = ["beacon_url", "site_domain", "user_ip"];

		if(!config) {
			config = {};
		}

		for(i=0; i<properties.length; i++) {
			if(typeof config[properties[i]] !== "undefined") {
				impl[properties[i]] = config[properties[i]];
			}
		}

		if(typeof config.log  !== "undefined") {
			this.log = config.log;
		}
		if(!this.log) {
			this.log = function(m,l,s) { };
		}

		for(k in this.plugins) {
			// config[pugin].enabled has been set to false
			if( config[k]
				&& ("enabled" in config[k])
				&& config[k].enabled === false
			) {
				impl.disabled_plugins[k] = 1;
				continue;
			}
			else if(impl.disabled_plugins[k]) {
				delete impl.disabled_plugins[k];
			}

			// plugin exists and has an init method
			if(this.plugins.hasOwnProperty(k)
				&& typeof this.plugins[k].init === "function"
			) {
				this.plugins[k].init(config);
			}
		}

		// The developer can override onload by setting autorun to false
		if(!("autorun" in config) || config.autorun !== false) {
			if("onpagehide" in w) {
				impl.addListener(w, "pageshow", BOOMR.page_ready);
			}
			else {
				impl.addListener(w, "load", BOOMR.page_ready);
			}
		}

		impl.addListener(w, "DOMContentLoaded", function() { impl.fireEvent("dom_loaded"); });

		// visibilitychange is useful to detect if the page loaded through prerender
		// or if the page never became visible
		// http://www.w3.org/TR/2011/WD-page-visibility-20110602/
		// http://www.nczonline.net/blog/2011/08/09/introduction-to-the-page-visibility-api/
		var fire_visible = function() { impl.fireEvent("visibility_changed"); }
		if(d.webkitVisibilityState)
			impl.addListener(d, "webkitvisibilitychange", fire_visible);
		else if(d.msVisibilityState)
			impl.addListener(d, "msvisibilitychange", fire_visible);
		else if(d.visibilityState)
			impl.addListener(d, "visibilitychange", fire_visible);

		if(!("onpagehide" in w)) {
			// This must be the last one to fire
			// We only clear w on browsers that don't support onpagehide because
			// those that do are new enough to not have memory leak problems of
			// some older browsers
			impl.addListener(w, "unload", function() { w=null; });
		}

		return this;
	},

	// The page dev calls this method when they determine the page is usable.
	// Only call this if autorun is explicitly set to false
	page_ready: function() {
		impl.fireEvent("page_ready");
		return this;
	},

	subscribe: function(e_name, fn, cb_data, cb_scope) {
		var i, h, e;

		if(!impl.events.hasOwnProperty(e_name)) {
			return this;
		}

		e = impl.events[e_name];

		// don't allow a handler to be attached more than once to the same event
		for(i=0; i<e.length; i++) {
			h = e[i];
			if(h[0] === fn && h[1] === cb_data && h[2] === cb_scope) {
				return this;
			}
		}
		e.push([ fn, cb_data || {}, cb_scope || null ]);

		// Attach unload handlers directly to the window.onunload and
		// window.onbeforeunload events. The first of the two to fire will clear
		// fn so that the second doesn't fire. We do this because technically
		// onbeforeunload is the right event to fire, but all browsers don't
		// support it.  This allows us to fall back to onunload when onbeforeunload
		// isn't implemented
		if(e_name === 'page_unload') {
			var unload_handler = function() {
							if(fn) {
								fn.call(cb_scope, null, cb_data);
							}
							fn=cb_scope=cb_data=null;
						};
			// pagehide is for iOS devices
			// see http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/
			if("onpagehide" in w) {
				impl.addListener(w, "pagehide", unload_handler);
			}
			else {
				impl.addListener(w, "unload", unload_handler);
				impl.addListener(w, "beforeunload", unload_handler);
			}
		}

		return this;
	},

	addVar: function(name, value) {
		if(typeof name === "string") {
			impl.vars[name] = value;
		}
		else if(typeof name === "object") {
			var o = name, k;
			for(k in o) {
				if(o.hasOwnProperty(k)) {
					impl.vars[k] = o[k];
				}
			}
		}
		return this;
	},

	removeVar: function() {
		var i, params;
		if(!arguments.length) {
			return this;
		}

		if(arguments.length === 1
				&& Object.prototype.toString.apply(arguments[0]) === "[object Array]") {
			params = arguments[0];
		}
		else {
			params = arguments;
		}

		for(i=0; i<params.length; i++) {
			if(impl.vars.hasOwnProperty(params[i])) {
				delete impl.vars[params[i]];
			}
		}

		return this;
	},

	sendBeacon: function() {
		var k, url, img, nparams=0;

		// At this point someone is ready to send the beacon.  We send
		// the beacon only if all plugins have finished doing what they
		// wanted to do
		for(k in this.plugins) {
			if(this.plugins.hasOwnProperty(k)) {
				if(impl.disabled_plugins[k]) {
					continue;
				}
				if(!this.plugins[k].is_complete()) {
					return this;
				}
			}
		}

		impl.vars.v = BOOMR.version;
		impl.vars.u = d.URL.replace(/#.*/, '');
		// use d.URL instead of location.href because of a safari bug

		// If we reach here, all plugins have completed
		impl.fireEvent("before_beacon", impl.vars);

		// Don't send a beacon if no beacon_url has been set
		// you would do this if you want to do some fancy beacon handling
		// in the `before_beacon` event instead of a simple GET request
		if(!impl.beacon_url) {
			return this;
		}

		// if there are already url parameters in the beacon url,
		// change the first parameter prefix for the boomerang url parameters to &

		url = impl.beacon_url + ((impl.beacon_url.indexOf('?') > -1)?'&':'?');

		for(k in impl.vars) {
			if(impl.vars.hasOwnProperty(k)) {
				nparams++;
				url += "&" + encodeURIComponent(k)
					+ "="
					+ (
						impl.vars[k]===undefined || impl.vars[k]===null
						? ''
						: encodeURIComponent(impl.vars[k])
					);
			}
		}

		// only send beacon if we actually have something to beacon back
		if(nparams) {
			img = new Image();
			img.src=url;
		}

		return this;
	}

};

delete BOOMR_start;

var make_logger = function(l) {
	return function(m, s) {
		this.log(m, l, "boomerang" + (s?"."+s:"")); return this;
	};
};

boomr.debug = make_logger("debug");
boomr.info = make_logger("info");
boomr.warn = make_logger("warn");
boomr.error = make_logger("error");

if(w.YAHOO && w.YAHOO.widget && w.YAHOO.widget.Logger) {
	boomr.log = w.YAHOO.log;
}
else if(typeof w.Y !== "undefined" && typeof w.Y.log !== "undefined") {
	boomr.log = w.Y.log;
}
else if(typeof console !== "undefined" && typeof console.log !== "undefined") {
	boomr.log = function(m,l,s) { console.log(s + ": [" + l + "] " + m); };
}

for(k in boomr) {
	if(boomr.hasOwnProperty(k)) {
		BOOMR[k] = boomr[k];
	}
}

BOOMR.plugins = BOOMR.plugins || {};

}(window));

// end of boomerang beaconing section
// Now we start built in plugins.

/*jslint white: false, devel: true, onevar: true, browser: true, undef: true, nomen: true, regexp: false, continue: true, plusplus: false, bitwise: false, newcap: true, maxerr: 50, indent: 4 */
<|endoftext|>


<commit_before>const VERSION = '7.2.0-beta1';
const PREFS_ROOT = 'extensions.HTMLRuby.';
const DEBUG = false;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cc = Components.classes;

var shutdownQueue = [];

Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/AddonManager.jsm');
Cu.import("resource://gre/modules/PopupNotifications.jsm");

(function(global) {
	var literal;
	function getXMLHttpRequest() {
		return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
	}
	global.include = function(path) {
		log('include(' + path + ')');
		Services.scriptloader.loadSubScript(path, global, 'utf-8');
	};
	global.read = function(path) {
		var request = getXMLHttpRequest();
		request.overrideMimeType('text/plain');
		request.open('GET', path, false);
		request.send(null);
		return request.responseText;
	};
	global.readAsync = function(path, callback) {
		var request = getXMLHttpRequest();
		req.overrideMimeType('text/plain');
		request.onreadystatechange = function() {
			if (request.readyState === 4) {
				callback(request.responseText);
			}
		};
		request.open('GET', path, true);
		request.send(null);
	};
	global.log = function(message) {
		if (!DEBUG)
			return;

		var d = new Date();
		Services.console.logStringMessage('HTML Ruby: ' + message + ' [' + String(d.getTime()).substr(-6, 6) + ']');
	};
	global.setString = function(path) {
		log('loading stringbundle [' + path + ']');
		literal = Services.strings.createBundle(path);
		shutdownQueue.push(function() {
			Services.strings.flushBundles();
		});
	};
	global.getString = function(name, args) {
		if (typeof args === 'undefined') {
			return literal.GetStringFromName(name);
		} else if (Array.isArray(args)) {
			return literal.formatStringFromName(name, args, args.length);
		} else {
			return literal.formatStringFromName(name, [args], 1);
		}
	};
}(this));

function install(data, reason) {
	log('install start');
	log('install end');
}

function startup(data, reason) {
	log('startup start');
	include('chrome://htmlruby/content/bootstrap/startup.js');
	log('startup end');
}

function shutdown(data, reason) {
	log('shutdown start');
	shutdownQueue.forEach(function(unloader) {
		unloader();
	});
	shutdownQueue = [];
	log('shutdown end');
}

function uninstall(data, reason) {
	log('uninstall start');
	log('clearing preferences');
	var defBranch = Services.prefs.getDefaultBranch(PREFS_ROOT);
	defBranch.deleteBranch('');
	log('uninstall end');
}<commit_msg>unload loaded JSM<commit_after>const VERSION = '7.2.0-beta1';
const PREFS_ROOT = 'extensions.HTMLRuby.';
const DEBUG = false;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cc = Components.classes;

var shutdownQueue = [];

(function(global) {
	var literal;
	function getXMLHttpRequest() {
		return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
	}
	global.include = function(path) {
		log('include(' + path + ')');
		Services.scriptloader.loadSubScript(path, global, 'utf-8');
	};
	global.read = function(path) {
		var request = getXMLHttpRequest();
		request.overrideMimeType('text/plain');
		request.open('GET', path, false);
		request.send(null);
		return request.responseText;
	};
	global.readAsync = function(path, callback) {
		var request = getXMLHttpRequest();
		req.overrideMimeType('text/plain');
		request.onreadystatechange = function() {
			if (request.readyState === 4) {
				callback(request.responseText);
			}
		};
		request.open('GET', path, true);
		request.send(null);
	};
	global.log = function(message) {
		if (!DEBUG)
			return;

		var d = new Date();
		Services.console.logStringMessage('HTML Ruby: ' + message + ' [' + String(d.getTime()).substr(-6, 6) + ']');
	};
	global.setString = function(path) {
		log('loading stringbundle [' + path + ']');
		literal = Services.strings.createBundle(path);
		shutdownQueue.push(function() {
			Services.strings.flushBundles();
		});
	};
	global.getString = function(name, args) {
		if (typeof args === 'undefined') {
			return literal.GetStringFromName(name);
		} else if (Array.isArray(args)) {
			return literal.formatStringFromName(name, args, args.length);
		} else {
			return literal.formatStringFromName(name, [args], 1);
		}
	};
}(this));

function install(data, reason) {
	log('install start');
	log('install end');
}

function startup(data, reason) {
	log('startup start');
	Cu.import('resource://gre/modules/Services.jsm');
	Cu.import('resource://gre/modules/AddonManager.jsm');
	Cu.import('resource://gre/modules/PopupNotifications.jsm');
	include('chrome://htmlruby/content/bootstrap/startup.js');
	log('startup end');
}

function shutdown(data, reason) {
	log('shutdown start');
	shutdownQueue.forEach(function(unloader) {
		unloader();
	});
	shutdownQueue = [];
	Cu.unload('resource://gre/modules/Services.jsm');
	Cu.unload('resource://gre/modules/AddonManager.jsm');
	Cu.unload('resource://gre/modules/PopupNotifications.jsm');
	log('shutdown end');
}

function uninstall(data, reason) {
	log('uninstall start');
	log('clearing preferences');
	var defBranch = Services.prefs.getDefaultBranch(PREFS_ROOT);
	defBranch.deleteBranch('');
	log('uninstall end');
}<|endoftext|>


<commit_before>const {classes: Cc, interfaces: Ci, utils: Cu} = Components;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");

const RESOURCE_HOST = "verticaltabs";
const PREF_BRANCH = "extensions.verticaltabs.";
const DEFAULT_PREFS = {
  "extensions.verticaltabs.width": 250,
  "extensions.verticaltabs.right": false,
  "browser.allTabs.previews": true
};

let unloaders = [];

function setDefaultPrefs() {
  let branch = Services.prefs.getDefaultBranch("");
  for (let [name, value] in Iterator(DEFAULT_PREFS)) {
    switch (typeof value) {
      case "boolean":
        branch.setBoolPref(name, value);
        break;
      case "number":
        branch.setIntPref(name, value);
        break;
      case "string":
        branch.setCharPref(name, value);
        break;
    }
  }
}

function loadIntoWindow(win) {
  let vt = new VerticalTabs(win);
  unloaders.push(vt.unload.bind(vt));
}

function runOnLoad(window, callback) {
  window.addEventListener("DOMContentLoaded", function onLoad() {
    window.removeEventListener("DOMContentLoaded", onLoad, false);
    callback(window);
  }, false);
}

function eachWindow(callback) {
  let enumerator = Services.wm.getEnumerator("navigator:browser");
  while (enumerator.hasMoreElements()) {
    let win = enumerator.getNext();
    if (win.document.readyState === "complete") {
      callback(win);
    } else {
      runOnLoad(win, callback);
    }
  }
}

function windowWatcher(subject, topic) {
  if (topic !== "domwindowopened") {
    return;
  }
  let win = subject.QueryInterface(Ci.nsIDOMWindow);
  // We don't know the type of the window at this point yet, only when
  // the load event has been fired.
  runOnLoad(win, function (win) {
    let doc = win.document.documentElement;
    if (doc.getAttribute("windowtype") == "navigator:browser") {
      loadIntoWindow(win);
    }
  });
}

function registerResource(name, installPath) {
  let resource = Services.io.getProtocolHandler("resource")
                         .QueryInterface(Ci.nsIResProtocolHandler);
  let alias = Services.io.newFileURI(installPath);
  if (!installPath.isDirectory()) {
    alias = Services.io.newURI("jar:" + alias.spec + "!/", null, null);
  }
  resource.setSubstitution(name, alias);
  unloaders.push(function () {
    resource.setSubstitution(name, null);
  });
}

function startup(data, reason) {
  setDefaultPrefs();
  unloaders.push(function() {
    Services.prefs.getDefaultBranch(PREF_BRANCH).deleteBranc();
  });

  AddonManager.getAddonByID(data.id, function(addon) {
    registerResource(RESOURCE_HOST, data.installPath);
    Cu.import("resource://verticaltabs/content/verticaltabs.js");

    eachWindow(loadIntoWindow);

    Services.ww.registerNotification(windowWatcher);
    unloaders.push(function() {
      Services.ww.unregisterNotification(windowWatcher);
    });
  });
};

function shutdown(data, reason) {
  if (reason == APP_SHUTDOWN) {
    return;
  }
  unloaders.forEach(function(unload) {
    unload();
  });
}

function install() {
}

function uninstall() {
}
<commit_msg>Fix pref clean up<commit_after>const {classes: Cc, interfaces: Ci, utils: Cu} = Components;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");

const RESOURCE_HOST = "verticaltabs";
const PREF_BRANCH = "extensions.verticaltabs.";
const DEFAULT_PREFS = {
  "extensions.verticaltabs.width": 250,
  "extensions.verticaltabs.right": false,
  "browser.allTabs.previews": true
};

let unloaders = [];

function setDefaultPrefs() {
  let branch = Services.prefs.getDefaultBranch("");
  for (let [name, value] in Iterator(DEFAULT_PREFS)) {
    switch (typeof value) {
      case "boolean":
        branch.setBoolPref(name, value);
        break;
      case "number":
        branch.setIntPref(name, value);
        break;
      case "string":
        branch.setCharPref(name, value);
        break;
    }
  }
}

function loadIntoWindow(win) {
  let vt = new VerticalTabs(win);
  unloaders.push(vt.unload.bind(vt));
}

function runOnLoad(window, callback) {
  window.addEventListener("DOMContentLoaded", function onLoad() {
    window.removeEventListener("DOMContentLoaded", onLoad, false);
    callback(window);
  }, false);
}

function eachWindow(callback) {
  let enumerator = Services.wm.getEnumerator("navigator:browser");
  while (enumerator.hasMoreElements()) {
    let win = enumerator.getNext();
    if (win.document.readyState === "complete") {
      callback(win);
    } else {
      runOnLoad(win, callback);
    }
  }
}

function windowWatcher(subject, topic) {
  if (topic !== "domwindowopened") {
    return;
  }
  let win = subject.QueryInterface(Ci.nsIDOMWindow);
  // We don't know the type of the window at this point yet, only when
  // the load event has been fired.
  runOnLoad(win, function (win) {
    let doc = win.document.documentElement;
    if (doc.getAttribute("windowtype") == "navigator:browser") {
      loadIntoWindow(win);
    }
  });
}

function registerResource(name, installPath) {
  let resource = Services.io.getProtocolHandler("resource")
                         .QueryInterface(Ci.nsIResProtocolHandler);
  let alias = Services.io.newFileURI(installPath);
  if (!installPath.isDirectory()) {
    alias = Services.io.newURI("jar:" + alias.spec + "!/", null, null);
  }
  resource.setSubstitution(name, alias);
  unloaders.push(function () {
    resource.setSubstitution(name, null);
  });
}

function startup(data, reason) {
  setDefaultPrefs();
  unloaders.push(function() {
    Services.prefs.getDefaultBranch(PREF_BRANCH).deleteBranch("");
  });

  AddonManager.getAddonByID(data.id, function(addon) {
    registerResource(RESOURCE_HOST, data.installPath);
    Cu.import("resource://verticaltabs/content/verticaltabs.js");

    eachWindow(loadIntoWindow);

    Services.ww.registerNotification(windowWatcher);
    unloaders.push(function() {
      Services.ww.unregisterNotification(windowWatcher);
    });
  });
};

function shutdown(data, reason) {
  if (reason == APP_SHUTDOWN) {
    return;
  }
  unloaders.forEach(function(unload) {
    unload();
  });
}

function install() {
}

function uninstall() {
}
<|endoftext|>


<commit_before>'use strict'
module.exports = {
  cssUl: {
    'list-style-type': 'none',
    '-webkit-margin-before': '0px',
    '-webkit-margin-after': '0px',
    '-webkit-margin-start': '0px',
    '-webkit-margin-end': '0px',
    '-webkit-padding-start': '0px'
  },
  cssLi: {
    'list-style-type': 'none',
    '-webkit-margin-before': '0px',
    '-webkit-margin-after': '0px',
    '-webkit-margin-start': '0px',
    '-webkit-margin-end': '0px',
    '-webkit-padding-start': '0px',
    'margin-left': '10px'
  },
  label: {
    'vertical-align': 'top',
    'font-family': 'arial,sans-serif'
  },
  caret: {
    'position': 'absolute',
    'margin-top': '3px'
  },
  data: {
    'margin-left': '10px'
  }
}
<commit_msg>fix caret placement for struct data<commit_after>'use strict'
module.exports = {
  cssUl: {
    'list-style-type': 'none',
    '-webkit-margin-before': '0px',
    '-webkit-margin-after': '0px',
    '-webkit-margin-start': '0px',
    '-webkit-margin-end': '0px',
    '-webkit-padding-start': '0px'
  },
  cssLi: {
    'list-style-type': 'none',
    '-webkit-margin-before': '0px',
    '-webkit-margin-after': '0px',
    '-webkit-margin-start': '0px',
    '-webkit-margin-end': '0px',
    '-webkit-padding-start': '0px',
    'margin-left': '10px'
  },
  label: {
    'vertical-align': 'top',
    'font-family': 'arial,sans-serif'
  },
  caret: {
    'margin-top': '3px'
  },
  data: {
    'margin-left': '10px'
  }
}
<|endoftext|>


<commit_before>buster.testCase("Backbone.Validation builtin validator", {
    setUp: function() {
        this.valid = this.spy();
        this.invalid = this.spy();

        this.model = new Backbone.Model();
        this.view = new Backbone.View({
            model: this.model
        });

        Backbone.Validation.bind(this.view, {
            valid: this.valid,
            invalid: this.invalid
        });
    },

    "'function'": {
        setUp: function() {
            var that = this;
            this.model.validation = {
                name: function(val){
                    that.ctx = this;
                    if(name !== 'backbone') {
                        return 'Error';
                    }
                }
            };
        },

        "should call specified method": function() {
            refute(this.model.set({name: ''}));
        },

        "context should be the model": function() {
            this.model.set({name: ''});
            assert.same(this.ctx, this.model);
        }
    },

    "'named function'": {
        setUp: function() {
            var that = this;
            this.model.validation = {
                name: 'validateName'
            };

            this.model.validateName = function(val){
                that.ctx = this;
                if(name !== 'backbone') {
                    return 'Error';
                }
            };
        },

        "should call specified method on the model": function() {
            refute(this.model.set({name: ''}));
        },

        "context should be the model": function() {
            this.model.set({name: ''});
            assert.same(this.ctx, this.model);
        }
    },

    "'required'": {
        setUp: function() {
            this.model.validation = {
                name: {
                    required: true
                },
                agree: {
                    required: true
                }
            };
        },

        "empty string should be invalid": function() {
            refute(this.model.set({
                name: ''
            }));
        },

        "blank string should be invalid": function() {
            refute(this.model.set({
                name: '  '
            }));
        },

        "null should be invalid": function() {
            refute(this.model.set({
                name: null
            }));
        },

        "undefined should be invalid": function() {
            refute(this.model.set({
                name: undefined
            }));
        },

        "false boolean should be invalid": function() {
            refute(this.model.set({
                agree: false
            }));
        },

        "true boolean should be valid": function() {
            assert(this.model.set({
                agree: true
            }));
        }
    },

    "'min'": {
        setUp: function() {
            this.model.validation = {
                age: {
                    min: 1
                }
            };
        },

        "undefined should be invalid": function() {
            refute(this.model.set({
                age: undefined
            }));
        },

        "setting value lower than min should be invalid": function() {
            refute(this.model.set({
                age: 0
            }));
        },

        "setting non numeric value should be invalid": function() {
            refute(this.model.set({
                age: '10error'
            }));
        },

        "setting value equal to min should be valid": function() {
            assert(this.model.set({
                age: 1
            }));
        },

        "setting numeric string value equal to min should be valid": function() {
            assert(this.model.set({
                age: '1'
            }));
        }
    },

    "'max'": {
        setUp: function() {
            this.model.validation = {
                age: {
                    max: 10
                }
            };
        },

        "undefined should be invalid": function() {
            refute(this.model.set({
                age: undefined
            }));
        },

        "setting value higher than max should be invalid": function() {
            refute(this.model.set({
                age: 11
            }));
        },

        "setting non numeric value should be invalid": function() {
            refute(this.model.set({
                age: '10error'
            }));
        },

        "setting value equal to max should be valid": function() {
            assert(this.model.set({
                age: 10
            }));
        },

        "setting numeric string value equal to max should be valid": function() {
            assert(this.model.set({
                age: '10'
            }));
        }
    },

    "'min' and 'max'": {
        setUp: function() {
            this.model.validation = {
                age: {
                    min: 1,
                    max: 10
                }
            };
        },

        "setting value lower than min should be invalid": function() {
            refute(this.model.set({
                age: 0
            }));
        },

        "setting value equal to min should be valid": function() {
            assert(this.model.set({
                age: 1
            }));
        },

        "setting value higher than max should be invalid": function() {
            refute(this.model.set({
                age: 11
            }));
        },

        "setting value equal to max should be valid": function() {
            assert(this.model.set({
                age: 10
            }));
        }
    },

    "'length'": {
        setUp: function() {
            this.model.validation = {
                postalCode: {
                    length: 2
                }
            };
        },

        "undefined should be invalid": function() {
            refute(this.model.set({
                postalCode: undefined
            }));
        },

        "setting value with length shorter than length should be invalid": function() {
            refute(this.model.set({
                postalCode: 'a'
            }));
        },

        "setting value with length longer than length should be invalid": function() {
            refute(this.model.set({
                postalCode: 'aaa'
            }));
        },

        "setting value with length equal to length should be valid": function() {
            assert(this.model.set({
                postalCode: 'aa'
            }));
        }
    },

    "'minLength'": {
        setUp: function() {
            this.model.validation = {
                name: {
                    minLength: 2
                }
            };
        },

        "undefined should be invalid": function() {
            refute(this.model.set({
                name: undefined
            }));
        },

        "setting value with length shorter than minLenght should be invalid": function() {
            refute(this.model.set({
                name: 'a'
            }));
        },

        "setting value with length equal to minLength should be valid": function() {
            assert(this.model.set({
                name: 'aa'
            }));
        }
    },

    "'maxLength'": {
        setUp: function() {
            this.model.validation = {
                name: {
                    maxLength: 2
                }
            };
        },

        "setting value with length longer than maxLenght should be invalid": function() {
            refute(this.model.set({
                name: 'aaa'
            }));
        },

        "setting value with length equal to maxLength should be valid": function() {
            assert(this.model.set({
                name: 'aa'
            }));
        }
    },

    "'email pattern'": {
        setUp: function() {
            this.model.validation = {
                email: {
                    pattern: 'email'
                }
            };
        },

        "setting invalid email should be invalid": function() {
            refute(this.model.set({
                email: 'aaa'
            }));
        },

        "setting valid email should be valid": function() {
            assert(this.model.set({
                email: 'a@example.com'
            }));
        }
    },

    "'url pattern'": {
        setUp: function() {
            this.model.validation = {
                url: {
                    pattern: 'url'
                }
            };
        },

        "setting invalid url should be invalid": function() {
            refute(this.model.set({
                url: 'aaa'
            }));
        },

        "setting valid url should be valid": function() {
            assert(this.model.set({
                url: 'http://www.example.com?something=true&'
            }));
        }
    },

    "'number pattern'": {
        setUp: function() {
            this.model.validation = {
                age: {
                    pattern: 'number'
                }
            };
        },

        "setting non numeric value should be invalid": function() {
            refute(this.model.set({
                age: '1a'
            }));
        },

        "setting numeric value with one digit should be valid": function() {
            assert(this.model.set({
                age: 1
            }));
        },

        "setting negative numeric value with one digit should be valid": function() {
            assert(this.model.set({
                age: -1
            }));
        },

        "setting numeric value with several digits should be valid": function() {
            assert(this.model.set({
                age: 1234
            }));
        },

        "setting numeric string value should be valid": function() {
            assert(this.model.set({
                age: "1234"
            }));
        },

        "setting negative numeric string value should be valid": function() {
            assert(this.model.set({
                age: "-1234"
            }));
        }
    },

    "'pattern'": {
        setUp: function() {
            this.model.validation = {
                name: {
                    pattern: /^test/
                }
            };
        },

        "setting value not matching pattern should be invalid": function() {
            refute(this.model.set({
                name: 'aaa'
            }));
        },

        "setting value matching pattern should be valid": function() {
            assert(this.model.set({
                name: 'test'
            }));
        }
    }
});
<commit_msg>Renamed some tests<commit_after>buster.testCase("Backbone.Validation builtin validator", {
    setUp: function() {
        this.model = new Backbone.Model();
        this.view = new Backbone.View({
            model: this.model
        });

        Backbone.Validation.bind(this.view, {
            valid: this.spy(),
            invalid: this.spy()
        });
    },

    "'function'": {
        setUp: function() {
            var that = this;
            this.model.validation = {
                name: function(val){
                    that.ctx = this;
                    if(name !== 'backbone') {
                        return 'Error';
                    }
                }
            };
        },

        "is invalid when method returns truthy value": function() {
            refute(this.model.set({name: ''}));
        },

        "is valid when method returns falsy value": function() {
            refute(this.model.set({name: 'backbone'}));
        },

        "context is the model": function() {
            this.model.set({name: ''});
            assert.same(this.ctx, this.model);
        }
    },

    "'named function'": {
        setUp: function() {
            var that = this;
            this.model.validation = {
                name: 'validateName'
            };

            this.model.validateName = function(val){
                that.ctx = this;
                if(name !== 'backbone') {
                    return 'Error';
                }
            };
        },

        "is invalid when method returns truthy value": function() {
            refute(this.model.set({name: ''}));
        },

        "is valid when method returns falsy value": function() {
            refute(this.model.set({name: 'backbone'}));
        },

        "context is the model": function() {
            this.model.set({name: ''});
            assert.same(this.ctx, this.model);
        }
    },

    "'required'": {
        setUp: function() {
            this.model.validation = {
                name: {
                    required: true
                },
                agree: {
                    required: true
                }
            };
        },

        "empty string is invalid": function() {
            refute(this.model.set({
                name: ''
            }));
        },

        "non-empty string is valid": function() {
            assert(this.model.set({
                name: 'a'
            }));
        },

        "blank string is invalid": function() {
            refute(this.model.set({
                name: '  '
            }));
        },

        "null is invalid": function() {
            refute(this.model.set({
                name: null
            }));
        },

        "undefined is invalid": function() {
            refute(this.model.set({
                name: undefined
            }));
        },

        "false boolean is invalid": function() {
            refute(this.model.set({
                agree: false
            }));
        },

        "true boolean is valid": function() {
            assert(this.model.set({
                agree: true
            }));
        }
    },

    "'min'": {
        setUp: function() {
            this.model.validation = {
                age: {
                    min: 1
                }
            };
        },

        "undefined is invalid": function() {
            refute(this.model.set({
                age: undefined
            }));
        },

        "value lower than min is invalid": function() {
            refute(this.model.set({
                age: 0
            }));
        },

        "non numeric value is invalid": function() {
            refute(this.model.set({
                age: '10error'
            }));
        },

        "value equal to min is valid": function() {
            assert(this.model.set({
                age: 1
            }));
        },

        "numeric string value equal to min is valid": function() {
            assert(this.model.set({
                age: '1'
            }));
        }
    },

    "'max'": {
        setUp: function() {
            this.model.validation = {
                age: {
                    max: 10
                }
            };
        },

        "undefined is invalid": function() {
            refute(this.model.set({
                age: undefined
            }));
        },

        "value higher than max is invalid": function() {
            refute(this.model.set({
                age: 11
            }));
        },

        "non numeric value is invalid": function() {
            refute(this.model.set({
                age: '10error'
            }));
        },

        "value equal to max is valid": function() {
            assert(this.model.set({
                age: 10
            }));
        },

        "numeric string value equal to max is valid": function() {
            assert(this.model.set({
                age: '10'
            }));
        }
    },

    "'min' and 'max'": {
        setUp: function() {
            this.model.validation = {
                age: {
                    min: 1,
                    max: 10
                }
            };
        },

        "value lower than min is invalid": function() {
            refute(this.model.set({
                age: 0
            }));
        },

        "value equal to min is valid": function() {
            assert(this.model.set({
                age: 1
            }));
        },

        "value higher than max is invalid": function() {
            refute(this.model.set({
                age: 11
            }));
        },

        "value equal to max is valid": function() {
            assert(this.model.set({
                age: 10
            }));
        }
    },

    "'length'": {
        setUp: function() {
            this.model.validation = {
                postalCode: {
                    length: 2
                }
            };
        },

        "undefined is invalid": function() {
            refute(this.model.set({
                postalCode: undefined
            }));
        },

        "value with length shorter than length is invalid": function() {
            refute(this.model.set({
                postalCode: 'a'
            }));
        },

        "value with length longer than length is invalid": function() {
            refute(this.model.set({
                postalCode: 'aaa'
            }));
        },

        "value with length equal to length is valid": function() {
            assert(this.model.set({
                postalCode: 'aa'
            }));
        }
    },

    "'minLength'": {
        setUp: function() {
            this.model.validation = {
                name: {
                    minLength: 2
                }
            };
        },

        "undefined is invalid": function() {
            refute(this.model.set({
                name: undefined
            }));
        },

        "value with length shorter than minLenght is invalid": function() {
            refute(this.model.set({
                name: 'a'
            }));
        },

        "value with length equal to minLength is valid": function() {
            assert(this.model.set({
                name: 'aa'
            }));
        }
    },

    "'maxLength'": {
        setUp: function() {
            this.model.validation = {
                name: {
                    maxLength: 2
                }
            };
        },

        "value with length longer than maxLenght is invalid": function() {
            refute(this.model.set({
                name: 'aaa'
            }));
        },

        "value with length equal to maxLength is valid": function() {
            assert(this.model.set({
                name: 'aa'
            }));
        }
    },

    "'pattern'": {
        setUp: function() {
            this.model.validation = {
                name: {
                    pattern: /^test/
                }
            };
        },

        "value not matching pattern is invalid": function() {
            refute(this.model.set({
                name: 'aaa'
            }));
        },

        "value matching pattern is valid": function() {
            assert(this.model.set({
                name: 'test'
            }));
        }
    },

    "'email pattern'": {
        setUp: function() {
            this.model.validation = {
                email: {
                    pattern: 'email'
                }
            };
        },

        "an invalid email is invalid": function() {
            refute(this.model.set({
                email: 'aaa'
            }));
        },

        "a valid email is valid": function() {
            assert(this.model.set({
                email: 'a@example.com'
            }));
        }
    },

    "'url pattern'": {
        setUp: function() {
            this.model.validation = {
                url: {
                    pattern: 'url'
                }
            };
        },

        "an invalid url is invalid": function() {
            refute(this.model.set({
                url: 'aaa'
            }));
        },

        "a valid url is valid": function() {
            assert(this.model.set({
                url: 'http://www.example.com?something=true&'
            }));
        }
    },

    "'number pattern'": {
        setUp: function() {
            this.model.validation = {
                age: {
                    pattern: 'number'
                }
            };
        },

        "non numeric value is invalid": function() {
            refute(this.model.set({
                age: '1a'
            }));
        },

        "numeric value with one digit is valid": function() {
            assert(this.model.set({
                age: 1
            }));
        },

        "negative numeric value with one digit is valid": function() {
            assert(this.model.set({
                age: -1
            }));
        },

        "numeric value with several digits is valid": function() {
            assert(this.model.set({
                age: 1234
            }));
        },

        "numeric string value is valid": function() {
            assert(this.model.set({
                age: "1234"
            }));
        },

        "negative numeric string value is valid": function() {
            assert(this.model.set({
                age: "-1234"
            }));
        }
    }
});
<|endoftext|>