<commit_before>describe('event', function() {
  it("don't break existing event hash", function() {
    var spy = this.spy();

    var view = new Thorax.View({
      key: 'value',
      events: {
        test1: 'test1',
        test2: spy
      },
      test1: spy
    });
    view.trigger('test1');
    view.trigger('test2');

    view = new Thorax.View({
      events: function() {
        return {
          test3: 'test3'
        };
      },
      key: 'value',
      test3: spy
    });
    view.trigger('test3');
    expect(spy.callCount).to.equal(3);
  });

  //ensure view.on('viewEventOne viewEventTwo') still works
  it("Inheritable events", function() {
    var Parent = Thorax.View.extend({}),
        aCount = 0,
        bCount = 0;
    Parent.on({
      a: function() {
        ++aCount;
      }
    });
    var Child = Parent.extend({});
    Child.on({
      b: function() {
        ++bCount;
      }
    });
    var parent = new Parent(),
        child = new Child();
    parent.trigger('a');
    parent.trigger('b');
    child.trigger('a');
    child.trigger('b');
    expect(aCount).to.equal(2);
    expect(bCount).to.equal(1);

    //ensure events are properly cloned
    Parent = Thorax.View.extend();
    Parent.on({
      a: 1
    });

    Child = Parent.extend({});
    Child.on({
      a: 2
    });

    var ChildTwo = Parent.extend({});
    expect(Parent._events[0][1]).to.equal(1, 'ensure events are not shared between children');
    expect(Parent._events.length).to.equal(1, 'ensure events are not shared between children');
    expect(Child._events[0][1]).to.equal(2, 'ensure events are not shared between children');
    expect(Child._events.length).to.equal(1, 'ensure events are not shared between children');
    expect(ChildTwo._events.length).to.equal(0, 'ensure events are not shared between children');
  });

  it("inherit prototype event hash", function() {
    var spy = this.spy();

    var View = Thorax.View.extend({
      key: 'value',
      events: {
        test1: 'test1',
        test2: spy
      },
      test1: spy
    });

    var view = new View();
    view.trigger('test1');
    view.trigger('test2');

    view = new View({
      events: function() {
        return {
          test3: 'test3'
        };
      },
      key: 'value',
      test3: spy
    });
    view.trigger('test1');
    view.trigger('test2');
    view.trigger('test3');

    View = View.extend({
      events: function() {
        return {
          test3: 'test3'
        };
      },
      key: 'value',
      test3: spy
    });
    view = new View();
    view.trigger('test1');
    view.trigger('test2');
    view.trigger('test3');
    expect(spy.callCount).to.equal(8);
  });

  it("multiple event registration", function() {
    var view = new Thorax.View(), a = 0, b = 0, c = 0, d = 0, e = 0;
    view.on({
      'a b': function() {
        ++a;
        ++b;
      },
      'c': [
        function() {
          ++c;
        },
        function() {
          ++c;
        }
      ],
      'd e': [
        function() {
          ++d;
        },
        function() {
          ++e;
        }
      ]
    });
    view.trigger('a');
    view.trigger('b c');
    view.trigger('d e');
    expect(a).to.equal(2);
    expect(b).to.equal(2);
    expect(c).to.equal(2);
    expect(d).to.equal(2);
    expect(e).to.equal(2);
  });

  it("auto dispose events", function() {
    var view = new Thorax.View({});
    var model = new Thorax.Model();
    var callCount = 0;
    view.on(model, 'test', function() {
      ++callCount;
    });
    model.trigger('test');
    expect(callCount).to.equal(1);
    view.freeze();
    model.trigger('test');
    expect(callCount).to.equal(1);
  });

  // TODO: simluated DOM events fail under Phantom + Zepto, but work in all
  // other scenarios, figure out why this test won't run
  if (!window.callPhantom || (window.callPhantom && typeof jQuery !== 'undefined')) {
    it("bindToView", function() {
      var childClickedCount = 0,
          parentClickedCount = 0;

      var Child = Thorax.View.extend({
        template: Thorax.templates.child,
        events: {
          'click div': function() {
            ++childClickedCount;
          }
        }
      });

      var Parent = Thorax.View.extend({
        template: Thorax.templates.parent,
        events: {
          'click div': function() {
            ++parentClickedCount;
          }
        },
        initialize: function() {
          this.child = new Child({
            value: 'a'
          });
        }
      });

      var parent = new Parent();
      $('body').append(parent.el);
      parent.render();
      $(parent.$('div')[0]).trigger('click');
      expect(parentClickedCount).to.equal(1);
      expect(childClickedCount).to.equal(0);
      parent.child.$('div').trigger('click');
      expect(parentClickedCount).to.equal(1);
      expect(childClickedCount).to.equal(1);
      parent.$el.remove();
    });
  }
});
<commit_msg>Add event map test<commit_after>describe('event', function() {
  it("don't break existing event hash", function() {
    var spy = this.spy();

    var view = new Thorax.View({
      key: 'value',
      events: {
        test1: 'test1',
        test2: spy
      },
      test1: spy
    });
    view.trigger('test1');
    view.trigger('test2');

    view = new Thorax.View({
      events: function() {
        return {
          test3: 'test3'
        };
      },
      key: 'value',
      test3: spy
    });
    view.trigger('test3');
    expect(spy.callCount).to.equal(3);
  });

  //ensure view.on('viewEventOne viewEventTwo') still works
  it("Inheritable events", function() {
    var Parent = Thorax.View.extend({}),
        aCount = 0,
        bCount = 0;
    Parent.on({
      a: function() {
        ++aCount;
      }
    });
    var Child = Parent.extend({});
    Child.on({
      b: function() {
        ++bCount;
      }
    });
    var parent = new Parent(),
        child = new Child();
    parent.trigger('a');
    parent.trigger('b');
    child.trigger('a');
    child.trigger('b');
    expect(aCount).to.equal(2);
    expect(bCount).to.equal(1);

    //ensure events are properly cloned
    Parent = Thorax.View.extend();
    Parent.on({
      a: 1
    });

    Child = Parent.extend({});
    Child.on({
      a: 2
    });

    var ChildTwo = Parent.extend({});
    expect(Parent._events[0][1]).to.equal(1, 'ensure events are not shared between children');
    expect(Parent._events.length).to.equal(1, 'ensure events are not shared between children');
    expect(Child._events[0][1]).to.equal(2, 'ensure events are not shared between children');
    expect(Child._events.length).to.equal(1, 'ensure events are not shared between children');
    expect(ChildTwo._events.length).to.equal(0, 'ensure events are not shared between children');
  });

  it("inherit prototype event hash", function() {
    var spy = this.spy();

    var View = Thorax.View.extend({
      key: 'value',
      events: {
        test1: 'test1',
        test2: spy
      },
      test1: spy
    });

    var view = new View();
    view.trigger('test1');
    view.trigger('test2');

    view = new View({
      events: function() {
        return {
          test3: 'test3'
        };
      },
      key: 'value',
      test3: spy
    });
    view.trigger('test1');
    view.trigger('test2');
    view.trigger('test3');

    View = View.extend({
      events: function() {
        return {
          test3: 'test3'
        };
      },
      key: 'value',
      test3: spy
    });
    view = new View();
    view.trigger('test1');
    view.trigger('test2');
    view.trigger('test3');
    expect(spy.callCount).to.equal(8);
  });

  it("event map", function() {
    var spy = this.spy(),
        view = new Thorax.View();
    view.on({test: spy});
    view.trigger('test');
    expect(spy.callCount).to.equal(1);
  });

  it("multiple event registration", function() {
    var view = new Thorax.View(), a = 0, b = 0, c = 0, d = 0, e = 0;
    view.on({
      'a b': function() {
        ++a;
        ++b;
      },
      'c': [
        function() {
          ++c;
        },
        function() {
          ++c;
        }
      ],
      'd e': [
        function() {
          ++d;
        },
        function() {
          ++e;
        }
      ]
    });
    view.trigger('a');
    view.trigger('b c');
    view.trigger('d e');
    expect(a).to.equal(2);
    expect(b).to.equal(2);
    expect(c).to.equal(2);
    expect(d).to.equal(2);
    expect(e).to.equal(2);
  });

  it("auto dispose events", function() {
    var view = new Thorax.View({});
    var model = new Thorax.Model();
    var callCount = 0;
    view.on(model, 'test', function() {
      ++callCount;
    });
    model.trigger('test');
    expect(callCount).to.equal(1);
    view.freeze();
    model.trigger('test');
    expect(callCount).to.equal(1);
  });

  // TODO: simluated DOM events fail under Phantom + Zepto, but work in all
  // other scenarios, figure out why this test won't run
  if (!window.callPhantom || (window.callPhantom && typeof jQuery !== 'undefined')) {
    it("bindToView", function() {
      var childClickedCount = 0,
          parentClickedCount = 0;

      var Child = Thorax.View.extend({
        template: Thorax.templates.child,
        events: {
          'click div': function() {
            ++childClickedCount;
          }
        }
      });

      var Parent = Thorax.View.extend({
        template: Thorax.templates.parent,
        events: {
          'click div': function() {
            ++parentClickedCount;
          }
        },
        initialize: function() {
          this.child = new Child({
            value: 'a'
          });
        }
      });

      var parent = new Parent();
      $('body').append(parent.el);
      parent.render();
      $(parent.$('div')[0]).trigger('click');
      expect(parentClickedCount).to.equal(1);
      expect(childClickedCount).to.equal(0);
      parent.child.$('div').trigger('click');
      expect(parentClickedCount).to.equal(1);
      expect(childClickedCount).to.equal(1);
      parent.$el.remove();
    });
  }
});
<|endoftext|>


<commit_before>/*jslint node: true */
"use strict";

var Stopwatch = require('../lib/Stopwatch');
var defaultPrecision = 15;
var assert = require('assert');
var should = require('should');

describe('stopwatch', function () {
    this.timeout(5000);

    describe('constructor', function () {
        it('w/no params', function () {
            var stopwatch = new Stopwatch();
            should.exist(stopwatch);
        });

        it('w/name as first param', function () {
            var stopwatch = new Stopwatch('metric-name');
            stopwatch.name().should.equal('metric-name');
        });

        it('w/autostart as first param', function () {
            var stopwatch = new Stopwatch(true);
            should.exist(stopwatch.name());
            stopwatch.name().should.not.equal(true);
        });

        it('w/both name and autostart', function () {
            var stopwatch = new Stopwatch('metric-name', true);
            stopwatch.name().should.equal('metric-name');
        });

        it('autocreated names are not constant', function () {
            var stopwatch1 = new Stopwatch(true);
            var stopwatch2 = new Stopwatch(true);
            stopwatch1.name().should.not.equal(stopwatch2.name());
        });
    });

    it('start and read (100ms)', function (done) {
        var testtime = 100;

        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            var delta = stopwatch.read();
            verifyDelta(testtime, delta, defaultPrecision);
            done();
        }, testtime);
    });

    it('start and read (10ms)', function (done) {
        var testtime = 10;

        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            var delta = stopwatch.read();
            verifyDelta(testtime, delta, defaultPrecision);
            done();
        }, testtime);
    });

    it('autostart set to true automatically starts stopwatch', function (done) {
        var testtime = 10;

        var stopwatch = new Stopwatch(true);
        setTimeout(function () {
            var delta = stopwatch.read();
            verifyDelta(testtime, delta, defaultPrecision);
            done();
        }, testtime);
    });

    it('autostart set to false does NOT automatically start stopwatch', function (done) {
        var testtime = 10;

        var stopwatch = new Stopwatch(false);
        setTimeout(function () {
            stopwatch.read().should.be.NaN();
            done();
        }, testtime);
    });

    it('with two stopwatches, do independent reads of each', function (done) {
        var stopwatch1 = new Stopwatch();
        var stopwatch2 = new Stopwatch();

        stopwatch1.start();

        //start first stopwatch, then do a read .3s later
        var testtimeA = 300;
        setTimeout(function () {
            var delta1 = stopwatch1.read();
            verifyDelta(testtimeA, delta1, defaultPrecision);
        }, testtimeA);

        //start second stopwatch .1s second after the first, then do a read .5s later
        var testtimeB = 500;
        setTimeout(function () {
            stopwatch2.start();
            setTimeout(function () {
                var delta2 = stopwatch2.read();
                verifyDelta(testtimeB, delta2, defaultPrecision);
                done();
            }, testtimeB);
        }, 100);
    });

    it('start, stop, and read should return the time at stop', function (done) {
        var testtime = 100;

        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            stopwatch.stop();

            setTimeout(function () {
                var delta = stopwatch.read();
                verifyDelta(testtime, delta, defaultPrecision);
                done();
            }, 500);
        }, testtime);
    });

    it('performing read without start() or stop() returns NaN', function (done) {
        var stopwatch = new Stopwatch();
        assert.ok(isNaN(stopwatch.read()));
        done();
    });

    it('performing read without start() returns NaN', function (done) {
        var stopwatch = new Stopwatch();
        stopwatch.stop();
        assert.ok(isNaN(stopwatch.read()));
        done();
    });

    it('executing stop twice should return time at second stop', function (done) {
        //start(), wait .1s, stop(), wait .2s, stop(), wait .5s, read(), ensure delta = .3s
        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            stopwatch.stop();

            setTimeout(function () {
                verifyDelta(100 + 200, stopwatch.stop(), defaultPrecision);

                setTimeout(function () {
                    var delta = stopwatch.read();
                    verifyDelta(100 + 200, delta, defaultPrecision);
                    done();
                }, 500);
            }, 200);
        }, 100);
    });

    it('ensure that stop() returns time', function (done) {
        var testtime = 100;
        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            var delta = stopwatch.stop();
            verifyDelta(testtime, delta, defaultPrecision);
            done();
        }, testtime);
    });

    describe('toString()', function () {
        it('idle', function () {
            var stopwatch = new Stopwatch('sw');
            //[sw => state:init; value:NaN]
            stopwatch.toString().should.containEql('state:init');
            stopwatch.toString().should.containEql('value:');
        });
        it('started', function () {
            var stopwatch = new Stopwatch('sw', true);
            //[sw => state:running; value:0.01]
            stopwatch.toString().should.containEql('state:running');
            stopwatch.toString().should.containEql('value:0');
        });
        it('stopped', function () {
            var stopwatch = new Stopwatch('sw', true);
            stopwatch.stop();
            //[sw => state:stopped; value:0.01]
            stopwatch.toString().should.containEql('state:stopped');
            stopwatch.toString().should.containEql('value:0');
        });
    });

    // https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/time/StopWatch.html
    describe('java stopwatch compliance', function () {
        it('time should equal read on a running stopwatch', function () {
            //TODO: list time as alias of read
            var stopwatch = new Stopwatch('sw');
            stopwatch.start();

            var readTime = stopwatch.read();
            var time = stopwatch.time();

            verifyDelta(readTime, time, 10);
        });
        it('time should equal read on a stopped stopwatch', function (done) {
            //TODO: list time as alias of read
            var stopwatch = new Stopwatch('sw');
            stopwatch.start();
            setTimeout(function () {
                stopwatch.stop();
                stopwatch.read().should.be.equal(stopwatch.time());
                done();
            }, 10);

        });
        describe('reset', function () {
            it('reseting a not-started stopwatch should have no effect', function () {
                var stopwatch = new Stopwatch('sw');
                stopwatch.reset();
                stopwatch.state().should.be.equal("init");
            });
            it('reseting a started stopwatch should bring it back to init', function () {
                var stopwatch = new Stopwatch('sw');
                stopwatch.start();
                stopwatch.reset();
                should.not.exist(stopwatch.startTime);
                should.not.exist(stopwatch.stopTime);
                stopwatch.state().should.be.equal("init");
            });
            it('reseting a stopped stopwatch should bring it back to init', function () {
                var stopwatch = new Stopwatch('sw');
                stopwatch.start();
                stopwatch.stop();
                stopwatch.reset();
                should.not.exist(stopwatch.startTime);
                should.not.exist(stopwatch.stopTime);
                stopwatch.state().should.be.equal("init");
            });
        });
        describe('split', function () {
            it('start, split, then getSplit will return the split time', function () {
                var stopwatch = new Stopwatch('sw');
                stopwatch.start();

                setTimeout(function () {
                    stopwatch.split();
                    setTimeout(function () {
                        verifyDelta(100, stopwatch.time, 10);
                        verifyDelta(200, stopwatch.splitTime, 10);
                        done();
                    }, 200);
                }, 100);
            });
            it('split/unsplit/getSplitTime', function () {
                // Split the time.  This method sets the stop time of the watch to allow a time to be extracted. The start time is unaffected, enabling unsplit() to continue the timing from the original start point.
                // Remove a split.  This method clears the stop time. The start time is unaffected, enabling timing from the original start point to continue.
                // IllegalStateException - if the StopWatch is not running. (on split)
                // IllegalStateException - if the StopWatch has not yet been split. (on unsplit)
            });
            it('split/unsplit/getSplitTime', function () {
                // Split the time.  This method sets the stop time of the watch to allow a time to be extracted. The start time is unaffected, enabling unsplit() to continue the timing from the original start point.
                // Remove a split.  This method clears the stop time. The start time is unaffected, enabling timing from the original start point to continue.
                // IllegalStateException - if the StopWatch is not running. (on split)
                // IllegalStateException - if the StopWatch has not yet been split. (on unsplit)
            });
        });
        it.skip('suspend/resume', function () {
            // This method suspends the watch until it is resumed. The watch will not include time between the suspend and resume calls in the total time.
            // IllegalStateException - if the StopWatch is not currently running.
            // IllegalStateException - if the StopWatch has not been suspended.
        });
        it.skip('start while already running', function () {
            // IllegalStateException - if the StopWatch is already running.
        });
        it.skip('stop while not running', function () {
            // IllegalStateException - if the StopWatch is not running.
        });
    });
});

//TODO:
//replace with: statman.TestHelper.assertCloseEnough(testtime, delta, defaultPrecision);
function verifyDelta(expected, actual, acceptedVariance) {
    var lowerThreshold = expected - acceptedVariance;
    var upperThreshold = expected + acceptedVariance;
    var message = "Expected " + expected + " ± " + acceptedVariance + ", was " + actual + ".";
    assert.ok((actual >= lowerThreshold) && (actual <= upperThreshold), message);
}<commit_msg>clean up test<commit_after>/*jslint node: true */
"use strict";

var Stopwatch = require('../lib/Stopwatch');
var defaultPrecision = 15;
var assert = require('assert');
var should = require('should');

describe('stopwatch', function () {
    this.timeout(5000);

    describe('constructor', function () {
        it('w/no params', function () {
            var stopwatch = new Stopwatch();
            should.exist(stopwatch);
        });

        it('w/name as first param', function () {
            var stopwatch = new Stopwatch('metric-name');
            stopwatch.name().should.equal('metric-name');
        });

        it('w/autostart as first param', function () {
            var stopwatch = new Stopwatch(true);
            should.exist(stopwatch.name());
            stopwatch.name().should.not.equal(true);
        });

        it('w/both name and autostart', function () {
            var stopwatch = new Stopwatch('metric-name', true);
            stopwatch.name().should.equal('metric-name');
        });

        it('autocreated names are not constant', function () {
            var stopwatch1 = new Stopwatch(true);
            var stopwatch2 = new Stopwatch(true);
            stopwatch1.name().should.not.equal(stopwatch2.name());
        });
    });

    it('start and read (100ms)', function (done) {
        var testtime = 100;

        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            var delta = stopwatch.read();
            verifyDelta(testtime, delta, defaultPrecision);
            done();
        }, testtime);
    });

    it('start and read (10ms)', function (done) {
        var testtime = 10;

        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            var delta = stopwatch.read();
            verifyDelta(testtime, delta, defaultPrecision);
            done();
        }, testtime);
    });

    it('autostart set to true automatically starts stopwatch', function (done) {
        var testtime = 10;

        var stopwatch = new Stopwatch(true);
        setTimeout(function () {
            var delta = stopwatch.read();
            verifyDelta(testtime, delta, defaultPrecision);
            done();
        }, testtime);
    });

    it('autostart set to false does NOT automatically start stopwatch', function (done) {
        var testtime = 10;

        var stopwatch = new Stopwatch(false);
        setTimeout(function () {
            stopwatch.read().should.be.NaN();
            done();
        }, testtime);
    });

    it('with two stopwatches, do independent reads of each', function (done) {
        var stopwatch1 = new Stopwatch();
        var stopwatch2 = new Stopwatch();

        stopwatch1.start();

        //start first stopwatch, then do a read .3s later
        var testtimeA = 300;
        setTimeout(function () {
            var delta1 = stopwatch1.read();
            verifyDelta(testtimeA, delta1, defaultPrecision);
        }, testtimeA);

        //start second stopwatch .1s second after the first, then do a read .5s later
        var testtimeB = 500;
        setTimeout(function () {
            stopwatch2.start();
            setTimeout(function () {
                var delta2 = stopwatch2.read();
                verifyDelta(testtimeB, delta2, defaultPrecision);
                done();
            }, testtimeB);
        }, 100);
    });

    it('start, stop, and read should return the time at stop', function (done) {
        var testtime = 100;

        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            stopwatch.stop();

            setTimeout(function () {
                var delta = stopwatch.read();
                verifyDelta(testtime, delta, defaultPrecision);
                done();
            }, 500);
        }, testtime);
    });

    it('performing read without start() or stop() returns NaN', function (done) {
        var stopwatch = new Stopwatch();
        assert.ok(isNaN(stopwatch.read()));
        done();
    });

    it('performing read without start() returns NaN', function (done) {
        var stopwatch = new Stopwatch();
        stopwatch.stop();
        assert.ok(isNaN(stopwatch.read()));
        done();
    });

    it('executing stop twice should return time at second stop', function (done) {
        //start(), wait .1s, stop(), wait .2s, stop(), wait .5s, read(), ensure delta = .3s
        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            stopwatch.stop();

            setTimeout(function () {
                verifyDelta(100 + 200, stopwatch.stop(), defaultPrecision);

                setTimeout(function () {
                    var delta = stopwatch.read();
                    verifyDelta(100 + 200, delta, defaultPrecision);
                    done();
                }, 500);
            }, 200);
        }, 100);
    });

    it('ensure that stop() returns time', function (done) {
        var testtime = 100;
        var stopwatch = new Stopwatch();
        stopwatch.start();
        setTimeout(function () {
            var delta = stopwatch.stop();
            verifyDelta(testtime, delta, defaultPrecision);
            done();
        }, testtime);
    });

    describe('toString()', function () {
        it('idle', function () {
            var stopwatch = new Stopwatch('sw');
            //[sw => state:init; value:NaN]
            stopwatch.toString().should.containEql('state:init');
            stopwatch.toString().should.containEql('value:');
        });
        it('started', function () {
            var stopwatch = new Stopwatch('sw', true);
            //[sw => state:running; value:0.01]
            stopwatch.toString().should.containEql('state:running');
            stopwatch.toString().should.containEql('value:0');
        });
        it('stopped', function () {
            var stopwatch = new Stopwatch('sw', true);
            stopwatch.stop();
            //[sw => state:stopped; value:0.01]
            stopwatch.toString().should.containEql('state:stopped');
            stopwatch.toString().should.containEql('value:0');
        });
    });

    // https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/time/StopWatch.html
    describe('java stopwatch compliance', function () {
        it('time should equal read on a running stopwatch', function () {
            //TODO: list time as alias of read
            var stopwatch = new Stopwatch('sw');
            stopwatch.start();

            var readTime = stopwatch.read();
            var time = stopwatch.time();

            verifyDelta(readTime, time, 10);
        });
        it('time should equal read on a stopped stopwatch', function (done) {
            //TODO: list time as alias of read
            var stopwatch = new Stopwatch('sw');
            stopwatch.start();
            setTimeout(function () {
                stopwatch.stop();
                stopwatch.read().should.be.equal(stopwatch.time());
                done();
            }, 10);

        });
        describe('reset', function () {
            it('reseting a not-started stopwatch should have no effect', function () {
                var stopwatch = new Stopwatch('sw');
                stopwatch.reset();
                stopwatch.state().should.be.equal("init");
            });
            it('reseting a started stopwatch should bring it back to init', function () {
                var stopwatch = new Stopwatch('sw');
                stopwatch.start();
                stopwatch.reset();
                should.not.exist(stopwatch.startTime);
                should.not.exist(stopwatch.stopTime);
                stopwatch.state().should.be.equal("init");
            });
            it('reseting a stopped stopwatch should bring it back to init', function () {
                var stopwatch = new Stopwatch('sw');
                stopwatch.start();
                stopwatch.stop();
                stopwatch.reset();
                should.not.exist(stopwatch.startTime);
                should.not.exist(stopwatch.stopTime);
                stopwatch.state().should.be.equal("init");
            });
        });
        describe('split', function () {
            it('start, split, then getSplit will return the split time', function (done) {
                var stopwatch = new Stopwatch('sw');
                stopwatch.start();

                setTimeout(function () {
                    stopwatch.split();
                    setTimeout(function () {
                        verifyDelta(100, stopwatch.time(), 10);
                        verifyDelta(100, stopwatch.splitTime(), 10);
                        done();
                    }, 200);
                }, 100);
            });
            it('split/unsplit/getSplitTime', function () {
                // Split the time.  This method sets the stop time of the watch to allow a time to be extracted. The start time is unaffected, enabling unsplit() to continue the timing from the original start point.
                // Remove a split.  This method clears the stop time. The start time is unaffected, enabling timing from the original start point to continue.
                // IllegalStateException - if the StopWatch is not running. (on split)
                // IllegalStateException - if the StopWatch has not yet been split. (on unsplit)
            });
            it('split/unsplit/getSplitTime', function () {
                // Split the time.  This method sets the stop time of the watch to allow a time to be extracted. The start time is unaffected, enabling unsplit() to continue the timing from the original start point.
                // Remove a split.  This method clears the stop time. The start time is unaffected, enabling timing from the original start point to continue.
                // IllegalStateException - if the StopWatch is not running. (on split)
                // IllegalStateException - if the StopWatch has not yet been split. (on unsplit)
            });
        });
        it.skip('suspend/resume', function () {
            // This method suspends the watch until it is resumed. The watch will not include time between the suspend and resume calls in the total time.
            // IllegalStateException - if the StopWatch is not currently running.
            // IllegalStateException - if the StopWatch has not been suspended.
        });
        it.skip('start while already running', function () {
            // IllegalStateException - if the StopWatch is already running.
        });
        it.skip('stop while not running', function () {
            // IllegalStateException - if the StopWatch is not running.
        });
    });
});

//TODO:
//replace with: statman.TestHelper.assertCloseEnough(testtime, delta, defaultPrecision);
function verifyDelta(expected, actual, acceptedVariance) {
    var lowerThreshold = expected - acceptedVariance;
    var upperThreshold = expected + acceptedVariance;
    var message = "Expected " + expected + " ± " + acceptedVariance + ", was " + actual + ".";
    assert.ok((actual >= lowerThreshold) && (actual <= upperThreshold), message);
}<|endoftext|>


<commit_before>var syslogParser = require('../lib/glossy/parse.js'),
          assert = require('assert');

assert.ok(syslogParser, 'parser loaded');
var singleStructure = '[exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"]';
assert.deepEqual(syslogParser.parseStructure(singleStructure), {
    'exampleSDID@32473': {
        iut: '3',
        eventSource: 'Application',
        eventID: '1011'
    }
});

<commit_msg>Adding unit test for multiple structured data.<commit_after>var syslogParser = require('../lib/glossy/parse.js'),
          assert = require('assert');

assert.ok(syslogParser, 'parser loaded');
var singleStructure = '[exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"]';
assert.deepEqual(syslogParser.parseStructure(singleStructure), {
    'exampleSDID@32473': {
        iut: '3',
        eventSource: 'Application',
        eventID: '1011'
    }
});

var doubleStructure = '[exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"][examplePriority@32473 class="high"] ';
assert.deepEqual(syslogParser.parseStructure(doubleStructure), {
    'exampleSDID@32473': {
            iut: '3',
        eventID: '1011',
        eventSource: 'Application'
     },
     'examplePriority@32473': {
         'class': 'high'
     }
});
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert');
var $$ = require('../../lib/js-yaml/common');

var _common = module.exports = {};
$$.extend(_common, $$);

function isNothing(subject) {
  return (undefined === subject) || (null === subject);
}

function toArray(sequence) {
  if (Array.isArray(sequence)) {
    return sequence;
  } else if (undefined === sequence || null === sequence) {
    return [];
  } else {
    return [ sequence ];
  }
}

function makeClassConstructor(Class, params) {
  var mapKeys      = params.map      || {},
      requiredKeys = params.required || [],
      optionalKeys = params.optional || [];

  return function fromYAMLNode(node) {
    var mapping = this.constructMapping(node, true);

    assert.equal(typeof mapping, 'object');

    $$.each(mapKeys, function (newKey, oldKey) {
      if (Object.prototype.hasOwnProperty.call(mapping, oldKey)) {
        mapping[newKey] = mapping[oldKey];
        delete mapping[oldKey];
      }
    });

    requiredKeys.forEach(function (key) {
      assert(Object.prototype.hasOwnProperty.call(mapping, key));
    });

    $$.each(mapping, function (value, key) {
      var hasAsRequired = (0 <= requiredKeys.indexOf(key)),
          hasAsOptional = (0 <= optionalKeys.indexOf(key));

      assert(hasAsRequired || hasAsOptional);
    });

    return new Class(mapping);
  };
}

_common.isNothing = isNothing;
_common.toArray = toArray;
_common.makeClassConstructor = makeClassConstructor;
<commit_msg>Use `isNothing` in the tests code<commit_after>'use strict';

var assert = require('assert');
var $$ = require('../../lib/js-yaml/common');

var _common = module.exports = {};
$$.extend(_common, $$);

function isNothing(subject) {
  return (undefined === subject) || (null === subject);
}

function toArray(sequence) {
  if (Array.isArray(sequence)) {
    return sequence;
  } else if (isNothing(sequence)) {
    return [];
  } else {
    return [ sequence ];
  }
}

function makeClassConstructor(Class, params) {
  var mapKeys      = params.map      || {},
      requiredKeys = params.required || [],
      optionalKeys = params.optional || [];

  return function fromYAMLNode(node) {
    var mapping = this.constructMapping(node, true);

    assert.equal(typeof mapping, 'object');

    $$.each(mapKeys, function (newKey, oldKey) {
      if (Object.prototype.hasOwnProperty.call(mapping, oldKey)) {
        mapping[newKey] = mapping[oldKey];
        delete mapping[oldKey];
      }
    });

    requiredKeys.forEach(function (key) {
      assert(Object.prototype.hasOwnProperty.call(mapping, key));
    });

    $$.each(mapping, function (value, key) {
      var hasAsRequired = (0 <= requiredKeys.indexOf(key)),
          hasAsOptional = (0 <= optionalKeys.indexOf(key));

      assert(hasAsRequired || hasAsOptional);
    });

    return new Class(mapping);
  };
}

_common.isNothing = isNothing;
_common.toArray = toArray;
_common.makeClassConstructor = makeClassConstructor;
<|endoftext|>


<commit_before><commit_msg>Installateur Greasemonkey<commit_after><|endoftext|>


<commit_before>var _ = require("underscore");

Parse.Cloud.define("searchAll", function(request, response) {
	var Scope = {
		All: 0,
		Users: 1,
		Posts: 2,
		Albums: 3,
		Groups: 4
	};
	var filter = request.params.filter;
	var probe = request.params.probe;
	var user = request.user;
	var searchResults = [];
	var promises = [];
	function getQuery(className) {
		return new Parse.Query(Parse.Object.extend(className));
	}
	if (filter == Scope.All || filter == Scope.Posts) {
		// search posts and photos from roll
		function queryPostField(field) {
			var query = getQuery("Post");
			query.equalTo("createdBy", user).matches("title", "(?i)" + probe).matches("title", "(?i)" + probe);
			return query.find();
		}
		var tagQuery = getQuery("Tag");
		tagQuery.matches("name", "(?i)" + probe)
		//promises.push(tagQuery);		//TODO: This isn't right. Must find posts that contain these tags
		promises.push(queryPostField("title"));
		promises.push(queryPostField("notes"));
	}
	if (filter == Scope.All || filter == Scope.Albums || filter == Scope.Groups) {
		// search groups and albums
		function queryAlbumGroupField(type, field) {
			var query = getQuery("Album");
			query.equalTo("type", type);
			if (type == "album")
				query.equalTo("createdBy", user);
			query.matches(field,  "(?i)" + probe);
			return query.find()
		}
		if (filter != Scope.Groups) {
			promises.push(queryAlbumGroupField("album", "title"));
			promises.push(queryAlbumGroupField("album", "notes"));
		}
		if (filter != Scope.Albums) {
			promises.push(queryAlbumGroupField("group", "title"));
			promises.push(queryAlbumGroupField("group", "notes"));
		}
	}
	if (filter == Scope.All || filter == Scope.Users) {
		// search users
		function queryUserField(field) {
			var query = getQuery("_User");
			query.matches(field,  "(?i)" + probe);
			return query.find();
		}
		promises.push(queryUserField("username"));
		promises.push(queryUserField("email"));
		promises.push(queryUserField("name"));
	}
	Parse.Promise.when(promises).then(function(results) {
		var finalResults = [];
		try {
			_.each(results, function accum(r) { finalResults = finalResults.concat(r) });
			console.log(JSON.stringify(finalResults[0]));
			finalResults = _.sortBy(_.uniq(finalResults, function (a) { console.log(typeof(a)); return a["objectId"] }), function(a) { return Date.parse(a["createdAt"]) }).reverse();
		}
		catch (e) {
			console.log(e);
		}
		response.success(finalResults);
	});
});
<commit_msg>Search in back end<commit_after>var _ = require("underscore");

Parse.Cloud.define("searchAll", function(request, response) {
	var Scope = {
		All: 0,
		Users: 1,
		Posts: 2,
		Albums: 3,
		Groups: 4
	};
	var filter = request.params.filter;
	var probe = request.params.probe;
	var user = request.user;
	var searchResults = [];
	var promises = [];
	function getQuery(className) {
		return new Parse.Query(Parse.Object.extend(className));
	}
	if (filter == Scope.All || filter == Scope.Posts) {
		// search posts and photos from roll
		function queryPostField(field) {
			var query = getQuery("Post");
			query.equalTo("createdBy", user).matches("title", "(?i)" + probe).matches("title", "(?i)" + probe);
			return query.find();
		}
		var tagQuery = getQuery("Tag");
		tagQuery.matches("name", "(?i)" + probe)
		//promises.push(tagQuery);		//TODO: This isn't right. Must find posts that contain these tags
		promises.push(queryPostField("title"));
		promises.push(queryPostField("notes"));
	}
	if (filter == Scope.All || filter == Scope.Albums || filter == Scope.Groups) {
		// search groups and albums
		function queryAlbumGroupField(type, field) {
			var query = getQuery("Album");
			query.equalTo("type", type);
			if (type == "album")
				query.equalTo("createdBy", user);
			query.matches(field,  "(?i)" + probe);
			return query.find()
		}
		if (filter != Scope.Groups) {
			promises.push(queryAlbumGroupField("album", "title"));
			promises.push(queryAlbumGroupField("album", "notes"));
		}
		if (filter != Scope.Albums) {
			promises.push(queryAlbumGroupField("group", "title"));
			promises.push(queryAlbumGroupField("group", "notes"));
		}
	}
	if (filter == Scope.All || filter == Scope.Users) {
		// search users
		function queryUserField(field) {
			var query = getQuery("_User");
			query.matches(field,  "(?i)" + probe);
			return query.find();
		}
		promises.push(queryUserField("username"));
		promises.push(queryUserField("email"));
		promises.push(queryUserField("name"));
	}
	Parse.Promise.when(promises).then(function(results) {
		var finalResults = [];
		try {
			_.each(results, function accum(r) { finalResults = finalResults.concat(r) });
			console.log(JSON.stringify(finalResults[0]));
			finalResults = _.sortBy(_.uniq(finalResults, function (a) { console.log(typeof(a.id)); return a["objectId"] }), function(a) { return Date.parse(a["createdAt"]) }).reverse();
		}
		catch (e) {
			console.log(e);
		}
		response.success(finalResults);
	});
});
<|endoftext|>


<commit_before>module('views', {
  setup : function () {
    this.name = 'test_suite_db';
  }
});

asyncTest("Create a pouch", function() {

  var values = [];

  // special values sort before all other types
  values.push(null);
  values.push(false);
  values.push(true);

  // then numbers
  values.push(1);
  values.push(2);
  values.push(3.0);
  values.push(4);

  // then text, case sensitive
  values.push("a");
  //values.push("A");
  values.push("aa");
  values.push("b");
  //values.push("B");
  values.push("ba");
  values.push("bb");

  // then arrays. compared element by element until different.
  // Longer arrays sort after their prefixes
  values.push(["a"]);
  values.push(["b"]);
  values.push(["b","c"]);
  values.push(["b","c", "a"]);
  values.push(["b","d"]);
  values.push(["b","d", "e"]);

  // then object, compares each key value in the list until different.
  // larger objects sort after their subset objects.
  values.push({a:1});
  values.push({a:2});
  values.push({b:1});
  values.push({b:2});
  values.push({b:2, a:1}); // Member order does matter for collation.
  // CouchDB preserves member order
  // but doesn't require that clients will.
  // (this test might fail if used with a js engine
  // that doesn't preserve order)
  values.push({b:2, c:2});

  initTestDB(this.name, function(err, db) {
    var docs = values.map(function(x, i) {
      return {_id: (i).toString(), foo: x};
    });
    db.bulkDocs({docs: docs}, {}, function() {
      var queryFun = function(doc) { emit(doc.foo, null); };
      db.query(queryFun, null, function(_, res) {
        res.rows.forEach(function(x, i) {
          ok(JSON.stringify(x.key) === JSON.stringify(values[i]), 'keys collate');
        });
        db.query(queryFun, null, {descending: true}, function(_, res) {
          res.rows.forEach(function(x, i) {
            ok(JSON.stringify(x.key) === JSON.stringify(values[values.length - 1 - i]),
               'keys collate descending')
          });
          start();
        });
      });
    });
  });

});

<commit_msg>Added comments and names for views tests<commit_after>module('views', {
  setup : function () {
    this.name = 'test_suite_db';
  }
});

asyncTest("Test basic view collation", function() {

  var values = [];

  // special values sort before all other types
  values.push(null);
  values.push(false);
  values.push(true);

  // then numbers
  values.push(1);
  values.push(2);
  values.push(3.0);
  values.push(4);

  // then text, case sensitive
  // currently chrome uses ascii ordering and so wont handle capitals properly
  values.push("a");
  //values.push("A");
  values.push("aa");
  values.push("b");
  //values.push("B");
  values.push("ba");
  values.push("bb");

  // then arrays. compared element by element until different.
  // Longer arrays sort after their prefixes
  values.push(["a"]);
  values.push(["b"]);
  values.push(["b","c"]);
  values.push(["b","c", "a"]);
  values.push(["b","d"]);
  values.push(["b","d", "e"]);

  // then object, compares each key value in the list until different.
  // larger objects sort after their subset objects.
  values.push({a:1});
  values.push({a:2});
  values.push({b:1});
  values.push({b:2});
  values.push({b:2, a:1}); // Member order does matter for collation.
  // CouchDB preserves member order
  // but doesn't require that clients will.
  // (this test might fail if used with a js engine
  // that doesn't preserve order)
  values.push({b:2, c:2});

  initTestDB(this.name, function(err, db) {
    var docs = values.map(function(x, i) {
      return {_id: (i).toString(), foo: x};
    });
    db.bulkDocs({docs: docs}, {}, function() {
      var queryFun = function(doc) { emit(doc.foo, null); };
      db.query(queryFun, null, function(_, res) {
        res.rows.forEach(function(x, i) {
          ok(JSON.stringify(x.key) === JSON.stringify(values[i]), 'keys collate');
        });
        db.query(queryFun, null, {descending: true}, function(_, res) {
          res.rows.forEach(function(x, i) {
            ok(JSON.stringify(x.key) === JSON.stringify(values[values.length - 1 - i]),
               'keys collate descending')
          });
          start();
        });
      });
    });
  });

});

<|endoftext|>


<commit_before>/*
 * jQuery.zipLookup v0.1
 *   - by Ari Asulin (ari.asulin at gmail.com)
 *   - New permanent url for zero-installation users: http://protricity.github.io/zip-lookup/zip-lookup.js
 *   - New Demo page: http://protricity.github.io/zip-lookup/
 *   - Re-wrote db gen script in node.js. Fixed 0XXXX bug. Fixed default city bug.
 *   - Removed jQuery dependency
 *   - Code/DB cleanup
 *   - Event driven js
 *   - jQuery plugin to dynamically fill in City/State Form Fields using an ajax Zipcode lookup
 *   - Apache License, Version 2.0
 */

(function() {
    var DEBUG = false;
    var GROUP_LENGTH = 2;

    var CLASS_ZIPCODE = 'zip-lookup-field-zipcode';
    var CLASS_CITY = 'zip-lookup-field-city';
    var CLASS_CITY_TITLE_CASE = 'zip-lookup-field-city-title-case';
    var CLASS_STATE = 'zip-lookup-field-state';
    var CLASS_STATE_SHORT = 'zip-lookup-field-state-short';
    var CLASS_MESSAGE = 'zip-lookup-message';

    var setValue = function(element, value) {
        if(element.nodeName.toLowerCase() === 'select') {
            var options = element.getElementsByTagName('option');
            for (var i = 0; i < options.length; i++) {
                if (options[i].value === value || options[i].innerHTML === value) {
                    element.selectedIndex = i;
                    return;
                }
            }
        }

        if(element.nodeName.toLowerCase() === 'input') {
            element.setAttribute('value', value);

        } else {
            element.setAttribute('data-value', value);
        }
    };

    var hasClass = function(element, className) {
        return new RegExp("(^|\\s)" + className + "(\\s|$)", 'i').test(element.className);
    };
    var addClass = function(element, className) {
        if(!hasClass(element, className))
            element.className += (element.className ? " " : "" ) + className;
    };
    var removeClass = function(element, className) {
        if(hasClass(element, className))
            element.className = element.className.replace(new RegExp("(^|\\s)" + className + "(\\s|$)", 'i'), '');
    };

    var fireEvent = function(element, eventName) {
        var event; // The custom event that will be created

        if (document.createEvent) {
            event = document.createEvent("HTMLEvents");
            event.initEvent(eventName, true, true);
        } else {
            event = document.createEventObject();
        }
        event.eventName = eventName;
        //event.target = element;

        if (document.createEvent) {
            element.dispatchEvent(event);
        } else {
            element.fireEvent("on" + eventName, event);
        }

        return event;
    };

    var traverseDOM = function (elm, callback) {
        if(elm === document)
            elm = document.body;

        for(var i=0; i<elm.children.length; i++) {
            var child = elm.children[i];
            if(callback)
                if(callback(child) === true)
                    return false;

            if(traverseDOM(child, callback) === false)
                return false;
        }
        return true;
    };

    var ascendDOM = function (elm, callback) {
        if(elm === document.body || elm === document)
            return false;
        var parent = elm.parentNode;
        if(callback)
            if(callback(parent) === true)
                return false;

        return ascendDOM(parent, callback);
    };

    var lookup = function(zipVal, country) {
        var THIS = this;
        this.country = country || 'us';

        var head = document.getElementsByTagName('head')[0];
        var libDirPath = 'zip-lookup/db';
        traverseDOM(head, function(elm) {
            if(elm.nodeName.toUpperCase() === 'SCRIPT') {
                if(elm.getAttribute('src') && elm.getAttribute('src').match(/zip-lookup(?:\.min)?\.js$/i)) {
                    libDirPath = elm.getAttribute('src').replace(/zip-lookup(?:\.min)?\.js$/i, 'db');
                    if(DEBUG)
                        console.log("Library path set: " + libDirPath);
                    head = elm.parentNode;
                    return true;
                }
            }
        });

        var onSuccess = function(cityName, stateName, stateShortName) {};
        this.onSuccess = function(callback) { onSuccess = callback; return THIS; };

        var onError = function(throwError) {};
        this.onError = function(callback) { onError = callback; return THIS; };

        //if(!(zipVal = parseInt(zipVal, 10)))                  // If not a valid zip, error
        //    throw new Error("Invalid zip code: "+ zipVal);

        var zipGroup = zipVal.substring(0, GROUP_LENGTH);       // Determine the zip group
        var zipSet = zipVal.substring(GROUP_LENGTH);            // Determine the zip set

        var path = libDirPath + '/' + this.country + '/' + zipGroup + ".js";
        // Figure out the path to the zip group

        var script = document.createElement('script');
        script.src = path;
        script.type = 'text/javascript';
        script.async = true;
        head.appendChild(script);

        var errorTimeout = setTimeout(function() {
            onError("Search Timed out");
        }, 3000);

        window['__zl'] = function(data) {
            clearTimeout(errorTimeout);
            if(data === undefined || data[0] === undefined)         // If no data returned, the file was probably 404
                return onError("Zipcode Not Found in DB");          // Thus, zip is not in the db
            var cityID = data[0][zipSet];                           // Look for the City ID in the dataset.
            if(data[1][cityID] === undefined)                       // If no city,
                return onError("Zipcode City Not Found in DB");     // the zip is not in the db
            var cityData = data[1][cityID].split('|');              // Split the city data into name and State ID
            var cityName = cityData[0];
            if(!cityData[1]) cityData[1] = 0;                       // If no State ID was added, this means its 0
            var stateID = cityData[1];                              // Set State ID
            var stateData = data[2][stateID].split('|');            // Split State name and abbreviation
            var stateName = stateData[1];                           // State Name
            var stateShortName = stateData[0];                      // State abbreviation
            onSuccess(cityName, stateName, stateShortName);  // Execute onFound callback with data
        };

        return this;

    };

    var messageElements = document.getElementsByClassName(CLASS_MESSAGE);

    var eventHandler = function(e) {
        switch(e.type) {
            case 'blur':
            case 'change':
                if(hasClass(e.target, CLASS_ZIPCODE)) {
                    var val = e.target.value;
                    var lastVal = typeof e.target.lastVal === 'undefined' ? null : e.target.lastVal;
                    if(val && val !== lastVal) {
                        e.target.lastVal = val;
                        fireEvent(e.target, 'zip-lookup');
                    }
                }

                break;
            case 'zip-lookup':
                var zip = e.target ? e.target.value.trim() : null;

                var container = e.target.form || document;
                ascendDOM(e.target, function(elm) {
                    if(elm.nodeName.toLowerCase() === 'fieldset'
                        || elm === container) {
                        container = elm;
                        return true;
                    }
                });
                for(var i=0; i<messageElements.length; i++) (function(elm) {
                    elm.innerHTML = "Searching...";
                    removeClass(elm, 'error');
                })(messageElements[i]);

                lookup(zip)
                    .onError(function(error) {
                        e.target.setAttribute('zip-lookup-error-message', error);
                        fireEvent(e.target, 'zip-lookup-error');

                        for(var i=0; i<messageElements.length; i++) (function(elm) {
                            elm.innerHTML = error;
                            addClass(elm, 'error');
                        })(messageElements[i]);

                    }).onSuccess(function (cityName, stateName, stateShortName) {
                        traverseDOM(container, function(elm) {
                            if(hasClass(elm,  CLASS_CITY))
                                setValue(elm, cityName);
                            if(hasClass(elm,  CLASS_CITY_TITLE_CASE))
                                setValue(elm, titleCase(cityName));

                            if(hasClass(elm,  CLASS_STATE)){
                                setValue(elm, stateName);}
                            if(hasClass(elm,  CLASS_STATE_SHORT))
                                setValue(elm, stateShortName);

                            if(hasClass(elm,  CLASS_MESSAGE)){
                                elm.innerHTML = "Result found - " + cityName + ', ' + stateShortName;
                                removeClass(elm, 'error');
                            }
                        });

                        e.target.setAttribute('data-city-name', cityName);
                        e.target.setAttribute('data-state-name', stateName);
                        e.target.setAttribute('data-state-short-name', stateShortName);
                        fireEvent(e.target, 'zip-lookup-found');

                        for(var i=0; i<messageElements.length; i++) (function(elm) {
                            elm.innerHTML = "Found " + titleCase(cityName) + ", " + stateName;
                            removeClass(elm, 'error');
                        })(messageElements[i]);

                    });
                break;
            default:
                break;
        }
    };
    document.addEventListener('blur', eventHandler);
    document.addEventListener('change', eventHandler);
    document.addEventListener('zip-lookup', eventHandler);

    function titleCase(str) {
        return str.toLowerCase()
            .replace(/^([a-z\u00E0-\u00FC])|\s+([a-z\u00E0-\u00FC])/g, function($1) {
                return $1.toUpperCase();
            });
    }
})();
<commit_msg>version<commit_after>/*
 * jQuery.zipLookup v0.2
 *   - by Ari Asulin (ari.asulin at gmail.com)
 *   - New permanent url for zero-installation users: http://protricity.github.io/zip-lookup/zip-lookup.js
 *   - New Demo page: http://protricity.github.io/zip-lookup/
 *   - Re-wrote db gen script in node.js. Fixed 0XXXX bug. Fixed default city bug.
 *   - Removed jQuery dependency
 *   - Code/DB cleanup
 *   - Event driven js
 *   - jQuery plugin to dynamically fill in City/State Form Fields using an ajax Zipcode lookup
 *   - Apache License, Version 2.0
 */

(function() {
    var DEBUG = false;
    var GROUP_LENGTH = 2;

    var CLASS_ZIPCODE = 'zip-lookup-field-zipcode';
    var CLASS_CITY = 'zip-lookup-field-city';
    var CLASS_CITY_TITLE_CASE = 'zip-lookup-field-city-title-case';
    var CLASS_STATE = 'zip-lookup-field-state';
    var CLASS_STATE_SHORT = 'zip-lookup-field-state-short';
    var CLASS_MESSAGE = 'zip-lookup-message';

    var setValue = function(element, value) {
        if(element.nodeName.toLowerCase() === 'select') {
            var options = element.getElementsByTagName('option');
            for (var i = 0; i < options.length; i++) {
                if (options[i].value === value || options[i].innerHTML === value) {
                    element.selectedIndex = i;
                    return;
                }
            }
        }

        if(element.nodeName.toLowerCase() === 'input') {
            element.setAttribute('value', value);

        } else {
            element.setAttribute('data-value', value);
        }
    };

    var hasClass = function(element, className) {
        return new RegExp("(^|\\s)" + className + "(\\s|$)", 'i').test(element.className);
    };
    var addClass = function(element, className) {
        if(!hasClass(element, className))
            element.className += (element.className ? " " : "" ) + className;
    };
    var removeClass = function(element, className) {
        if(hasClass(element, className))
            element.className = element.className.replace(new RegExp("(^|\\s)" + className + "(\\s|$)", 'i'), '');
    };

    var fireEvent = function(element, eventName) {
        var event; // The custom event that will be created

        if (document.createEvent) {
            event = document.createEvent("HTMLEvents");
            event.initEvent(eventName, true, true);
        } else {
            event = document.createEventObject();
        }
        event.eventName = eventName;
        //event.target = element;

        if (document.createEvent) {
            element.dispatchEvent(event);
        } else {
            element.fireEvent("on" + eventName, event);
        }

        return event;
    };

    var traverseDOM = function (elm, callback) {
        if(elm === document)
            elm = document.body;

        for(var i=0; i<elm.children.length; i++) {
            var child = elm.children[i];
            if(callback)
                if(callback(child) === true)
                    return false;

            if(traverseDOM(child, callback) === false)
                return false;
        }
        return true;
    };

    var ascendDOM = function (elm, callback) {
        if(elm === document.body || elm === document)
            return false;
        var parent = elm.parentNode;
        if(callback)
            if(callback(parent) === true)
                return false;

        return ascendDOM(parent, callback);
    };

    var lookup = function(zipVal, country) {
        var THIS = this;
        this.country = country || 'us';

        var head = document.getElementsByTagName('head')[0];
        var libDirPath = 'zip-lookup/db';
        traverseDOM(head, function(elm) {
            if(elm.nodeName.toUpperCase() === 'SCRIPT') {
                if(elm.getAttribute('src') && elm.getAttribute('src').match(/zip-lookup(?:\.min)?\.js$/i)) {
                    libDirPath = elm.getAttribute('src').replace(/zip-lookup(?:\.min)?\.js$/i, 'db');
                    if(DEBUG)
                        console.log("Library path set: " + libDirPath);
                    head = elm.parentNode;
                    return true;
                }
            }
        });

        var onSuccess = function(cityName, stateName, stateShortName) {};
        this.onSuccess = function(callback) { onSuccess = callback; return THIS; };

        var onError = function(throwError) {};
        this.onError = function(callback) { onError = callback; return THIS; };

        //if(!(zipVal = parseInt(zipVal, 10)))                  // If not a valid zip, error
        //    throw new Error("Invalid zip code: "+ zipVal);

        var zipGroup = zipVal.substring(0, GROUP_LENGTH);       // Determine the zip group
        var zipSet = zipVal.substring(GROUP_LENGTH);            // Determine the zip set

        var path = libDirPath + '/' + this.country + '/' + zipGroup + ".js";
        // Figure out the path to the zip group

        var script = document.createElement('script');
        script.src = path;
        script.type = 'text/javascript';
        script.async = true;
        head.appendChild(script);

        var errorTimeout = setTimeout(function() {
            onError("Search Timed out");
        }, 3000);

        window['__zl'] = function(data) {
            clearTimeout(errorTimeout);
            if(data === undefined || data[0] === undefined)         // If no data returned, the file was probably 404
                return onError("Zipcode Not Found in DB");          // Thus, zip is not in the db
            var cityID = data[0][zipSet];                           // Look for the City ID in the dataset.
            if(data[1][cityID] === undefined)                       // If no city,
                return onError("Zipcode City Not Found in DB");     // the zip is not in the db
            var cityData = data[1][cityID].split('|');              // Split the city data into name and State ID
            var cityName = cityData[0];
            if(!cityData[1]) cityData[1] = 0;                       // If no State ID was added, this means its 0
            var stateID = cityData[1];                              // Set State ID
            var stateData = data[2][stateID].split('|');            // Split State name and abbreviation
            var stateName = stateData[1];                           // State Name
            var stateShortName = stateData[0];                      // State abbreviation
            onSuccess(cityName, stateName, stateShortName);  // Execute onFound callback with data
        };

        return this;

    };

    var messageElements = document.getElementsByClassName(CLASS_MESSAGE);

    var eventHandler = function(e) {
        switch(e.type) {
            case 'blur':
            case 'change':
                if(hasClass(e.target, CLASS_ZIPCODE)) {
                    var val = e.target.value;
                    var lastVal = typeof e.target.lastVal === 'undefined' ? null : e.target.lastVal;
                    if(val && val !== lastVal) {
                        e.target.lastVal = val;
                        fireEvent(e.target, 'zip-lookup');
                    }
                }

                break;
            case 'zip-lookup':
                var zip = e.target ? e.target.value.trim() : null;

                var container = e.target.form || document;
                ascendDOM(e.target, function(elm) {
                    if(elm.nodeName.toLowerCase() === 'fieldset'
                        || elm === container) {
                        container = elm;
                        return true;
                    }
                });
                for(var i=0; i<messageElements.length; i++) (function(elm) {
                    elm.innerHTML = "Searching...";
                    removeClass(elm, 'error');
                })(messageElements[i]);

                lookup(zip)
                    .onError(function(error) {
                        e.target.setAttribute('zip-lookup-error-message', error);
                        fireEvent(e.target, 'zip-lookup-error');

                        for(var i=0; i<messageElements.length; i++) (function(elm) {
                            elm.innerHTML = error;
                            addClass(elm, 'error');
                        })(messageElements[i]);

                    }).onSuccess(function (cityName, stateName, stateShortName) {
                        traverseDOM(container, function(elm) {
                            if(hasClass(elm,  CLASS_CITY))
                                setValue(elm, cityName);
                            if(hasClass(elm,  CLASS_CITY_TITLE_CASE))
                                setValue(elm, titleCase(cityName));

                            if(hasClass(elm,  CLASS_STATE)){
                                setValue(elm, stateName);}
                            if(hasClass(elm,  CLASS_STATE_SHORT))
                                setValue(elm, stateShortName);

                            if(hasClass(elm,  CLASS_MESSAGE)){
                                elm.innerHTML = "Result found - " + cityName + ', ' + stateShortName;
                                removeClass(elm, 'error');
                            }
                        });

                        e.target.setAttribute('data-city-name', cityName);
                        e.target.setAttribute('data-state-name', stateName);
                        e.target.setAttribute('data-state-short-name', stateShortName);
                        fireEvent(e.target, 'zip-lookup-found');

                        for(var i=0; i<messageElements.length; i++) (function(elm) {
                            elm.innerHTML = "Found " + titleCase(cityName) + ", " + stateName;
                            removeClass(elm, 'error');
                        })(messageElements[i]);

                    });
                break;
            default:
                break;
        }
    };
    document.addEventListener('blur', eventHandler);
    document.addEventListener('change', eventHandler);
    document.addEventListener('zip-lookup', eventHandler);

    function titleCase(str) {
        return str.toLowerCase()
            .replace(/^([a-z\u00E0-\u00FC])|\s+([a-z\u00E0-\u00FC])/g, function($1) {
                return $1.toUpperCase();
            });
    }
})();
<|endoftext|>


<commit_before>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/**
 * @fileoverview Defines WebDriver's logging system. The logging system is
 * broken into major components: local and remote logging.
 *
 * The local logging API, which is anchored by the
 * {@link webdriver.logging.Logger Logger} class, is similar to Java's
 * logging API. Loggers, retrieved by {@link webdriver.logging.getLogger}, use
 * hierarchical, dot-delimited namespaces
 * (e.g. "" > "webdriver" > "webdriver.logging"). Recorded log messages are
 * represented by the {@link webdriver.logging.LogRecord LogRecord} class. You
 * can capture log records by
 * {@linkplain webdriver.logging.Logger#addHandler attaching} a handler function
 * to the desired logger. For convenience, you can quickly enable logging to
 * the console by simply calling
 * {@link webdriver.logging.installConsoleHandler()}.
 *
 * The [remote logging API](https://github.com/SeleniumHQ/selenium/wiki/Logging)
 * allows you to retrieve logs from a remote WebDriver server. This API uses the
 * {@link Preferences} class to define desired log levels prior to create a
 * WebDriver session:
 *
 *     var prefs = new webdriver.logging.Preferences();
 *     prefs.setLevel(webdriver.logging.Type.BROWSER,
 *                    webdriver.logging.Level.DEBUG);
 *
 *     var caps = webdriver.Capabilities.chrome();
 *     caps.setLoggingPrefs(prefs);
 *     // ...
 *
 * Remote log entries are represented by the {@link Entry} class and may be
 * retrieved via {@link webdriver.WebDriver.Logs}:
 *
 *     driver.manage().logs().get(webdriver.logging.Type.BROWSER)
 *         .then(function(entries) {
 *            entries.forEach(function(entry) {
 *              console.log('[%s] %s', entry.level.name, entry.message);
 *            });
 *         });
 *
 * **NOTE:** Only a few browsers support the remote logging API (notably
 * Firefox and Chrome). Firefox supports basic logging functionality, while
 * Chrome exposes robust
 * [performance logging](https://sites.google.com/a/chromium.org/chromedriver/logging)
 * options. Remote logging is still considered a non-standard feature, and the
 * APIs exposed by this module for it are non-frozen. Once logging is officially
 * defined by the [W3C WebDriver spec](http://www.w3.org/TR/webdriver/), this
 * module will be updated to use a consistent API for local and remote logging.
 */

goog.module('webdriver.logging');
goog.module.declareLegacyNamespace();

var googDebug = goog.require('goog.debug');
var googString = goog.require('goog.string');

var LogManager = googDebug.LogManager;
var LogRecord = googDebug.LogRecord;
var Logger = googDebug.Logger;
var padNumber = googString.padNumber;

/** @const */
exports.LogRecord = LogRecord;

/** @const */
exports.Logger = Logger;

/** @const */
exports.Level = Logger.Level;

/**
 * DEBUG is a message level for debugging messages and has the same log level
 * as the {@link Logger.Level.CONFIG} message level.
 * @const {!Logger.Level}
 */
Logger.Level.DEBUG = new Logger.Level('DEBUG', Logger.Level.CONFIG.value);

/**
 * Finds a named logger.
 *
 * @param {string=} opt_name The dot-delimited logger name, such as
 *     "webdriver.logging.Logger". Defaults to the name of the root logger.
 * @return {!Logger} The named logger.
 */
function getLogger(opt_name) {
  return LogManager.getLogger(opt_name || Logger.ROOT_LOGGER_NAME);
}
exports.getLogger = getLogger;

/**
 * Logs all messages to the Console API.
 */
function consoleHandler(record) {
  if (typeof console === 'undefined' || !console) {
    return;
  }
  record = /** @type {!LogRecord} */(record);
  var timestamp = new Date(record.getMillis());
  var msg =
      '[' + timestamp.getUTCFullYear() + '-' +
      padNumber(timestamp.getUTCMonth() + 1, 2) + '-' +
      padNumber(timestamp.getUTCDate(), 2) + 'T' +
      padNumber(timestamp.getUTCHours(), 2) + ':' +
      padNumber(timestamp.getUTCMinutes(), 2) + ':' +
      padNumber(timestamp.getUTCSeconds(), 2) + 'Z]' +
      '[' + record.getLevel().name + ']' +
      '[' + record.getLoggerName() + '] ' +
      record.getMessage();

  var level = record.getLevel().value;
  if (level >= Logger.Level.SEVERE.value) {
    console.error(msg);
  } else if (level >= Logger.Level.WARNING.value) {
    console.warn(msg);
  } else {
    console.log(msg);
  }
}

/**
 * Adds the console handler to the given logger. The console handler will log
 * all messages using the JavaScript Console API.
 *
 * @param {Logger=} opt_logger The logger to add the handler to; defaults
 *     to the root logger.
 * @see exports.removeConsoleHandler
 */
exports.addConsoleHandler = function(opt_logger) {
  var logger = opt_logger || getLogger();
  logger.addHandler(consoleHandler);
};

/**
 * Installs the console log handler on the root logger.
 * @see exports.addConsoleHandler
 */
exports.installConsoleHandler = function() {
  exports.addConsoleHandler();
};

/**
 * Removes the console log handler from the given logger.
 *
 * @param {Logger=} opt_logger The logger to remove the handler from; defaults
 *     to the root logger.
 * @see exports.addConsoleHandler
 */
exports.removeConsoleHandler = function(opt_logger) {
  var logger = opt_logger || getLogger();
  logger.removeHandler(consoleHandler);
};

/**
 * Converts a level name or value to a {@link webdriver.logging.Level} value.
 * If the name/value is not recognized, {@link webdriver.logging.Level.ALL}
 * will be returned.
 * @param {(number|string)} nameOrValue The log level name, or value, to
 *     convert .
 * @return {!Logger.Level} The converted level.
 */
function getLevel(nameOrValue) {
  // DEBUG is not a predefined Closure log level, but maps to CONFIG. Since
  // DEBUG is a predefined level for the WebDriver protocol, we prefer it over
  // CONFIG.
  if ('DEBUG' === nameOrValue || Logger.Level.DEBUG.value === nameOrValue) {
    return Logger.Level.DEBUG;
  } else if (goog.isString(nameOrValue)) {
    return Logger.Level.getPredefinedLevel(/** @type {string} */(nameOrValue))
        || Logger.Level.ALL;
  } else {
    return Logger.Level.getPredefinedLevelByValue(
        /** @type {number} */(nameOrValue)) || Logger.Level.ALL;
  }
}
exports.getLevel = getLevel;

/**
 * Normalizes a {@link Logger.Level} to one of the distinct values recognized
 * by WebDriver's wire protocol.
 * @param {!Logger.Level} level The input level.
 * @return {!Logger.Level} The normalized level.
 */
function normalizeLevel(level) {
  if (level.value <= Logger.Level.ALL.value) {          // ALL is 0.
    return Logger.Level.ALL;

  } else if (level.value === Logger.Level.OFF.value) {  // OFF is Infinity
    return Logger.Level.OFF;

  } else if (level.value < Logger.Level.INFO.value) {
    return Logger.Level.DEBUG;

  } else if (level.value < Logger.Level.WARNING.value) {
    return Logger.Level.INFO;

  } else if (level.value < Logger.Level.SEVERE.value) {
    return Logger.Level.WARNING;

  } else {
    return Logger.Level.SEVERE;
  }
}

/**
 * Common log types.
 * @enum {string}
 */
var Type = {
  /** Logs originating from the browser. */
  BROWSER: 'browser',
  /** Logs from a WebDriver client. */
  CLIENT: 'client',
  /** Logs from a WebDriver implementation. */
  DRIVER: 'driver',
  /** Logs related to performance. */
  PERFORMANCE: 'performance',
  /** Logs from the remote server. */
  SERVER: 'server'
};
exports.Type = Type;

/**
 * Describes the log preferences for a WebDriver session.
 * @final
 */
var Preferences = goog.defineClass(null, {
  /** @constructor */
  constructor: function() {
    /** @private {!Object.<string, Logger.Level>} */
    this.prefs_ = {};
  },

  /**
   * Sets the desired logging level for a particular log type.
   * @param {(string|Type)} type The log type.
   * @param {!Logger.Level} level The desired log level.
   */
  setLevel: function(type, level) {
    this.prefs_[type] = normalizeLevel(level);
  },

  /**
   * Converts this instance to its JSON representation.
   * @return {!Object.<string, string>} The JSON representation of this set of
   *     preferences.
   */
  toJSON: function() {
    var obj = {};
    for (var type in this.prefs_) {
      if (this.prefs_.hasOwnProperty(type)) {
        obj[type] = this.prefs_[type].name;
      }
    }
    return obj;
  }
});
exports.Preferences = Preferences;

/**
 * A single log entry recorded by a WebDriver component, such as a remote
 * WebDriver server.
 * @final
 */
var Entry = goog.defineClass(null, {
  /**
   * @param {(!Logger.Level|string)} level The entry level.
   * @param {string} message The log message.
   * @param {number=} opt_timestamp The time this entry was generated, in
   *     milliseconds since 0:00:00, January 1, 1970 UTC. If omitted, the
   *     current time will be used.
   * @param {string=} opt_type The log type, if known.
   * @constructor
   */
  constructor: function(level, message, opt_timestamp, opt_type) {

    /** @type {!Logger.Level} */
    this.level = goog.isString(level) ? getLevel(level) : level;

    /** @type {string} */
    this.message = message;

    /** @type {number} */
    this.timestamp = goog.isNumber(opt_timestamp) ? opt_timestamp : goog.now();

    /** @type {string} */
    this.type = opt_type || '';
  },

  statics: {
    /**
     * Converts a {@link goog.debug.LogRecord} into a
     * {@link webdriver.logging.Entry}.
     * @param {!LogRecord} logRecord The record to convert.
     * @param {string=} opt_type The log type.
     * @return {!Entry} The converted entry.
     */
    fromClosureLogRecord: function(logRecord, opt_type) {
      return new Entry(
          normalizeLevel(/** @type {!Logger.Level} */(logRecord.getLevel())),
          '[' + logRecord.getLoggerName() + '] ' + logRecord.getMessage(),
          logRecord.getMillis(),
          opt_type);
    }
  },

  /**
   * @return {{level: string, message: string, timestamp: number,
   *           type: string}} The JSON representation of this entry.
   */
  toJSON: function() {
    return {
      'level': this.level.name,
      'message': this.message,
      'timestamp': this.timestamp,
      'type': this.type
    };
  }
});
exports.Entry = Entry;
<commit_msg>Get the JS tests working again<commit_after>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/**
 * @fileoverview Defines WebDriver's logging system. The logging system is
 * broken into major components: local and remote logging.
 *
 * The local logging API, which is anchored by the
 * {@link webdriver.logging.Logger Logger} class, is similar to Java's
 * logging API. Loggers, retrieved by {@link webdriver.logging.getLogger}, use
 * hierarchical, dot-delimited namespaces
 * (e.g. "" > "webdriver" > "webdriver.logging"). Recorded log messages are
 * represented by the {@link webdriver.logging.LogRecord LogRecord} class. You
 * can capture log records by
 * {@linkplain webdriver.logging.Logger#addHandler attaching} a handler function
 * to the desired logger. For convenience, you can quickly enable logging to
 * the console by simply calling
 * {@link webdriver.logging.installConsoleHandler()}.
 *
 * The [remote logging API](https://github.com/SeleniumHQ/selenium/wiki/Logging)
 * allows you to retrieve logs from a remote WebDriver server. This API uses the
 * {@link Preferences} class to define desired log levels prior to create a
 * WebDriver session:
 *
 *     var prefs = new webdriver.logging.Preferences();
 *     prefs.setLevel(webdriver.logging.Type.BROWSER,
 *                    webdriver.logging.Level.DEBUG);
 *
 *     var caps = webdriver.Capabilities.chrome();
 *     caps.setLoggingPrefs(prefs);
 *     // ...
 *
 * Remote log entries are represented by the {@link Entry} class and may be
 * retrieved via {@link webdriver.WebDriver.Logs}:
 *
 *     driver.manage().logs().get(webdriver.logging.Type.BROWSER)
 *         .then(function(entries) {
 *            entries.forEach(function(entry) {
 *              console.log('[%s] %s', entry.level.name, entry.message);
 *            });
 *         });
 *
 * **NOTE:** Only a few browsers support the remote logging API (notably
 * Firefox and Chrome). Firefox supports basic logging functionality, while
 * Chrome exposes robust
 * [performance logging](https://sites.google.com/a/chromium.org/chromedriver/logging)
 * options. Remote logging is still considered a non-standard feature, and the
 * APIs exposed by this module for it are non-frozen. Once logging is officially
 * defined by the [W3C WebDriver spec](http://www.w3.org/TR/webdriver/), this
 * module will be updated to use a consistent API for local and remote logging.
 */

goog.module('webdriver.logging');
goog.module.declareLegacyNamespace();

var LogManager = goog.require('goog.debug.LogManager');
var LogRecord = goog.require('goog.debug.LogRecord');
var Logger = goog.require('goog.debug.Logger');
var googString = goog.require('goog.string');

var padNumber = googString.padNumber;

/** @const */
exports.LogRecord = LogRecord;

/** @const */
exports.Logger = Logger;

/** @const */
exports.Level = Logger.Level;

/**
 * DEBUG is a message level for debugging messages and has the same log level
 * as the {@link Logger.Level.CONFIG} message level.
 * @const {!Logger.Level}
 */
Logger.Level.DEBUG = new Logger.Level('DEBUG', Logger.Level.CONFIG.value);

/**
 * Finds a named logger.
 *
 * @param {string=} opt_name The dot-delimited logger name, such as
 *     "webdriver.logging.Logger". Defaults to the name of the root logger.
 * @return {!Logger} The named logger.
 */
function getLogger(opt_name) {
  return LogManager.getLogger(opt_name || Logger.ROOT_LOGGER_NAME);
}
exports.getLogger = getLogger;

/**
 * Logs all messages to the Console API.
 */
function consoleHandler(record) {
  if (typeof console === 'undefined' || !console) {
    return;
  }
  record = /** @type {!LogRecord} */(record);
  var timestamp = new Date(record.getMillis());
  var msg =
      '[' + timestamp.getUTCFullYear() + '-' +
      padNumber(timestamp.getUTCMonth() + 1, 2) + '-' +
      padNumber(timestamp.getUTCDate(), 2) + 'T' +
      padNumber(timestamp.getUTCHours(), 2) + ':' +
      padNumber(timestamp.getUTCMinutes(), 2) + ':' +
      padNumber(timestamp.getUTCSeconds(), 2) + 'Z]' +
      '[' + record.getLevel().name + ']' +
      '[' + record.getLoggerName() + '] ' +
      record.getMessage();

  var level = record.getLevel().value;
  if (level >= Logger.Level.SEVERE.value) {
    console.error(msg);
  } else if (level >= Logger.Level.WARNING.value) {
    console.warn(msg);
  } else {
    console.log(msg);
  }
}

/**
 * Adds the console handler to the given logger. The console handler will log
 * all messages using the JavaScript Console API.
 *
 * @param {Logger=} opt_logger The logger to add the handler to; defaults
 *     to the root logger.
 * @see exports.removeConsoleHandler
 */
exports.addConsoleHandler = function(opt_logger) {
  var logger = opt_logger || getLogger();
  logger.addHandler(consoleHandler);
};

/**
 * Installs the console log handler on the root logger.
 * @see exports.addConsoleHandler
 */
exports.installConsoleHandler = function() {
  exports.addConsoleHandler();
};

/**
 * Removes the console log handler from the given logger.
 *
 * @param {Logger=} opt_logger The logger to remove the handler from; defaults
 *     to the root logger.
 * @see exports.addConsoleHandler
 */
exports.removeConsoleHandler = function(opt_logger) {
  var logger = opt_logger || getLogger();
  logger.removeHandler(consoleHandler);
};

/**
 * Converts a level name or value to a {@link webdriver.logging.Level} value.
 * If the name/value is not recognized, {@link webdriver.logging.Level.ALL}
 * will be returned.
 * @param {(number|string)} nameOrValue The log level name, or value, to
 *     convert .
 * @return {!Logger.Level} The converted level.
 */
function getLevel(nameOrValue) {
  // DEBUG is not a predefined Closure log level, but maps to CONFIG. Since
  // DEBUG is a predefined level for the WebDriver protocol, we prefer it over
  // CONFIG.
  if ('DEBUG' === nameOrValue || Logger.Level.DEBUG.value === nameOrValue) {
    return Logger.Level.DEBUG;
  } else if (goog.isString(nameOrValue)) {
    return Logger.Level.getPredefinedLevel(/** @type {string} */(nameOrValue))
        || Logger.Level.ALL;
  } else {
    return Logger.Level.getPredefinedLevelByValue(
        /** @type {number} */(nameOrValue)) || Logger.Level.ALL;
  }
}
exports.getLevel = getLevel;

/**
 * Normalizes a {@link Logger.Level} to one of the distinct values recognized
 * by WebDriver's wire protocol.
 * @param {!Logger.Level} level The input level.
 * @return {!Logger.Level} The normalized level.
 */
function normalizeLevel(level) {
  if (level.value <= Logger.Level.ALL.value) {          // ALL is 0.
    return Logger.Level.ALL;

  } else if (level.value === Logger.Level.OFF.value) {  // OFF is Infinity
    return Logger.Level.OFF;

  } else if (level.value < Logger.Level.INFO.value) {
    return Logger.Level.DEBUG;

  } else if (level.value < Logger.Level.WARNING.value) {
    return Logger.Level.INFO;

  } else if (level.value < Logger.Level.SEVERE.value) {
    return Logger.Level.WARNING;

  } else {
    return Logger.Level.SEVERE;
  }
}

/**
 * Common log types.
 * @enum {string}
 */
var Type = {
  /** Logs originating from the browser. */
  BROWSER: 'browser',
  /** Logs from a WebDriver client. */
  CLIENT: 'client',
  /** Logs from a WebDriver implementation. */
  DRIVER: 'driver',
  /** Logs related to performance. */
  PERFORMANCE: 'performance',
  /** Logs from the remote server. */
  SERVER: 'server'
};
exports.Type = Type;

/**
 * Describes the log preferences for a WebDriver session.
 * @final
 */
var Preferences = goog.defineClass(null, {
  /** @constructor */
  constructor: function() {
    /** @private {!Object.<string, Logger.Level>} */
    this.prefs_ = {};
  },

  /**
   * Sets the desired logging level for a particular log type.
   * @param {(string|Type)} type The log type.
   * @param {!Logger.Level} level The desired log level.
   */
  setLevel: function(type, level) {
    this.prefs_[type] = normalizeLevel(level);
  },

  /**
   * Converts this instance to its JSON representation.
   * @return {!Object.<string, string>} The JSON representation of this set of
   *     preferences.
   */
  toJSON: function() {
    var obj = {};
    for (var type in this.prefs_) {
      if (this.prefs_.hasOwnProperty(type)) {
        obj[type] = this.prefs_[type].name;
      }
    }
    return obj;
  }
});
exports.Preferences = Preferences;

/**
 * A single log entry recorded by a WebDriver component, such as a remote
 * WebDriver server.
 * @final
 */
var Entry = goog.defineClass(null, {
  /**
   * @param {(!Logger.Level|string)} level The entry level.
   * @param {string} message The log message.
   * @param {number=} opt_timestamp The time this entry was generated, in
   *     milliseconds since 0:00:00, January 1, 1970 UTC. If omitted, the
   *     current time will be used.
   * @param {string=} opt_type The log type, if known.
   * @constructor
   */
  constructor: function(level, message, opt_timestamp, opt_type) {

    /** @type {!Logger.Level} */
    this.level = goog.isString(level) ? getLevel(level) : level;

    /** @type {string} */
    this.message = message;

    /** @type {number} */
    this.timestamp = goog.isNumber(opt_timestamp) ? opt_timestamp : goog.now();

    /** @type {string} */
    this.type = opt_type || '';
  },

  statics: {
    /**
     * Converts a {@link goog.debug.LogRecord} into a
     * {@link webdriver.logging.Entry}.
     * @param {!LogRecord} logRecord The record to convert.
     * @param {string=} opt_type The log type.
     * @return {!Entry} The converted entry.
     */
    fromClosureLogRecord: function(logRecord, opt_type) {
      return new Entry(
          normalizeLevel(/** @type {!Logger.Level} */(logRecord.getLevel())),
          '[' + logRecord.getLoggerName() + '] ' + logRecord.getMessage(),
          logRecord.getMillis(),
          opt_type);
    }
  },

  /**
   * @return {{level: string, message: string, timestamp: number,
   *           type: string}} The JSON representation of this entry.
   */
  toJSON: function() {
    return {
      'level': this.level.name,
      'message': this.message,
      'timestamp': this.timestamp,
      'type': this.type
    };
  }
});
exports.Entry = Entry;
<|endoftext|>