You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by mm...@apache.org on 2014/04/24 20:30:28 UTC

[1/9] git commit: css syntax fix

Repository: cordova-labs
Updated Branches:
  refs/heads/cdvtest adc757661 -> 7d614b920


css syntax fix


Project: http://git-wip-us.apache.org/repos/asf/cordova-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-labs/commit/b12e2cf1
Tree: http://git-wip-us.apache.org/repos/asf/cordova-labs/tree/b12e2cf1
Diff: http://git-wip-us.apache.org/repos/asf/cordova-labs/diff/b12e2cf1

Branch: refs/heads/cdvtest
Commit: b12e2cf1ce038bbbfa40031e50fd372aadf4c5f1
Parents: adc7576
Author: Michal Mocny <mm...@gmail.com>
Authored: Mon Mar 31 15:01:54 2014 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Mon Mar 31 15:01:54 2014 -0400

----------------------------------------------------------------------
 cordova-app-test-harness/www/main.css | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/b12e2cf1/cordova-app-test-harness/www/main.css
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/main.css b/cordova-app-test-harness/www/main.css
index 70bfcf9..c85be21 100644
--- a/cordova-app-test-harness/www/main.css
+++ b/cordova-app-test-harness/www/main.css
@@ -1,6 +1,6 @@
 html, body {
   height: 100%;
-  width: 100%
+  width: 100%;
   padding: 0;
   margin: 0;
 }


[4/9] replace jasmine rc5 with release version

Posted by mm...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine.css
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine.css b/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine.css
new file mode 100755
index 0000000..f4d35b6
--- /dev/null
+++ b/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine.css
@@ -0,0 +1,55 @@
+body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
+
+.html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+.html-reporter a { text-decoration: none; }
+.html-reporter a:hover { text-decoration: underline; }
+.html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; }
+.html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; }
+.html-reporter .banner .version { margin-left: 14px; }
+.html-reporter #jasmine_content { position: fixed; right: 100%; }
+.html-reporter .version { color: #aaaaaa; }
+.html-reporter .banner { margin-top: 14px; }
+.html-reporter .duration { color: #aaaaaa; float: right; }
+.html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+.html-reporter .symbol-summary li { display: inline-block; height: 8px; width: 14px; font-size: 16px; }
+.html-reporter .symbol-summary li.passed { font-size: 14px; }
+.html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; }
+.html-reporter .symbol-summary li.failed { line-height: 9px; }
+.html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+.html-reporter .symbol-summary li.disabled { font-size: 14px; }
+.html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; }
+.html-reporter .symbol-summary li.pending { line-height: 17px; }
+.html-reporter .symbol-summary li.pending:before { color: #ba9d37; content: "*"; }
+.html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
+.html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+.html-reporter .bar.failed { background-color: #b03911; }
+.html-reporter .bar.passed { background-color: #a6b779; }
+.html-reporter .bar.skipped { background-color: #bababa; }
+.html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; }
+.html-reporter .bar.menu a { color: #333333; }
+.html-reporter .bar a { color: white; }
+.html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; }
+.html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; }
+.html-reporter .running-alert { background-color: #666666; }
+.html-reporter .results { margin-top: 14px; }
+.html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+.html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+.html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+.html-reporter.showDetails .summary { display: none; }
+.html-reporter.showDetails #details { display: block; }
+.html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+.html-reporter .summary { margin-top: 14px; }
+.html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; }
+.html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; }
+.html-reporter .summary li.passed a { color: #5e7d00; }
+.html-reporter .summary li.failed a { color: #b03911; }
+.html-reporter .summary li.pending a { color: #ba9d37; }
+.html-reporter .description + .suite { margin-top: 0; }
+.html-reporter .suite { margin-top: 14px; }
+.html-reporter .suite a { color: #333333; }
+.html-reporter .failures .spec-detail { margin-bottom: 28px; }
+.html-reporter .failures .spec-detail .description { background-color: #b03911; }
+.html-reporter .failures .spec-detail .description a { color: white; }
+.html-reporter .result-message { padding-top: 14px; color: #333333; white-space: pre; }
+.html-reporter .result-message span.result { display: block; }
+.html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine.js b/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine.js
new file mode 100755
index 0000000..8fffe94
--- /dev/null
+++ b/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine.js
@@ -0,0 +1,2401 @@
+/*
+Copyright (c) 2008-2013 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+function getJasmineRequireObj() {
+  if (typeof module !== "undefined" && module.exports) {
+    return exports;
+  } else {
+    window.jasmineRequire = window.jasmineRequire || {};
+    return window.jasmineRequire;
+  }
+}
+
+getJasmineRequireObj().core = function(jRequire) {
+  var j$ = {};
+
+  jRequire.base(j$);
+  j$.util = jRequire.util();
+  j$.Any = jRequire.Any();
+  j$.CallTracker = jRequire.CallTracker();
+  j$.Clock = jRequire.Clock();
+  j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
+  j$.Env = jRequire.Env(j$);
+  j$.ExceptionFormatter = jRequire.ExceptionFormatter();
+  j$.Expectation = jRequire.Expectation();
+  j$.buildExpectationResult = jRequire.buildExpectationResult();
+  j$.JsApiReporter = jRequire.JsApiReporter();
+  j$.matchersUtil = jRequire.matchersUtil(j$);
+  j$.ObjectContaining = jRequire.ObjectContaining(j$);
+  j$.pp = jRequire.pp(j$);
+  j$.QueueRunner = jRequire.QueueRunner();
+  j$.ReportDispatcher = jRequire.ReportDispatcher();
+  j$.Spec = jRequire.Spec(j$);
+  j$.SpyStrategy = jRequire.SpyStrategy();
+  j$.Suite = jRequire.Suite();
+  j$.Timer = jRequire.Timer();
+  j$.version = jRequire.version();
+
+  j$.matchers = jRequire.requireMatchers(jRequire, j$);
+
+  return j$;
+};
+
+getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
+  var availableMatchers = [
+      "toBe",
+      "toBeCloseTo",
+      "toBeDefined",
+      "toBeFalsy",
+      "toBeGreaterThan",
+      "toBeLessThan",
+      "toBeNaN",
+      "toBeNull",
+      "toBeTruthy",
+      "toBeUndefined",
+      "toContain",
+      "toEqual",
+      "toHaveBeenCalled",
+      "toHaveBeenCalledWith",
+      "toMatch",
+      "toThrow",
+      "toThrowError"
+    ],
+    matchers = {};
+
+  for (var i = 0; i < availableMatchers.length; i++) {
+    var name = availableMatchers[i];
+    matchers[name] = jRequire[name](j$);
+  }
+
+  return matchers;
+};
+
+getJasmineRequireObj().base = (function (jasmineGlobal) {
+  return function(j$) {
+    j$.unimplementedMethod_ = function() {
+      throw new Error("unimplemented method");
+    };
+
+    j$.MAX_PRETTY_PRINT_DEPTH = 40;
+    j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+    j$.getGlobal = function() {
+      return jasmineGlobal;
+    };
+
+    j$.getEnv = function(options) {
+      var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
+      //jasmine. singletons in here (setTimeout blah blah).
+      return env;
+    };
+
+    j$.isArray_ = function(value) {
+      return j$.isA_("Array", value);
+    };
+
+    j$.isString_ = function(value) {
+      return j$.isA_("String", value);
+    };
+
+    j$.isNumber_ = function(value) {
+      return j$.isA_("Number", value);
+    };
+
+    j$.isA_ = function(typeName, value) {
+      return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+    };
+
+    j$.isDomNode = function(obj) {
+      return obj.nodeType > 0;
+    };
+
+    j$.any = function(clazz) {
+      return new j$.Any(clazz);
+    };
+
+    j$.objectContaining = function(sample) {
+      return new j$.ObjectContaining(sample);
+    };
+
+    j$.createSpy = function(name, originalFn) {
+
+      var spyStrategy = new j$.SpyStrategy({
+          name: name,
+          fn: originalFn,
+          getSpy: function() { return spy; }
+        }),
+        callTracker = new j$.CallTracker(),
+        spy = function() {
+          callTracker.track({
+            object: this,
+            args: Array.prototype.slice.apply(arguments)
+          });
+          return spyStrategy.exec.apply(this, arguments);
+        };
+
+      for (var prop in originalFn) {
+        if (prop === 'and' || prop === 'calls') {
+          throw new Error("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon");
+        }
+
+        spy[prop] = originalFn[prop];
+      }
+
+      spy.and = spyStrategy;
+      spy.calls = callTracker;
+
+      return spy;
+    };
+
+    j$.isSpy = function(putativeSpy) {
+      if (!putativeSpy) {
+        return false;
+      }
+      return putativeSpy.and instanceof j$.SpyStrategy &&
+        putativeSpy.calls instanceof j$.CallTracker;
+    };
+
+    j$.createSpyObj = function(baseName, methodNames) {
+      if (!j$.isArray_(methodNames) || methodNames.length === 0) {
+        throw "createSpyObj requires a non-empty array of method names to create spies for";
+      }
+      var obj = {};
+      for (var i = 0; i < methodNames.length; i++) {
+        obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
+      }
+      return obj;
+    };
+  }
+})(this);
+
+getJasmineRequireObj().util = function() {
+
+  var util = {};
+
+  util.inherit = function(childClass, parentClass) {
+    var Subclass = function() {
+    };
+    Subclass.prototype = parentClass.prototype;
+    childClass.prototype = new Subclass();
+  };
+
+  util.htmlEscape = function(str) {
+    if (!str) {
+      return str;
+    }
+    return str.replace(/&/g, '&amp;')
+      .replace(/</g, '&lt;')
+      .replace(/>/g, '&gt;');
+  };
+
+  util.argsToArray = function(args) {
+    var arrayOfArgs = [];
+    for (var i = 0; i < args.length; i++) {
+      arrayOfArgs.push(args[i]);
+    }
+    return arrayOfArgs;
+  };
+
+  util.isUndefined = function(obj) {
+    return obj === void 0;
+  };
+
+  return util;
+};
+
+getJasmineRequireObj().Spec = function(j$) {
+  function Spec(attrs) {
+    this.expectationFactory = attrs.expectationFactory;
+    this.resultCallback = attrs.resultCallback || function() {};
+    this.id = attrs.id;
+    this.description = attrs.description || '';
+    this.fn = attrs.fn;
+    this.beforeFns = attrs.beforeFns || function() { return []; };
+    this.afterFns = attrs.afterFns || function() { return []; };
+    this.onStart = attrs.onStart || function() {};
+    this.exceptionFormatter = attrs.exceptionFormatter || function() {};
+    this.getSpecName = attrs.getSpecName || function() { return ''; };
+    this.expectationResultFactory = attrs.expectationResultFactory || function() { };
+    this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
+    this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
+
+    this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout};
+
+    if (!this.fn) {
+      this.pend();
+    }
+
+    this.result = {
+      id: this.id,
+      description: this.description,
+      fullName: this.getFullName(),
+      failedExpectations: []
+    };
+  }
+
+  Spec.prototype.addExpectationResult = function(passed, data) {
+    if (passed) {
+      return;
+    }
+    this.result.failedExpectations.push(this.expectationResultFactory(data));
+  };
+
+  Spec.prototype.expect = function(actual) {
+    return this.expectationFactory(actual, this);
+  };
+
+  Spec.prototype.execute = function(onComplete) {
+    var self = this,
+        timeout;
+
+    this.onStart(this);
+
+    if (this.markedPending || this.disabled) {
+      complete();
+      return;
+    }
+
+    function timeoutable(fn) {
+      return function(done) {
+        timeout = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
+          onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'));
+          done();
+        }, j$.DEFAULT_TIMEOUT_INTERVAL]]);
+
+        var callDone = function() {
+          clearTimeoutable();
+          done();
+        };
+
+        fn.call(this, callDone); //TODO: do we care about more than 1 arg?
+      };
+    }
+
+    function clearTimeoutable() {
+      Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]);
+      timeout = void 0;
+    }
+
+    var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()),
+      allTimeoutableFns = [];
+    for (var i = 0; i < allFns.length; i++) {
+      var fn = allFns[i];
+      allTimeoutableFns.push(fn.length > 0 ? timeoutable(fn) : fn);
+    }
+
+    this.queueRunnerFactory({
+      fns: allTimeoutableFns,
+      onException: onException,
+      onComplete: complete
+    });
+
+    function onException(e) {
+      clearTimeoutable();
+      if (Spec.isPendingSpecException(e)) {
+        self.pend();
+        return;
+      }
+
+      self.addExpectationResult(false, {
+        matcherName: "",
+        passed: false,
+        expected: "",
+        actual: "",
+        error: e
+      });
+    }
+
+    function complete() {
+      self.result.status = self.status();
+      self.resultCallback(self.result);
+
+      if (onComplete) {
+        onComplete();
+      }
+    }
+  };
+
+  Spec.prototype.disable = function() {
+    this.disabled = true;
+  };
+
+  Spec.prototype.pend = function() {
+    this.markedPending = true;
+  };
+
+  Spec.prototype.status = function() {
+    if (this.disabled) {
+      return 'disabled';
+    }
+
+    if (this.markedPending) {
+      return 'pending';
+    }
+
+    if (this.result.failedExpectations.length > 0) {
+      return 'failed';
+    } else {
+      return 'passed';
+    }
+  };
+
+  Spec.prototype.getFullName = function() {
+    return this.getSpecName(this);
+  };
+
+  Spec.pendingSpecExceptionMessage = "=> marked Pending";
+
+  Spec.isPendingSpecException = function(e) {
+    return e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1;
+  };
+
+  return Spec;
+};
+
+if (typeof window == void 0 && typeof exports == "object") {
+  exports.Spec = jasmineRequire.Spec;
+}
+
+getJasmineRequireObj().Env = function(j$) {
+  function Env(options) {
+    options = options || {};
+
+    var self = this;
+    var global = options.global || j$.getGlobal();
+
+    var totalSpecsDefined = 0;
+
+    var catchExceptions = true;
+
+    var realSetTimeout = j$.getGlobal().setTimeout;
+    var realClearTimeout = j$.getGlobal().clearTimeout;
+    this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler());
+
+    var runnableLookupTable = {};
+
+    var spies = [];
+
+    var currentSpec = null;
+    var currentSuite = null;
+
+    var reporter = new j$.ReportDispatcher([
+      "jasmineStarted",
+      "jasmineDone",
+      "suiteStarted",
+      "suiteDone",
+      "specStarted",
+      "specDone"
+    ]);
+
+    this.specFilter = function() {
+      return true;
+    };
+
+    var equalityTesters = [];
+
+    var customEqualityTesters = [];
+    this.addCustomEqualityTester = function(tester) {
+      customEqualityTesters.push(tester);
+    };
+
+    j$.Expectation.addCoreMatchers(j$.matchers);
+
+    var nextSpecId = 0;
+    var getNextSpecId = function() {
+      return 'spec' + nextSpecId++;
+    };
+
+    var nextSuiteId = 0;
+    var getNextSuiteId = function() {
+      return 'suite' + nextSuiteId++;
+    };
+
+    var expectationFactory = function(actual, spec) {
+      return j$.Expectation.Factory({
+        util: j$.matchersUtil,
+        customEqualityTesters: customEqualityTesters,
+        actual: actual,
+        addExpectationResult: addExpectationResult
+      });
+
+      function addExpectationResult(passed, result) {
+        return spec.addExpectationResult(passed, result);
+      }
+    };
+
+    var specStarted = function(spec) {
+      currentSpec = spec;
+      reporter.specStarted(spec.result);
+    };
+
+    var beforeFns = function(suite) {
+      return function() {
+        var befores = [];
+        while(suite) {
+          befores = befores.concat(suite.beforeFns);
+          suite = suite.parentSuite;
+        }
+        return befores.reverse();
+      };
+    };
+
+    var afterFns = function(suite) {
+      return function() {
+        var afters = [];
+        while(suite) {
+          afters = afters.concat(suite.afterFns);
+          suite = suite.parentSuite;
+        }
+        return afters;
+      };
+    };
+
+    var getSpecName = function(spec, suite) {
+      return suite.getFullName() + ' ' + spec.description;
+    };
+
+    // TODO: we may just be able to pass in the fn instead of wrapping here
+    var buildExpectationResult = j$.buildExpectationResult,
+        exceptionFormatter = new j$.ExceptionFormatter(),
+        expectationResultFactory = function(attrs) {
+          attrs.messageFormatter = exceptionFormatter.message;
+          attrs.stackFormatter = exceptionFormatter.stack;
+
+          return buildExpectationResult(attrs);
+        };
+
+    // TODO: fix this naming, and here's where the value comes in
+    this.catchExceptions = function(value) {
+      catchExceptions = !!value;
+      return catchExceptions;
+    };
+
+    this.catchingExceptions = function() {
+      return catchExceptions;
+    };
+
+    var maximumSpecCallbackDepth = 20;
+    var currentSpecCallbackDepth = 0;
+
+    function clearStack(fn) {
+      currentSpecCallbackDepth++;
+      if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) {
+        currentSpecCallbackDepth = 0;
+        realSetTimeout(fn, 0);
+      } else {
+        fn();
+      }
+    }
+
+    var catchException = function(e) {
+      return j$.Spec.isPendingSpecException(e) || catchExceptions;
+    };
+
+    var queueRunnerFactory = function(options) {
+      options.catchException = catchException;
+      options.clearStack = options.clearStack || clearStack;
+
+      new j$.QueueRunner(options).execute();
+    };
+
+    var topSuite = new j$.Suite({
+      env: this,
+      id: getNextSuiteId(),
+      description: 'Jasmine__TopLevel__Suite',
+      queueRunner: queueRunnerFactory,
+      resultCallback: function() {} // TODO - hook this up
+    });
+    runnableLookupTable[topSuite.id] = topSuite;
+    currentSuite = topSuite;
+
+    this.topSuite = function() {
+      return topSuite;
+    };
+
+    this.execute = function(runnablesToRun) {
+      runnablesToRun = runnablesToRun || [topSuite.id];
+
+      var allFns = [];
+      for(var i = 0; i < runnablesToRun.length; i++) {
+        var runnable = runnableLookupTable[runnablesToRun[i]];
+        allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable));
+      }
+
+      reporter.jasmineStarted({
+        totalSpecsDefined: totalSpecsDefined
+      });
+
+      queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
+    };
+
+    this.addReporter = function(reporterToAdd) {
+      reporter.addReporter(reporterToAdd);
+    };
+
+    this.addMatchers = function(matchersToAdd) {
+      j$.Expectation.addMatchers(matchersToAdd);
+    };
+
+    this.spyOn = function(obj, methodName) {
+      if (j$.util.isUndefined(obj)) {
+        throw new Error("spyOn could not find an object to spy upon for " + methodName + "()");
+      }
+
+      if (j$.util.isUndefined(obj[methodName])) {
+        throw new Error(methodName + '() method does not exist');
+      }
+
+      if (obj[methodName] && j$.isSpy(obj[methodName])) {
+        //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
+        throw new Error(methodName + ' has already been spied upon');
+      }
+
+      var spy = j$.createSpy(methodName, obj[methodName]);
+
+      spies.push({
+        spy: spy,
+        baseObj: obj,
+        methodName: methodName,
+        originalValue: obj[methodName]
+      });
+
+      obj[methodName] = spy;
+
+      return spy;
+    };
+
+    var suiteFactory = function(description) {
+      var suite = new j$.Suite({
+        env: self,
+        id: getNextSuiteId(),
+        description: description,
+        parentSuite: currentSuite,
+        queueRunner: queueRunnerFactory,
+        onStart: suiteStarted,
+        resultCallback: function(attrs) {
+          reporter.suiteDone(attrs);
+        }
+      });
+
+      runnableLookupTable[suite.id] = suite;
+      return suite;
+    };
+
+    this.describe = function(description, specDefinitions) {
+      var suite = suiteFactory(description);
+
+      var parentSuite = currentSuite;
+      parentSuite.addChild(suite);
+      currentSuite = suite;
+
+      var declarationError = null;
+      try {
+        specDefinitions.call(suite);
+      } catch (e) {
+        declarationError = e;
+      }
+
+      if (declarationError) {
+        this.it("encountered a declaration exception", function() {
+          throw declarationError;
+        });
+      }
+
+      currentSuite = parentSuite;
+
+      return suite;
+    };
+
+    this.xdescribe = function(description, specDefinitions) {
+      var suite = this.describe(description, specDefinitions);
+      suite.disable();
+      return suite;
+    };
+
+    var specFactory = function(description, fn, suite) {
+      totalSpecsDefined++;
+
+      var spec = new j$.Spec({
+        id: getNextSpecId(),
+        beforeFns: beforeFns(suite),
+        afterFns: afterFns(suite),
+        expectationFactory: expectationFactory,
+        exceptionFormatter: exceptionFormatter,
+        resultCallback: specResultCallback,
+        getSpecName: function(spec) {
+          return getSpecName(spec, suite);
+        },
+        onStart: specStarted,
+        description: description,
+        expectationResultFactory: expectationResultFactory,
+        queueRunnerFactory: queueRunnerFactory,
+        fn: fn,
+        timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
+      });
+
+      runnableLookupTable[spec.id] = spec;
+
+      if (!self.specFilter(spec)) {
+        spec.disable();
+      }
+
+      return spec;
+
+      function removeAllSpies() {
+        for (var i = 0; i < spies.length; i++) {
+          var spyEntry = spies[i];
+          spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
+        }
+        spies = [];
+      }
+
+      function specResultCallback(result) {
+        removeAllSpies();
+        j$.Expectation.resetMatchers();
+        customEqualityTesters = [];
+        currentSpec = null;
+        reporter.specDone(result);
+      }
+    };
+
+    var suiteStarted = function(suite) {
+      reporter.suiteStarted(suite.result);
+    };
+
+    this.it = function(description, fn) {
+      var spec = specFactory(description, fn, currentSuite);
+      currentSuite.addChild(spec);
+      return spec;
+    };
+
+    this.xit = function(description, fn) {
+      var spec = this.it(description, fn);
+      spec.pend();
+      return spec;
+    };
+
+    this.expect = function(actual) {
+      return currentSpec.expect(actual);
+    };
+
+    this.beforeEach = function(beforeEachFunction) {
+      currentSuite.beforeEach(beforeEachFunction);
+    };
+
+    this.afterEach = function(afterEachFunction) {
+      currentSuite.afterEach(afterEachFunction);
+    };
+
+    this.pending = function() {
+      throw j$.Spec.pendingSpecExceptionMessage;
+    };
+  }
+
+  return Env;
+};
+
+getJasmineRequireObj().JsApiReporter = function() {
+
+  var noopTimer = {
+    start: function(){},
+    elapsed: function(){ return 0; }
+  };
+
+  function JsApiReporter(options) {
+    var timer = options.timer || noopTimer,
+        status = "loaded";
+
+    this.started = false;
+    this.finished = false;
+
+    this.jasmineStarted = function() {
+      this.started = true;
+      status = 'started';
+      timer.start();
+    };
+
+    var executionTime;
+
+    this.jasmineDone = function() {
+      this.finished = true;
+      executionTime = timer.elapsed();
+      status = 'done';
+    };
+
+    this.status = function() {
+      return status;
+    };
+
+    var suites = {};
+
+    this.suiteStarted = function(result) {
+      storeSuite(result);
+    };
+
+    this.suiteDone = function(result) {
+      storeSuite(result);
+    };
+
+    function storeSuite(result) {
+      suites[result.id] = result;
+    }
+
+    this.suites = function() {
+      return suites;
+    };
+
+    var specs = [];
+    this.specStarted = function(result) { };
+
+    this.specDone = function(result) {
+      specs.push(result);
+    };
+
+    this.specResults = function(index, length) {
+      return specs.slice(index, index + length);
+    };
+
+    this.specs = function() {
+      return specs;
+    };
+
+    this.executionTime = function() {
+      return executionTime;
+    };
+
+  }
+
+  return JsApiReporter;
+};
+
+getJasmineRequireObj().Any = function() {
+
+  function Any(expectedObject) {
+    this.expectedObject = expectedObject;
+  }
+
+  Any.prototype.jasmineMatches = function(other) {
+    if (this.expectedObject == String) {
+      return typeof other == 'string' || other instanceof String;
+    }
+
+    if (this.expectedObject == Number) {
+      return typeof other == 'number' || other instanceof Number;
+    }
+
+    if (this.expectedObject == Function) {
+      return typeof other == 'function' || other instanceof Function;
+    }
+
+    if (this.expectedObject == Object) {
+      return typeof other == 'object';
+    }
+    
+    if (this.expectedObject == Boolean) {
+      return typeof other == 'boolean';
+    }
+
+    return other instanceof this.expectedObject;
+  };
+
+  Any.prototype.jasmineToString = function() {
+    return '<jasmine.any(' + this.expectedClass + ')>';
+  };
+
+  return Any;
+};
+
+getJasmineRequireObj().CallTracker = function() {
+
+  function CallTracker() {
+    var calls = [];
+
+    this.track = function(context) {
+      calls.push(context);
+    };
+
+    this.any = function() {
+      return !!calls.length;
+    };
+
+    this.count = function() {
+      return calls.length;
+    };
+
+    this.argsFor = function(index) {
+      var call = calls[index];
+      return call ? call.args : [];
+    };
+
+    this.all = function() {
+      return calls;
+    };
+
+    this.allArgs = function() {
+      var callArgs = [];
+      for(var i = 0; i < calls.length; i++){
+        callArgs.push(calls[i].args);
+      }
+
+      return callArgs;
+    };
+
+    this.first = function() {
+      return calls[0];
+    };
+
+    this.mostRecent = function() {
+      return calls[calls.length - 1];
+    };
+
+    this.reset = function() {
+      calls = [];
+    };
+  }
+
+  return CallTracker;
+};
+
+getJasmineRequireObj().Clock = function() {
+  function Clock(global, delayedFunctionScheduler) {
+    var self = this,
+      realTimingFunctions = {
+        setTimeout: global.setTimeout,
+        clearTimeout: global.clearTimeout,
+        setInterval: global.setInterval,
+        clearInterval: global.clearInterval
+      },
+      fakeTimingFunctions = {
+        setTimeout: setTimeout,
+        clearTimeout: clearTimeout,
+        setInterval: setInterval,
+        clearInterval: clearInterval
+      },
+      installed = false,
+      timer;
+
+    self.install = function() {
+      replace(global, fakeTimingFunctions);
+      timer = fakeTimingFunctions;
+      installed = true;
+    };
+
+    self.uninstall = function() {
+      delayedFunctionScheduler.reset();
+      replace(global, realTimingFunctions);
+      timer = realTimingFunctions;
+      installed = false;
+    };
+
+    self.setTimeout = function(fn, delay, params) {
+      if (legacyIE()) {
+        if (arguments.length > 2) {
+          throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill");
+        }
+        return timer.setTimeout(fn, delay);
+      }
+      return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]);
+    };
+
+    self.setInterval = function(fn, delay, params) {
+      if (legacyIE()) {
+        if (arguments.length > 2) {
+          throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill");
+        }
+        return timer.setInterval(fn, delay);
+      }
+      return Function.prototype.apply.apply(timer.setInterval, [global, arguments]);
+    };
+
+    self.clearTimeout = function(id) {
+      return Function.prototype.call.apply(timer.clearTimeout, [global, id]);
+    };
+
+    self.clearInterval = function(id) {
+      return Function.prototype.call.apply(timer.clearInterval, [global, id]);
+    };
+
+    self.tick = function(millis) {
+      if (installed) {
+        delayedFunctionScheduler.tick(millis);
+      } else {
+        throw new Error("Mock clock is not installed, use jasmine.clock().install()");
+      }
+    };
+
+    return self;
+
+    function legacyIE() {
+      //if these methods are polyfilled, apply will be present
+      return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply;
+    }
+
+    function replace(dest, source) {
+      for (var prop in source) {
+        dest[prop] = source[prop];
+      }
+    }
+
+    function setTimeout(fn, delay) {
+      return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
+    }
+
+    function clearTimeout(id) {
+      return delayedFunctionScheduler.removeFunctionWithId(id);
+    }
+
+    function setInterval(fn, interval) {
+      return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
+    }
+
+    function clearInterval(id) {
+      return delayedFunctionScheduler.removeFunctionWithId(id);
+    }
+
+    function argSlice(argsObj, n) {
+      return Array.prototype.slice.call(argsObj, 2);
+    }
+  }
+
+  return Clock;
+};
+
+getJasmineRequireObj().DelayedFunctionScheduler = function() {
+  function DelayedFunctionScheduler() {
+    var self = this;
+    var scheduledLookup = [];
+    var scheduledFunctions = {};
+    var currentTime = 0;
+    var delayedFnCount = 0;
+
+    self.tick = function(millis) {
+      millis = millis || 0;
+      var endTime = currentTime + millis;
+
+      runScheduledFunctions(endTime);
+      currentTime = endTime;
+    };
+
+    self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
+      var f;
+      if (typeof(funcToCall) === 'string') {
+        /* jshint evil: true */
+        f = function() { return eval(funcToCall); };
+        /* jshint evil: false */
+      } else {
+        f = funcToCall;
+      }
+
+      millis = millis || 0;
+      timeoutKey = timeoutKey || ++delayedFnCount;
+      runAtMillis = runAtMillis || (currentTime + millis);
+
+      var funcToSchedule = {
+        runAtMillis: runAtMillis,
+        funcToCall: f,
+        recurring: recurring,
+        params: params,
+        timeoutKey: timeoutKey,
+        millis: millis
+      };
+
+      if (runAtMillis in scheduledFunctions) {
+        scheduledFunctions[runAtMillis].push(funcToSchedule);
+      } else {
+        scheduledFunctions[runAtMillis] = [funcToSchedule];
+        scheduledLookup.push(runAtMillis);
+        scheduledLookup.sort(function (a, b) {
+          return a - b;
+        });
+      }
+
+      return timeoutKey;
+    };
+
+    self.removeFunctionWithId = function(timeoutKey) {
+      for (var runAtMillis in scheduledFunctions) {
+        var funcs = scheduledFunctions[runAtMillis];
+        var i = indexOfFirstToPass(funcs, function (func) {
+          return func.timeoutKey === timeoutKey;
+        });
+
+        if (i > -1) {
+          if (funcs.length === 1) {
+            delete scheduledFunctions[runAtMillis];
+            deleteFromLookup(runAtMillis);
+          } else {
+            funcs.splice(i, 1);
+          }
+
+          // intervals get rescheduled when executed, so there's never more
+          // than a single scheduled function with a given timeoutKey
+          break;
+        }
+      }
+    };
+
+    self.reset = function() {
+      currentTime = 0;
+      scheduledLookup = [];
+      scheduledFunctions = {};
+      delayedFnCount = 0;
+    };
+
+    return self;
+
+    function indexOfFirstToPass(array, testFn) {
+      var index = -1;
+
+      for (var i = 0; i < array.length; ++i) {
+        if (testFn(array[i])) {
+          index = i;
+          break;
+        }
+      }
+
+      return index;
+    }
+
+    function deleteFromLookup(key) {
+      var value = Number(key);
+      var i = indexOfFirstToPass(scheduledLookup, function (millis) {
+        return millis === value;
+      });
+
+      if (i > -1) {
+        scheduledLookup.splice(i, 1);
+      }
+    }
+
+    function reschedule(scheduledFn) {
+      self.scheduleFunction(scheduledFn.funcToCall,
+        scheduledFn.millis,
+        scheduledFn.params,
+        true,
+        scheduledFn.timeoutKey,
+        scheduledFn.runAtMillis + scheduledFn.millis);
+    }
+
+    function runScheduledFunctions(endTime) {
+      if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
+        return;
+      }
+
+      do {
+        currentTime = scheduledLookup.shift();
+
+        var funcsToRun = scheduledFunctions[currentTime];
+        delete scheduledFunctions[currentTime];
+
+        for (var i = 0; i < funcsToRun.length; ++i) {
+          var funcToRun = funcsToRun[i];
+          funcToRun.funcToCall.apply(null, funcToRun.params || []);
+
+          if (funcToRun.recurring) {
+            reschedule(funcToRun);
+          }
+        }
+      } while (scheduledLookup.length > 0 &&
+              // checking first if we're out of time prevents setTimeout(0)
+              // scheduled in a funcToRun from forcing an extra iteration
+                 currentTime !== endTime  &&
+                 scheduledLookup[0] <= endTime);
+    }
+  }
+
+  return DelayedFunctionScheduler;
+};
+
+getJasmineRequireObj().ExceptionFormatter = function() {
+  function ExceptionFormatter() {
+    this.message = function(error) {
+      var message = error.name +
+        ': ' +
+        error.message;
+
+      if (error.fileName || error.sourceURL) {
+        message += " in " + (error.fileName || error.sourceURL);
+      }
+
+      if (error.line || error.lineNumber) {
+        message += " (line " + (error.line || error.lineNumber) + ")";
+      }
+
+      return message;
+    };
+
+    this.stack = function(error) {
+      return error ? error.stack : null;
+    };
+  }
+
+  return ExceptionFormatter;
+};
+
+getJasmineRequireObj().Expectation = function() {
+
+  var matchers = {};
+
+  function Expectation(options) {
+    this.util = options.util || { buildFailureMessage: function() {} };
+    this.customEqualityTesters = options.customEqualityTesters || [];
+    this.actual = options.actual;
+    this.addExpectationResult = options.addExpectationResult || function(){};
+    this.isNot = options.isNot;
+
+    for (var matcherName in matchers) {
+      this[matcherName] = matchers[matcherName];
+    }
+  }
+
+  Expectation.prototype.wrapCompare = function(name, matcherFactory) {
+    return function() {
+      var args = Array.prototype.slice.call(arguments, 0),
+        expected = args.slice(0),
+        message = "";
+
+      args.unshift(this.actual);
+
+      var matcher = matcherFactory(this.util, this.customEqualityTesters),
+          matcherCompare = matcher.compare;
+
+      function defaultNegativeCompare() {
+        var result = matcher.compare.apply(null, args);
+        result.pass = !result.pass;
+        return result;
+      }
+
+      if (this.isNot) {
+        matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
+      }
+
+      var result = matcherCompare.apply(null, args);
+
+      if (!result.pass) {
+        if (!result.message) {
+          args.unshift(this.isNot);
+          args.unshift(name);
+          message = this.util.buildFailureMessage.apply(null, args);
+        } else {
+          message = result.message;
+        }
+      }
+
+      if (expected.length == 1) {
+        expected = expected[0];
+      }
+
+      // TODO: how many of these params are needed?
+      this.addExpectationResult(
+        result.pass,
+        {
+          matcherName: name,
+          passed: result.pass,
+          message: message,
+          actual: this.actual,
+          expected: expected // TODO: this may need to be arrayified/sliced
+        }
+      );
+    };
+  };
+
+  Expectation.addCoreMatchers = function(matchers) {
+    var prototype = Expectation.prototype;
+    for (var matcherName in matchers) {
+      var matcher = matchers[matcherName];
+      prototype[matcherName] = prototype.wrapCompare(matcherName, matcher);
+    }
+  };
+
+  Expectation.addMatchers = function(matchersToAdd) {
+    for (var name in matchersToAdd) {
+      var matcher = matchersToAdd[name];
+      matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
+    }
+  };
+
+  Expectation.resetMatchers = function() {
+    for (var name in matchers) {
+      delete matchers[name];
+    }
+  };
+
+  Expectation.Factory = function(options) {
+    options = options || {};
+
+    var expect = new Expectation(options);
+
+    // TODO: this would be nice as its own Object - NegativeExpectation
+    // TODO: copy instead of mutate options
+    options.isNot = true;
+    expect.not = new Expectation(options);
+
+    return expect;
+  };
+
+  return Expectation;
+};
+
+//TODO: expectation result may make more sense as a presentation of an expectation.
+getJasmineRequireObj().buildExpectationResult = function() {
+  function buildExpectationResult(options) {
+    var messageFormatter = options.messageFormatter || function() {},
+      stackFormatter = options.stackFormatter || function() {};
+
+    return {
+      matcherName: options.matcherName,
+      expected: options.expected,
+      actual: options.actual,
+      message: message(),
+      stack: stack(),
+      passed: options.passed
+    };
+
+    function message() {
+      if (options.passed) {
+        return "Passed.";
+      } else if (options.message) {
+        return options.message;
+      } else if (options.error) {
+        return messageFormatter(options.error);
+      }
+      return "";
+    }
+
+    function stack() {
+      if (options.passed) {
+        return "";
+      }
+
+      var error = options.error;
+      if (!error) {
+        try {
+          throw new Error(message());
+        } catch (e) {
+          error = e;
+        }
+      }
+      return stackFormatter(error);
+    }
+  }
+
+  return buildExpectationResult;
+};
+
+getJasmineRequireObj().ObjectContaining = function(j$) {
+
+  function ObjectContaining(sample) {
+    this.sample = sample;
+  }
+
+  ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
+    if (typeof(this.sample) !== "object") { throw new Error("You must provide an object to objectContaining, not '"+this.sample+"'."); }
+
+    mismatchKeys = mismatchKeys || [];
+    mismatchValues = mismatchValues || [];
+
+    var hasKey = function(obj, keyName) {
+      return obj !== null && !j$.util.isUndefined(obj[keyName]);
+    };
+
+    for (var property in this.sample) {
+      if (!hasKey(other, property) && hasKey(this.sample, property)) {
+        mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+      }
+      else if (!j$.matchersUtil.equals(this.sample[property], other[property])) {
+        mismatchValues.push("'" + property + "' was '" + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + "' in actual, but was '" + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in expected.");
+      }
+    }
+
+    return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+  };
+
+  ObjectContaining.prototype.jasmineToString = function() {
+    return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>";
+  };
+
+  return ObjectContaining;
+};
+
+getJasmineRequireObj().pp = function(j$) {
+
+  function PrettyPrinter() {
+    this.ppNestLevel_ = 0;
+  }
+
+  PrettyPrinter.prototype.format = function(value) {
+    this.ppNestLevel_++;
+    try {
+      if (j$.util.isUndefined(value)) {
+        this.emitScalar('undefined');
+      } else if (value === null) {
+        this.emitScalar('null');
+      } else if (value === j$.getGlobal()) {
+        this.emitScalar('<global>');
+      } else if (value.jasmineToString) {
+        this.emitScalar(value.jasmineToString());
+      } else if (typeof value === 'string') {
+        this.emitString(value);
+      } else if (j$.isSpy(value)) {
+        this.emitScalar("spy on " + value.and.identity());
+      } else if (value instanceof RegExp) {
+        this.emitScalar(value.toString());
+      } else if (typeof value === 'function') {
+        this.emitScalar('Function');
+      } else if (typeof value.nodeType === 'number') {
+        this.emitScalar('HTMLNode');
+      } else if (value instanceof Date) {
+        this.emitScalar('Date(' + value + ')');
+      } else if (value.__Jasmine_been_here_before__) {
+        this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
+      } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
+        value.__Jasmine_been_here_before__ = true;
+        if (j$.isArray_(value)) {
+          this.emitArray(value);
+        } else {
+          this.emitObject(value);
+        }
+        delete value.__Jasmine_been_here_before__;
+      } else {
+        this.emitScalar(value.toString());
+      }
+    } finally {
+      this.ppNestLevel_--;
+    }
+  };
+
+  PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+    for (var property in obj) {
+      if (!obj.hasOwnProperty(property)) { continue; }
+      if (property == '__Jasmine_been_here_before__') { continue; }
+      fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
+          obj.__lookupGetter__(property) !== null) : false);
+    }
+  };
+
+  PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
+  PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
+  PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
+  PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
+
+  function StringPrettyPrinter() {
+    PrettyPrinter.call(this);
+
+    this.string = '';
+  }
+
+  j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
+
+  StringPrettyPrinter.prototype.emitScalar = function(value) {
+    this.append(value);
+  };
+
+  StringPrettyPrinter.prototype.emitString = function(value) {
+    this.append("'" + value + "'");
+  };
+
+  StringPrettyPrinter.prototype.emitArray = function(array) {
+    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+      this.append("Array");
+      return;
+    }
+
+    this.append('[ ');
+    for (var i = 0; i < array.length; i++) {
+      if (i > 0) {
+        this.append(', ');
+      }
+      this.format(array[i]);
+    }
+    this.append(' ]');
+  };
+
+  StringPrettyPrinter.prototype.emitObject = function(obj) {
+    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+      this.append("Object");
+      return;
+    }
+
+    var self = this;
+    this.append('{ ');
+    var first = true;
+
+    this.iterateObject(obj, function(property, isGetter) {
+      if (first) {
+        first = false;
+      } else {
+        self.append(', ');
+      }
+
+      self.append(property);
+      self.append(' : ');
+      if (isGetter) {
+        self.append('<getter>');
+      } else {
+        self.format(obj[property]);
+      }
+    });
+
+    this.append(' }');
+  };
+
+  StringPrettyPrinter.prototype.append = function(value) {
+    this.string += value;
+  };
+
+  return function(value) {
+    var stringPrettyPrinter = new StringPrettyPrinter();
+    stringPrettyPrinter.format(value);
+    return stringPrettyPrinter.string;
+  };
+};
+
+getJasmineRequireObj().QueueRunner = function() {
+
+  function QueueRunner(attrs) {
+    this.fns = attrs.fns || [];
+    this.onComplete = attrs.onComplete || function() {};
+    this.clearStack = attrs.clearStack || function(fn) {fn();};
+    this.onException = attrs.onException || function() {};
+    this.catchException = attrs.catchException || function() { return true; };
+    this.userContext = {};
+  }
+
+  QueueRunner.prototype.execute = function() {
+    this.run(this.fns, 0);
+  };
+
+  QueueRunner.prototype.run = function(fns, recursiveIndex) {
+    var length = fns.length,
+        self = this,
+        iterativeIndex;
+
+    for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
+      var fn = fns[iterativeIndex];
+      if (fn.length > 0) {
+        return attemptAsync(fn);
+      } else {
+        attemptSync(fn);
+      }
+    }
+
+    var runnerDone = iterativeIndex >= length;
+
+    if (runnerDone) {
+      this.clearStack(this.onComplete);
+    }
+
+    function attemptSync(fn) {
+      try {
+        fn.call(self.userContext);
+      } catch (e) {
+        handleException(e);
+      }
+    }
+
+    function attemptAsync(fn) {
+      var next = function () { self.run(fns, iterativeIndex + 1); };
+
+      try {
+        fn.call(self.userContext, next);
+      } catch (e) {
+        handleException(e);
+        next();
+      }
+    }
+
+    function handleException(e) {
+      self.onException(e);
+      if (!self.catchException(e)) {
+        //TODO: set a var when we catch an exception and
+        //use a finally block to close the loop in a nice way..
+        throw e;
+      }
+    }
+  };
+
+  return QueueRunner;
+};
+
+getJasmineRequireObj().ReportDispatcher = function() {
+  function ReportDispatcher(methods) {
+
+    var dispatchedMethods = methods || [];
+
+    for (var i = 0; i < dispatchedMethods.length; i++) {
+      var method = dispatchedMethods[i];
+      this[method] = (function(m) {
+        return function() {
+          dispatch(m, arguments);
+        };
+      }(method));
+    }
+
+    var reporters = [];
+
+    this.addReporter = function(reporter) {
+      reporters.push(reporter);
+    };
+
+    return this;
+
+    function dispatch(method, args) {
+      for (var i = 0; i < reporters.length; i++) {
+        var reporter = reporters[i];
+        if (reporter[method]) {
+          reporter[method].apply(reporter, args);
+        }
+      }
+    }
+  }
+
+  return ReportDispatcher;
+};
+
+
+getJasmineRequireObj().SpyStrategy = function() {
+
+  function SpyStrategy(options) {
+    options = options || {};
+
+    var identity = options.name || "unknown",
+        originalFn = options.fn || function() {},
+        getSpy = options.getSpy || function() {},
+        plan = function() {};
+
+    this.identity = function() {
+      return identity;
+    };
+
+    this.exec = function() {
+      return plan.apply(this, arguments);
+    };
+
+    this.callThrough = function() {
+      plan = originalFn;
+      return getSpy();
+    };
+
+    this.returnValue = function(value) {
+      plan = function() {
+        return value;
+      };
+      return getSpy();
+    };
+
+    this.throwError = function(something) {
+      var error = (something instanceof Error) ? something : new Error(something);
+      plan = function() {
+        throw error;
+      };
+      return getSpy();
+    };
+
+    this.callFake = function(fn) {
+      plan = fn;
+      return getSpy();
+    };
+
+    this.stub = function(fn) {
+      plan = function() {};
+      return getSpy();
+    };
+  }
+
+  return SpyStrategy;
+};
+
+getJasmineRequireObj().Suite = function() {
+  function Suite(attrs) {
+    this.env = attrs.env;
+    this.id = attrs.id;
+    this.parentSuite = attrs.parentSuite;
+    this.description = attrs.description;
+    this.onStart = attrs.onStart || function() {};
+    this.resultCallback = attrs.resultCallback || function() {};
+    this.clearStack = attrs.clearStack || function(fn) {fn();};
+
+    this.beforeFns = [];
+    this.afterFns = [];
+    this.queueRunner = attrs.queueRunner || function() {};
+    this.disabled = false;
+
+    this.children = [];
+
+    this.result = {
+      id: this.id,
+      status: this.disabled ? 'disabled' : '',
+      description: this.description,
+      fullName: this.getFullName()
+    };
+  }
+
+  Suite.prototype.getFullName = function() {
+    var fullName = this.description;
+    for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+      if (parentSuite.parentSuite) {
+        fullName = parentSuite.description + ' ' + fullName;
+      }
+    }
+    return fullName;
+  };
+
+  Suite.prototype.disable = function() {
+    this.disabled = true;
+  };
+
+  Suite.prototype.beforeEach = function(fn) {
+    this.beforeFns.unshift(fn);
+  };
+
+  Suite.prototype.afterEach = function(fn) {
+    this.afterFns.unshift(fn);
+  };
+
+  Suite.prototype.addChild = function(child) {
+    this.children.push(child);
+  };
+
+  Suite.prototype.execute = function(onComplete) {
+    var self = this;
+    if (this.disabled) {
+      complete();
+      return;
+    }
+
+    var allFns = [];
+
+    for (var i = 0; i < this.children.length; i++) {
+      allFns.push(wrapChildAsAsync(this.children[i]));
+    }
+
+    this.onStart(this);
+
+    this.queueRunner({
+      fns: allFns,
+      onComplete: complete
+    });
+
+    function complete() {
+      self.resultCallback(self.result);
+
+      if (onComplete) {
+        onComplete();
+      }
+    }
+
+    function wrapChildAsAsync(child) {
+      return function(done) { child.execute(done); };
+    }
+  };
+
+  return Suite;
+};
+
+if (typeof window == void 0 && typeof exports == "object") {
+  exports.Suite = jasmineRequire.Suite;
+}
+
+getJasmineRequireObj().Timer = function() {
+  function Timer(options) {
+    options = options || {};
+
+    var now = options.now || function() { return new Date().getTime(); },
+        startTime;
+
+    this.start = function() {
+      startTime = now();
+    };
+
+    this.elapsed = function() {
+      return now() - startTime;
+    };
+  }
+
+  return Timer;
+};
+
+getJasmineRequireObj().matchersUtil = function(j$) {
+  // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
+
+  return {
+    equals: function(a, b, customTesters) {
+      customTesters = customTesters || [];
+
+      return eq(a, b, [], [], customTesters);
+    },
+
+    contains: function(haystack, needle, customTesters) {
+      customTesters = customTesters || [];
+
+      if (Object.prototype.toString.apply(haystack) === "[object Array]") {
+        for (var i = 0; i < haystack.length; i++) {
+          if (eq(haystack[i], needle, [], [], customTesters)) {
+            return true;
+          }
+        }
+        return false;
+      }
+      return haystack.indexOf(needle) >= 0;
+    },
+
+    buildFailureMessage: function() {
+      var args = Array.prototype.slice.call(arguments, 0),
+        matcherName = args[0],
+        isNot = args[1],
+        actual = args[2],
+        expected = args.slice(3),
+        englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+
+      var message = "Expected " +
+        j$.pp(actual) +
+        (isNot ? " not " : " ") +
+        englishyPredicate;
+
+      if (expected.length > 0) {
+        for (var i = 0; i < expected.length; i++) {
+          if (i > 0) {
+            message += ",";
+          }
+          message += " " + j$.pp(expected[i]);
+        }
+      }
+
+      return message + ".";
+    }
+  };
+
+  // Equality function lovingly adapted from isEqual in
+  //   [Underscore](http://underscorejs.org)
+  function eq(a, b, aStack, bStack, customTesters) {
+    var result = true;
+
+    for (var i = 0; i < customTesters.length; i++) {
+      var customTesterResult = customTesters[i](a, b);
+      if (!j$.util.isUndefined(customTesterResult)) {
+        return customTesterResult;
+      }
+    }
+
+    if (a instanceof j$.Any) {
+      result = a.jasmineMatches(b);
+      if (result) {
+        return true;
+      }
+    }
+
+    if (b instanceof j$.Any) {
+      result = b.jasmineMatches(a);
+      if (result) {
+        return true;
+      }
+    }
+
+    if (b instanceof j$.ObjectContaining) {
+      result = b.jasmineMatches(a);
+      if (result) {
+        return true;
+      }
+    }
+
+    if (a instanceof Error && b instanceof Error) {
+      return a.message == b.message;
+    }
+
+    // Identical objects are equal. `0 === -0`, but they aren't identical.
+    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+    if (a === b) { return a !== 0 || 1 / a == 1 / b; }
+    // A strict comparison is necessary because `null == undefined`.
+    if (a === null || b === null) { return a === b; }
+    var className = Object.prototype.toString.call(a);
+    if (className != Object.prototype.toString.call(b)) { return false; }
+    switch (className) {
+      // Strings, numbers, dates, and booleans are compared by value.
+      case '[object String]':
+        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+        // equivalent to `new String("5")`.
+        return a == String(b);
+      case '[object Number]':
+        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
+        // other numeric values.
+        return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
+      case '[object Date]':
+      case '[object Boolean]':
+        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+        // millisecond representations. Note that invalid dates with millisecond representations
+        // of `NaN` are not equivalent.
+        return +a == +b;
+      // RegExps are compared by their source patterns and flags.
+      case '[object RegExp]':
+        return a.source == b.source &&
+          a.global == b.global &&
+          a.multiline == b.multiline &&
+          a.ignoreCase == b.ignoreCase;
+    }
+    if (typeof a != 'object' || typeof b != 'object') { return false; }
+    // Assume equality for cyclic structures. The algorithm for detecting cyclic
+    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+    var length = aStack.length;
+    while (length--) {
+      // Linear search. Performance is inversely proportional to the number of
+      // unique nested structures.
+      if (aStack[length] == a) { return bStack[length] == b; }
+    }
+    // Add the first object to the stack of traversed objects.
+    aStack.push(a);
+    bStack.push(b);
+    var size = 0;
+    // Recursively compare objects and arrays.
+    if (className == '[object Array]') {
+      // Compare array lengths to determine if a deep comparison is necessary.
+      size = a.length;
+      result = size == b.length;
+      if (result) {
+        // Deep compare the contents, ignoring non-numeric properties.
+        while (size--) {
+          if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) { break; }
+        }
+      }
+    } else {
+      // Objects with different constructors are not equivalent, but `Object`s
+      // from different frames are.
+      var aCtor = a.constructor, bCtor = b.constructor;
+      if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) &&
+        isFunction(bCtor) && (bCtor instanceof bCtor))) {
+        return false;
+      }
+      // Deep compare objects.
+      for (var key in a) {
+        if (has(a, key)) {
+          // Count the expected number of properties.
+          size++;
+          // Deep compare each member.
+          if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; }
+        }
+      }
+      // Ensure that both objects contain the same number of properties.
+      if (result) {
+        for (key in b) {
+          if (has(b, key) && !(size--)) { break; }
+        }
+        result = !size;
+      }
+    }
+    // Remove the first object from the stack of traversed objects.
+    aStack.pop();
+    bStack.pop();
+
+    return result;
+
+    function has(obj, key) {
+      return obj.hasOwnProperty(key);
+    }
+
+    function isFunction(obj) {
+      return typeof obj === 'function';
+    }
+  }
+};
+
+getJasmineRequireObj().toBe = function() {
+  function toBe() {
+    return {
+      compare: function(actual, expected) {
+        return {
+          pass: actual === expected
+        };
+      }
+    };
+  }
+
+  return toBe;
+};
+
+getJasmineRequireObj().toBeCloseTo = function() {
+
+  function toBeCloseTo() {
+    return {
+      compare: function(actual, expected, precision) {
+        if (precision !== 0) {
+          precision = precision || 2;
+        }
+
+        return {
+          pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
+        };
+      }
+    };
+  }
+
+  return toBeCloseTo;
+};
+
+getJasmineRequireObj().toBeDefined = function() {
+  function toBeDefined() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: (void 0 !== actual)
+        };
+      }
+    };
+  }
+
+  return toBeDefined;
+};
+
+getJasmineRequireObj().toBeFalsy = function() {
+  function toBeFalsy() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: !!!actual
+        };
+      }
+    };
+  }
+
+  return toBeFalsy;
+};
+
+getJasmineRequireObj().toBeGreaterThan = function() {
+
+  function toBeGreaterThan() {
+    return {
+      compare: function(actual, expected) {
+        return {
+          pass: actual > expected
+        };
+      }
+    };
+  }
+
+  return toBeGreaterThan;
+};
+
+
+getJasmineRequireObj().toBeLessThan = function() {
+  function toBeLessThan() {
+    return {
+
+      compare: function(actual, expected) {
+        return {
+          pass: actual < expected
+        };
+      }
+    };
+  }
+
+  return toBeLessThan;
+};
+getJasmineRequireObj().toBeNaN = function(j$) {
+
+  function toBeNaN() {
+    return {
+      compare: function(actual) {
+        var result = {
+          pass: (actual !== actual)
+        };
+
+        if (result.pass) {
+          result.message = "Expected actual not to be NaN.";
+        } else {
+          result.message = "Expected " + j$.pp(actual) + " to be NaN.";
+        }
+
+        return result;
+      }
+    };
+  }
+
+  return toBeNaN;
+};
+
+getJasmineRequireObj().toBeNull = function() {
+
+  function toBeNull() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: actual === null
+        };
+      }
+    };
+  }
+
+  return toBeNull;
+};
+
+getJasmineRequireObj().toBeTruthy = function() {
+
+  function toBeTruthy() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: !!actual
+        };
+      }
+    };
+  }
+
+  return toBeTruthy;
+};
+
+getJasmineRequireObj().toBeUndefined = function() {
+
+  function toBeUndefined() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: void 0 === actual
+        };
+      }
+    };
+  }
+
+  return toBeUndefined;
+};
+
+getJasmineRequireObj().toContain = function() {
+  function toContain(util, customEqualityTesters) {
+    customEqualityTesters = customEqualityTesters || [];
+
+    return {
+      compare: function(actual, expected) {
+
+        return {
+          pass: util.contains(actual, expected, customEqualityTesters)
+        };
+      }
+    };
+  }
+
+  return toContain;
+};
+
+getJasmineRequireObj().toEqual = function() {
+
+  function toEqual(util, customEqualityTesters) {
+    customEqualityTesters = customEqualityTesters || [];
+
+    return {
+      compare: function(actual, expected) {
+        var result = {
+          pass: false
+        };
+
+        result.pass = util.equals(actual, expected, customEqualityTesters);
+
+        return result;
+      }
+    };
+  }
+
+  return toEqual;
+};
+
+getJasmineRequireObj().toHaveBeenCalled = function(j$) {
+
+  function toHaveBeenCalled() {
+    return {
+      compare: function(actual) {
+        var result = {};
+
+        if (!j$.isSpy(actual)) {
+          throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
+        }
+
+        if (arguments.length > 1) {
+          throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+        }
+
+        result.pass = actual.calls.any();
+
+        result.message = result.pass ?
+          "Expected spy " + actual.and.identity() + " not to have been called." :
+          "Expected spy " + actual.and.identity() + " to have been called.";
+
+        return result;
+      }
+    };
+  }
+
+  return toHaveBeenCalled;
+};
+
+getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
+
+  function toHaveBeenCalledWith(util) {
+    return {
+      compare: function() {
+        var args = Array.prototype.slice.call(arguments, 0),
+          actual = args[0],
+          expectedArgs = args.slice(1),
+          result = { pass: false };
+
+        if (!j$.isSpy(actual)) {
+          throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
+        }
+
+        if (!actual.calls.any()) {
+          result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but it was never called.";
+          return result;
+        }
+
+        if (util.contains(actual.calls.allArgs(), expectedArgs)) {
+          result.pass = true;
+          result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was.";
+        } else {
+          result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but actual calls were " + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + ".";
+        }
+
+        return result;
+      }
+    };
+  }
+
+  return toHaveBeenCalledWith;
+};
+
+getJasmineRequireObj().toMatch = function() {
+
+  function toMatch() {
+    return {
+      compare: function(actual, expected) {
+        var regexp = new RegExp(expected);
+
+        return {
+          pass: regexp.test(actual)
+        };
+      }
+    };
+  }
+
+  return toMatch;
+};
+
+getJasmineRequireObj().toThrow = function(j$) {
+
+  function toThrow(util) {
+    return {
+      compare: function(actual, expected) {
+        var result = { pass: false },
+          threw = false,
+          thrown;
+
+        if (typeof actual != "function") {
+          throw new Error("Actual is not a Function");
+        }
+
+        try {
+          actual();
+        } catch (e) {
+          threw = true;
+          thrown = e;
+        }
+
+        if (!threw) {
+          result.message = "Expected function to throw an exception.";
+          return result;
+        }
+
+        if (arguments.length == 1) {
+          result.pass = true;
+          result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + ".";
+
+          return result;
+        }
+
+        if (util.equals(thrown, expected)) {
+          result.pass = true;
+          result.message = "Expected function not to throw " + j$.pp(expected) + ".";
+        } else {
+          result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " +  j$.pp(thrown) + ".";
+        }
+
+        return result;
+      }
+    };
+  }
+
+  return toThrow;
+};
+
+getJasmineRequireObj().toThrowError = function(j$) {
+  function toThrowError (util) {
+    return {
+      compare: function(actual) {
+        var threw = false,
+          thrown,
+          errorType,
+          message,
+          regexp,
+          name,
+          constructorName;
+
+        if (typeof actual != "function") {
+          throw new Error("Actual is not a Function");
+        }
+
+        extractExpectedParams.apply(null, arguments);
+
+        try {
+          actual();
+        } catch (e) {
+          threw = true;
+          thrown = e;
+        }
+
+        if (!threw) {
+          return fail("Expected function to throw an Error.");
+        }
+
+        if (!(thrown instanceof Error)) {
+          return fail("Expected function to throw an Error, but it threw " + thrown + ".");
+        }
+
+        if (arguments.length == 1) {
+          return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + ".");
+        }
+
+        if (errorType) {
+          name = fnNameFor(errorType);
+          constructorName = fnNameFor(thrown.constructor);
+        }
+
+        if (errorType && message) {
+          if (thrown.constructor == errorType && util.equals(thrown.message, message)) {
+            return pass("Expected function not to throw " + name + " with message \"" + message + "\".");
+          } else {
+            return fail("Expected function to throw " + name + " with message \"" + message +
+                        "\", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
+          }
+        }
+
+        if (errorType && regexp) {
+          if (thrown.constructor == errorType && regexp.test(thrown.message)) {
+            return pass("Expected function not to throw " + name + " with message matching " + regexp + ".");
+          } else {
+            return fail("Expected function to throw " + name + " with message matching " + regexp +
+                        ", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
+          }
+        }
+
+        if (errorType) {
+          if (thrown.constructor == errorType) {
+            return pass("Expected function not to throw " + name + ".");
+          } else {
+            return fail("Expected function to throw " + name + ", but it threw " + constructorName + ".");
+          }
+        }
+
+        if (message) {
+          if (thrown.message == message) {
+            return pass("Expected function not to throw an exception with message " + j$.pp(message) + ".");
+          } else {
+            return fail("Expected function to throw an exception with message " + j$.pp(message) +
+                        ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
+          }
+        }
+
+        if (regexp) {
+          if (regexp.test(thrown.message)) {
+            return pass("Expected function not to throw an exception with a message matching " + j$.pp(regexp) + ".");
+          } else {
+            return fail("Expected function to throw an exception with a message matching " + j$.pp(regexp) +
+                        ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
+          }
+        }
+
+        function fnNameFor(func) {
+            return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
+        }
+
+        function pass(notMessage) {
+          return {
+            pass: true,
+            message: notMessage
+          };
+        }
+
+        function fail(message) {
+          return {
+            pass: false,
+            message: message
+          };
+        }
+
+        function extractExpectedParams() {
+          if (arguments.length == 1) {
+            return;
+          }
+
+          if (arguments.length == 2) {
+            var expected = arguments[1];
+
+            if (expected instanceof RegExp) {
+              regexp = expected;
+            } else if (typeof expected == "string") {
+              message = expected;
+            } else if (checkForAnErrorType(expected)) {
+              errorType = expected;
+            }
+
+            if (!(errorType || message || regexp)) {
+              throw new Error("Expected is not an Error, string, or RegExp.");
+            }
+          } else {
+            if (checkForAnErrorType(arguments[1])) {
+              errorType = arguments[1];
+            } else {
+              throw new Error("Expected error type is not an Error.");
+            }
+
+            if (arguments[2] instanceof RegExp) {
+              regexp = arguments[2];
+            } else if (typeof arguments[2] == "string") {
+              message = arguments[2];
+            } else {
+              throw new Error("Expected error message is not a string or RegExp.");
+            }
+          }
+        }
+
+        function checkForAnErrorType(type) {
+          if (typeof type !== "function") {
+            return false;
+          }
+
+          var Surrogate = function() {};
+          Surrogate.prototype = type.prototype;
+          return (new Surrogate()) instanceof Error;
+        }
+      }
+    };
+  }
+
+  return toThrowError;
+};
+
+getJasmineRequireObj().version = function() {
+  return "2.0.0";
+};

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine_favicon.png
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine_favicon.png b/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine_favicon.png
new file mode 100755
index 0000000..3562e27
Binary files /dev/null and b/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine_favicon.png differ

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/index.html
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/index.html b/cordova-app-test-harness/www/index.html
index 8a2c566..2d0c2c7 100644
--- a/cordova-app-test-harness/www/index.html
+++ b/cordova-app-test-harness/www/index.html
@@ -5,11 +5,13 @@
     <meta charset="utf-8" />
     <meta name="format-detection" content="telephone=no" />
     <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width" />
+
     <link rel="stylesheet" type="text/css" href="assets/topcoat-0.7.5/css/topcoat-mobile-light.min.css">
-    <link rel="stylesheet" type="text/css" href="assets/jasmine-2.0.0-rc5/jasmine.css" media="screen">
+    <link rel="stylesheet" type="text/css" href="assets/jasmine-2.0.0/jasmine.css" media="screen">
     <link rel="stylesheet" type="text/css" href="main.css" media="screen">
-    <script type="text/javascript" src="assets/jasmine-2.0.0-rc5/jasmine.js"></script>
-    <script type="text/javascript" src="assets/jasmine-2.0.0-rc5/jasmine-html.js"></script>
+
+    <script type="text/javascript" src="assets/jasmine-2.0.0/jasmine.js"></script>
+    <script type="text/javascript" src="assets/jasmine-2.0.0/jasmine-html.js"></script>
     <script type="text/javascript" src="jasmine-jsreporter.js"></script>
     <script type="text/javascript" src="cordova.js"></script>
     <script type="text/javascript" src="main.js"></script>


[3/9] git commit: Adding project files to cordova-app-test-harness

Posted by mm...@apache.org.
Adding project files to cordova-app-test-harness


Project: http://git-wip-us.apache.org/repos/asf/cordova-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-labs/commit/8be3e81e
Tree: http://git-wip-us.apache.org/repos/asf/cordova-labs/tree/8be3e81e
Diff: http://git-wip-us.apache.org/repos/asf/cordova-labs/diff/8be3e81e

Branch: refs/heads/cdvtest
Commit: 8be3e81ecbb05ee5c0510945da93c5963e30ccef
Parents: d0aae3c
Author: Michal Mocny <mm...@gmail.com>
Authored: Tue Apr 22 10:11:58 2014 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Tue Apr 22 10:20:23 2014 -0400

----------------------------------------------------------------------
 cordova-app-test-harness/.gitignore                |  2 ++
 cordova-app-test-harness/config.xml                | 15 +++++++++++++++
 .../hooks/before_prepare/pre-prepare.js            | 17 +++++++++++++++++
 3 files changed, 34 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/8be3e81e/cordova-app-test-harness/.gitignore
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/.gitignore b/cordova-app-test-harness/.gitignore
new file mode 100644
index 0000000..c98dbcd
--- /dev/null
+++ b/cordova-app-test-harness/.gitignore
@@ -0,0 +1,2 @@
+platforms
+plugins

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/8be3e81e/cordova-app-test-harness/config.xml
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/config.xml b/cordova-app-test-harness/config.xml
new file mode 100644
index 0000000..142dae6
--- /dev/null
+++ b/cordova-app-test-harness/config.xml
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="org.apache.cordova.CordovaTests" version="0.1.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>Cordova Tests</name>
+    <description>
+        Cordova Test Runner
+    </description>
+    <author>
+    </author>
+    <content src="index.html" />
+    <access origin="http://www.apache.org/*" />
+    <access origin="https://www.googleapis.com/*" />
+
+    <preference name="fullscreen" value="true" />
+    <preference name="webviewbounce" value="false" />
+</widget>

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/8be3e81e/cordova-app-test-harness/hooks/before_prepare/pre-prepare.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/hooks/before_prepare/pre-prepare.js b/cordova-app-test-harness/hooks/before_prepare/pre-prepare.js
new file mode 100755
index 0000000..d7a1863
--- /dev/null
+++ b/cordova-app-test-harness/hooks/before_prepare/pre-prepare.js
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+if [ -d "plugins/org.apache.cordova.test-framework" ]; then
+  exit
+fi
+
+mkdir -p plugins platforms
+
+cordova platform add android
+cordova platform add ios
+
+cordova plugin add ~/dev/cordova/cordova-labs/cordova-plugin-test-framework
+cordova plugin add ~/dev/cordova/cordova-plugin-device
+cordova plugin add ~/dev/cordova/cordova-plugin-device-motion
+cordova plugin add ~/dev/cordova/cordova-plugin-device-orientation
+cordova plugin add ~/dev/cordova/cordova-plugin-geolocation
+cordova plugin add ~/dev/cordova/cordova-plugin-vibration


[6/9] git commit: replace jasmine rc5 with release version

Posted by mm...@apache.org.
replace jasmine rc5 with release version


Project: http://git-wip-us.apache.org/repos/asf/cordova-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-labs/commit/fce98946
Tree: http://git-wip-us.apache.org/repos/asf/cordova-labs/tree/fce98946
Diff: http://git-wip-us.apache.org/repos/asf/cordova-labs/diff/fce98946

Branch: refs/heads/cdvtest
Commit: fce98946d5ba344531b3fa1c1033f40537e204ae
Parents: 8be3e81
Author: Michal Mocny <mm...@gmail.com>
Authored: Tue Apr 22 10:22:56 2014 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Tue Apr 22 10:23:43 2014 -0400

----------------------------------------------------------------------
 .../www/assets/jasmine-2.0.0-rc5/boot.js        |  181 --
 .../www/assets/jasmine-2.0.0-rc5/console.js     |  160 --
 .../assets/jasmine-2.0.0-rc5/jasmine-html.js    |  359 ---
 .../www/assets/jasmine-2.0.0-rc5/jasmine.css    |   55 -
 .../www/assets/jasmine-2.0.0-rc5/jasmine.js     | 2367 -----------------
 .../jasmine-2.0.0-rc5/jasmine_favicon.png       |  Bin 2057 -> 0 bytes
 .../www/assets/jasmine-2.0.0/boot.js            |  181 ++
 .../www/assets/jasmine-2.0.0/console.js         |  160 ++
 .../www/assets/jasmine-2.0.0/jasmine-html.js    |  359 +++
 .../www/assets/jasmine-2.0.0/jasmine.css        |   55 +
 .../www/assets/jasmine-2.0.0/jasmine.js         | 2401 ++++++++++++++++++
 .../assets/jasmine-2.0.0/jasmine_favicon.png    |  Bin 0 -> 2057 bytes
 cordova-app-test-harness/www/index.html         |    8 +-
 13 files changed, 3161 insertions(+), 3125 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/boot.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/boot.js b/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/boot.js
deleted file mode 100755
index ec8baa0..0000000
--- a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/boot.js
+++ /dev/null
@@ -1,181 +0,0 @@
-/**
- Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
-
- If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
-
- The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
-
- [jasmine-gem]: http://github.com/pivotal/jasmine-gem
- */
-
-(function() {
-
-  /**
-   * ## Require &amp; Instantiate
-   *
-   * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
-   */
-  window.jasmine = jasmineRequire.core(jasmineRequire);
-
-  /**
-   * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
-   */
-  jasmineRequire.html(jasmine);
-
-  /**
-   * Create the Jasmine environment. This is used to run all specs in a project.
-   */
-  var env = jasmine.getEnv();
-
-  /**
-   * ## The Global Interface
-   *
-   * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
-   */
-  var jasmineInterface = {
-    describe: function(description, specDefinitions) {
-      return env.describe(description, specDefinitions);
-    },
-
-    xdescribe: function(description, specDefinitions) {
-      return env.xdescribe(description, specDefinitions);
-    },
-
-    it: function(desc, func) {
-      return env.it(desc, func);
-    },
-
-    xit: function(desc, func) {
-      return env.xit(desc, func);
-    },
-
-    beforeEach: function(beforeEachFunction) {
-      return env.beforeEach(beforeEachFunction);
-    },
-
-    afterEach: function(afterEachFunction) {
-      return env.afterEach(afterEachFunction);
-    },
-
-    expect: function(actual) {
-      return env.expect(actual);
-    },
-
-    pending: function() {
-      return env.pending();
-    },
-
-    spyOn: function(obj, methodName) {
-      return env.spyOn(obj, methodName);
-    },
-
-    jsApiReporter: new jasmine.JsApiReporter({
-      timer: new jasmine.Timer()
-    })
-  };
-
-  /**
-   * Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
-   */
-  if (typeof window == "undefined" && typeof exports == "object") {
-    extend(exports, jasmineInterface);
-  } else {
-    extend(window, jasmineInterface);
-  }
-
-  /**
-   * Expose the interface for adding custom equality testers.
-   */
-  jasmine.addCustomEqualityTester = function(tester) {
-    env.addCustomEqualityTester(tester);
-  };
-
-  /**
-   * Expose the interface for adding custom expectation matchers
-   */
-  jasmine.addMatchers = function(matchers) {
-    return env.addMatchers(matchers);
-  };
-
-  /**
-   * Expose the mock interface for the JavaScript timeout functions
-   */
-  jasmine.clock = function() {
-    return env.clock;
-  };
-
-  /**
-   * ## Runner Parameters
-   *
-   * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
-   */
-
-  var queryString = new jasmine.QueryString({
-    getWindowLocation: function() { return window.location; }
-  });
-
-  var catchingExceptions = queryString.getParam("catch");
-  env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
-
-  /**
-   * ## Reporters
-   * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
-   */
-  var htmlReporter = new jasmine.HtmlReporter({
-    env: env,
-    onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
-    getContainer: function() { return document.body; },
-    createElement: function() { return document.createElement.apply(document, arguments); },
-    createTextNode: function() { return document.createTextNode.apply(document, arguments); },
-    timer: new jasmine.Timer()
-  });
-
-  /**
-   * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results  from JavaScript.
-   */
-  env.addReporter(jasmineInterface.jsApiReporter);
-  env.addReporter(htmlReporter);
-
-  /**
-   * Filter which specs will be run by matching the start of the full name against the `spec` query param.
-   */
-  var specFilter = new jasmine.HtmlSpecFilter({
-    filterString: function() { return queryString.getParam("spec"); }
-  });
-
-  env.specFilter = function(spec) {
-    return specFilter.matches(spec.getFullName());
-  };
-
-  /**
-   * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
-   */
-  window.setTimeout = window.setTimeout;
-  window.setInterval = window.setInterval;
-  window.clearTimeout = window.clearTimeout;
-  window.clearInterval = window.clearInterval;
-
-  /**
-   * ## Execution
-   *
-   * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
-   */
-  var currentWindowOnload = window.onload;
-
-  window.onload = function() {
-    if (currentWindowOnload) {
-      currentWindowOnload();
-    }
-    htmlReporter.initialize();
-    env.execute();
-  };
-
-  /**
-   * Helper function for readability above.
-   */
-  function extend(destination, source) {
-    for (var property in source) destination[property] = source[property];
-    return destination;
-  }
-
-}());

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/console.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/console.js b/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/console.js
deleted file mode 100755
index 0a08f08..0000000
--- a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/console.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
-Copyright (c) 2008-2013 Pivotal Labs
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-function getJasmineRequireObj() {
-  if (typeof module !== "undefined" && module.exports) {
-    return exports;
-  } else {
-    window.jasmineRequire = window.jasmineRequire || {};
-    return window.jasmineRequire;
-  }
-}
-
-getJasmineRequireObj().console = function(jRequire, j$) {
-  j$.ConsoleReporter = jRequire.ConsoleReporter();
-};
-
-getJasmineRequireObj().ConsoleReporter = function() {
-
-  var noopTimer = {
-    start: function(){},
-    elapsed: function(){ return 0; }
-  };
-
-  function ConsoleReporter(options) {
-    var print = options.print,
-      showColors = options.showColors || false,
-      onComplete = options.onComplete || function() {},
-      timer = options.timer || noopTimer,
-      specCount,
-      failureCount,
-      failedSpecs = [],
-      pendingCount,
-      ansi = {
-        green: '\033[32m',
-        red: '\033[31m',
-        yellow: '\033[33m',
-        none: '\033[0m'
-      };
-
-    this.jasmineStarted = function() {
-      specCount = 0;
-      failureCount = 0;
-      pendingCount = 0;
-      print("Started");
-      printNewline();
-      timer.start();
-    };
-
-    this.jasmineDone = function() {
-      printNewline();
-      for (var i = 0; i < failedSpecs.length; i++) {
-        specFailureDetails(failedSpecs[i]);
-      }
-
-      printNewline();
-      var specCounts = specCount + " " + plural("spec", specCount) + ", " +
-        failureCount + " " + plural("failure", failureCount);
-
-      if (pendingCount) {
-        specCounts += ", " + pendingCount + " pending " + plural("spec", pendingCount);
-      }
-
-      print(specCounts);
-
-      printNewline();
-      var seconds = timer.elapsed() / 1000;
-      print("Finished in " + seconds + " " + plural("second", seconds));
-
-      printNewline();
-
-      onComplete(failureCount === 0);
-    };
-
-    this.specDone = function(result) {
-      specCount++;
-
-      if (result.status == "pending") {
-        pendingCount++;
-        print(colored("yellow", "*"));
-        return;
-      }
-
-      if (result.status == "passed") {
-        print(colored("green", '.'));
-        return;
-      }
-
-      if (result.status == "failed") {
-        failureCount++;
-        failedSpecs.push(result);
-        print(colored("red", 'F'));
-      }
-    };
-
-    return this;
-
-    function printNewline() {
-      print("\n");
-    }
-
-    function colored(color, str) {
-      return showColors ? (ansi[color] + str + ansi.none) : str;
-    }
-
-    function plural(str, count) {
-      return count == 1 ? str : str + "s";
-    }
-
-    function repeat(thing, times) {
-      var arr = [];
-      for (var i = 0; i < times; i++) {
-        arr.push(thing);
-      }
-      return arr;
-    }
-
-    function indent(str, spaces) {
-      var lines = (str || '').split("\n");
-      var newArr = [];
-      for (var i = 0; i < lines.length; i++) {
-        newArr.push(repeat(" ", spaces).join("") + lines[i]);
-      }
-      return newArr.join("\n");
-    }
-
-    function specFailureDetails(result) {
-      printNewline();
-      print(result.fullName);
-
-      for (var i = 0; i < result.failedExpectations.length; i++) {
-        var failedExpectation = result.failedExpectations[i];
-        printNewline();
-        print(indent(failedExpectation.stack, 2));
-      }
-
-      printNewline();
-    }
-  }
-
-  return ConsoleReporter;
-};

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine-html.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine-html.js b/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine-html.js
deleted file mode 100755
index 985d0d1..0000000
--- a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine-html.js
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
-Copyright (c) 2008-2013 Pivotal Labs
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-jasmineRequire.html = function(j$) {
-  j$.ResultsNode = jasmineRequire.ResultsNode();
-  j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
-  j$.QueryString = jasmineRequire.QueryString();
-  j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
-};
-
-jasmineRequire.HtmlReporter = function(j$) {
-
-  var noopTimer = {
-    start: function() {},
-    elapsed: function() { return 0; }
-  };
-
-  function HtmlReporter(options) {
-    var env = options.env || {},
-      getContainer = options.getContainer,
-      createElement = options.createElement,
-      createTextNode = options.createTextNode,
-      onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
-      timer = options.timer || noopTimer,
-      results = [],
-      specsExecuted = 0,
-      failureCount = 0,
-      pendingSpecCount = 0,
-      htmlReporterMain,
-      symbols;
-
-    this.initialize = function() {
-      htmlReporterMain = createDom("div", {className: "html-reporter"},
-        createDom("div", {className: "banner"},
-          createDom("span", {className: "title"}, "Jasmine"),
-          createDom("span", {className: "version"}, j$.version)
-        ),
-        createDom("ul", {className: "symbol-summary"}),
-        createDom("div", {className: "alert"}),
-        createDom("div", {className: "results"},
-          createDom("div", {className: "failures"})
-        )
-      );
-      getContainer().appendChild(htmlReporterMain);
-
-      symbols = find(".symbol-summary");
-    };
-
-    var totalSpecsDefined;
-    this.jasmineStarted = function(options) {
-      totalSpecsDefined = options.totalSpecsDefined || 0;
-      timer.start();
-    };
-
-    var summary = createDom("div", {className: "summary"});
-
-    var topResults = new j$.ResultsNode({}, "", null),
-      currentParent = topResults;
-
-    this.suiteStarted = function(result) {
-      currentParent.addChild(result, "suite");
-      currentParent = currentParent.last();
-    };
-
-    this.suiteDone = function(result) {
-      if (currentParent == topResults) {
-        return;
-      }
-
-      currentParent = currentParent.parent;
-    };
-
-    this.specStarted = function(result) {
-      currentParent.addChild(result, "spec");
-    };
-
-    var failures = [];
-    this.specDone = function(result) {
-      if (result.status != "disabled") {
-        specsExecuted++;
-      }
-
-      symbols.appendChild(createDom("li", {
-          className: result.status,
-          id: "spec_" + result.id,
-          title: result.fullName
-        }
-      ));
-
-      if (result.status == "failed") {
-        failureCount++;
-
-        var failure =
-          createDom("div", {className: "spec-detail failed"},
-            createDom("div", {className: "description"},
-              createDom("a", {title: result.fullName, href: specHref(result)}, result.fullName)
-            ),
-            createDom("div", {className: "messages"})
-          );
-        var messages = failure.childNodes[1];
-
-        for (var i = 0; i < result.failedExpectations.length; i++) {
-          var expectation = result.failedExpectations[i];
-          messages.appendChild(createDom("div", {className: "result-message"}, expectation.message));
-          messages.appendChild(createDom("div", {className: "stack-trace"}, expectation.stack));
-        }
-
-        failures.push(failure);
-      }
-
-      if (result.status == "pending") {
-        pendingSpecCount++;
-      }
-    };
-
-    this.jasmineDone = function() {
-      var banner = find(".banner");
-      banner.appendChild(createDom("span", {className: "duration"}, "finished in " + timer.elapsed() / 1000 + "s"));
-
-      var alert = find(".alert");
-
-      alert.appendChild(createDom("span", { className: "exceptions" },
-        createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"),
-        createDom("input", {
-          className: "raise",
-          id: "raise-exceptions",
-          type: "checkbox"
-        })
-      ));
-      var checkbox = find("input");
-
-      checkbox.checked = !env.catchingExceptions();
-      checkbox.onclick = onRaiseExceptionsClick;
-
-      if (specsExecuted < totalSpecsDefined) {
-        var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all";
-        alert.appendChild(
-          createDom("span", {className: "bar skipped"},
-            createDom("a", {href: "?", title: "Run all specs"}, skippedMessage)
-          )
-        );
-      }
-      var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount);
-      if (pendingSpecCount) { statusBarMessage += ", " + pluralize("pending spec", pendingSpecCount); }
-
-      var statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed");
-      alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage));
-
-      var results = find(".results");
-      results.appendChild(summary);
-
-      summaryList(topResults, summary);
-
-      function summaryList(resultsTree, domParent) {
-        var specListNode;
-        for (var i = 0; i < resultsTree.children.length; i++) {
-          var resultNode = resultsTree.children[i];
-          if (resultNode.type == "suite") {
-            var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id},
-              createDom("li", {className: "suite-detail"},
-                createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
-              )
-            );
-
-            summaryList(resultNode, suiteListNode);
-            domParent.appendChild(suiteListNode);
-          }
-          if (resultNode.type == "spec") {
-            if (domParent.getAttribute("class") != "specs") {
-              specListNode = createDom("ul", {className: "specs"});
-              domParent.appendChild(specListNode);
-            }
-            specListNode.appendChild(
-              createDom("li", {
-                  className: resultNode.result.status,
-                  id: "spec-" + resultNode.result.id
-                },
-                createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
-              )
-            );
-          }
-        }
-      }
-
-      if (failures.length) {
-        alert.appendChild(
-          createDom('span', {className: "menu bar spec-list"},
-            createDom("span", {}, "Spec List | "),
-            createDom('a', {className: "failures-menu", href: "#"}, "Failures")));
-        alert.appendChild(
-          createDom('span', {className: "menu bar failure-list"},
-            createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"),
-            createDom("span", {}, " | Failures ")));
-
-        find(".failures-menu").onclick = function() {
-          setMenuModeTo('failure-list');
-        };
-        find(".spec-list-menu").onclick = function() {
-          setMenuModeTo('spec-list');
-        };
-
-        setMenuModeTo('failure-list');
-
-        var failureNode = find(".failures");
-        for (var i = 0; i < failures.length; i++) {
-          failureNode.appendChild(failures[i]);
-        }
-      }
-    };
-
-    return this;
-
-    function find(selector) {
-      return getContainer().querySelector(selector);
-    }
-
-    function createDom(type, attrs, childrenVarArgs) {
-      var el = createElement(type);
-
-      for (var i = 2; i < arguments.length; i++) {
-        var child = arguments[i];
-
-        if (typeof child === 'string') {
-          el.appendChild(createTextNode(child));
-        } else {
-          if (child) {
-            el.appendChild(child);
-          }
-        }
-      }
-
-      for (var attr in attrs) {
-        if (attr == "className") {
-          el[attr] = attrs[attr];
-        } else {
-          el.setAttribute(attr, attrs[attr]);
-        }
-      }
-
-      return el;
-    }
-
-    function pluralize(singular, count) {
-      var word = (count == 1 ? singular : singular + "s");
-
-      return "" + count + " " + word;
-    }
-
-    function specHref(result) {
-      return "?spec=" + encodeURIComponent(result.fullName);
-    }
-
-    function setMenuModeTo(mode) {
-      htmlReporterMain.setAttribute("class", "html-reporter " + mode);
-    }
-  }
-
-  return HtmlReporter;
-};
-
-jasmineRequire.HtmlSpecFilter = function() {
-  function HtmlSpecFilter(options) {
-    var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
-    var filterPattern = new RegExp(filterString);
-
-    this.matches = function(specName) {
-      return filterPattern.test(specName);
-    };
-  }
-
-  return HtmlSpecFilter;
-};
-
-jasmineRequire.ResultsNode = function() {
-  function ResultsNode(result, type, parent) {
-    this.result = result;
-    this.type = type;
-    this.parent = parent;
-
-    this.children = [];
-
-    this.addChild = function(result, type) {
-      this.children.push(new ResultsNode(result, type, this));
-    };
-
-    this.last = function() {
-      return this.children[this.children.length - 1];
-    };
-  }
-
-  return ResultsNode;
-};
-
-jasmineRequire.QueryString = function() {
-  function QueryString(options) {
-
-    this.setParam = function(key, value) {
-      var paramMap = queryStringToParamMap();
-      paramMap[key] = value;
-      options.getWindowLocation().search = toQueryString(paramMap);
-    };
-
-    this.getParam = function(key) {
-      return queryStringToParamMap()[key];
-    };
-
-    return this;
-
-    function toQueryString(paramMap) {
-      var qStrPairs = [];
-      for (var prop in paramMap) {
-        qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop]));
-      }
-      return "?" + qStrPairs.join('&');
-    }
-
-    function queryStringToParamMap() {
-      var paramStr = options.getWindowLocation().search.substring(1),
-        params = [],
-        paramMap = {};
-
-      if (paramStr.length > 0) {
-        params = paramStr.split('&');
-        for (var i = 0; i < params.length; i++) {
-          var p = params[i].split('=');
-          var value = decodeURIComponent(p[1]);
-          if (value === "true" || value === "false") {
-            value = JSON.parse(value);
-          }
-          paramMap[decodeURIComponent(p[0])] = value;
-        }
-      }
-
-      return paramMap;
-    }
-
-  }
-
-  return QueryString;
-};

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine.css
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine.css b/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine.css
deleted file mode 100755
index f4d35b6..0000000
--- a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine.css
+++ /dev/null
@@ -1,55 +0,0 @@
-body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
-
-.html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
-.html-reporter a { text-decoration: none; }
-.html-reporter a:hover { text-decoration: underline; }
-.html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; }
-.html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; }
-.html-reporter .banner .version { margin-left: 14px; }
-.html-reporter #jasmine_content { position: fixed; right: 100%; }
-.html-reporter .version { color: #aaaaaa; }
-.html-reporter .banner { margin-top: 14px; }
-.html-reporter .duration { color: #aaaaaa; float: right; }
-.html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; }
-.html-reporter .symbol-summary li { display: inline-block; height: 8px; width: 14px; font-size: 16px; }
-.html-reporter .symbol-summary li.passed { font-size: 14px; }
-.html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; }
-.html-reporter .symbol-summary li.failed { line-height: 9px; }
-.html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
-.html-reporter .symbol-summary li.disabled { font-size: 14px; }
-.html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; }
-.html-reporter .symbol-summary li.pending { line-height: 17px; }
-.html-reporter .symbol-summary li.pending:before { color: #ba9d37; content: "*"; }
-.html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
-.html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
-.html-reporter .bar.failed { background-color: #b03911; }
-.html-reporter .bar.passed { background-color: #a6b779; }
-.html-reporter .bar.skipped { background-color: #bababa; }
-.html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; }
-.html-reporter .bar.menu a { color: #333333; }
-.html-reporter .bar a { color: white; }
-.html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; }
-.html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; }
-.html-reporter .running-alert { background-color: #666666; }
-.html-reporter .results { margin-top: 14px; }
-.html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
-.html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
-.html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
-.html-reporter.showDetails .summary { display: none; }
-.html-reporter.showDetails #details { display: block; }
-.html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
-.html-reporter .summary { margin-top: 14px; }
-.html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; }
-.html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; }
-.html-reporter .summary li.passed a { color: #5e7d00; }
-.html-reporter .summary li.failed a { color: #b03911; }
-.html-reporter .summary li.pending a { color: #ba9d37; }
-.html-reporter .description + .suite { margin-top: 0; }
-.html-reporter .suite { margin-top: 14px; }
-.html-reporter .suite a { color: #333333; }
-.html-reporter .failures .spec-detail { margin-bottom: 28px; }
-.html-reporter .failures .spec-detail .description { background-color: #b03911; }
-.html-reporter .failures .spec-detail .description a { color: white; }
-.html-reporter .result-message { padding-top: 14px; color: #333333; white-space: pre; }
-.html-reporter .result-message span.result { display: block; }
-.html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }


[5/9] replace jasmine rc5 with release version

Posted by mm...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine.js b/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine.js
deleted file mode 100755
index 7e0bf0a..0000000
--- a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine.js
+++ /dev/null
@@ -1,2367 +0,0 @@
-/*
-Copyright (c) 2008-2013 Pivotal Labs
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-function getJasmineRequireObj() {
-  if (typeof module !== "undefined" && module.exports) {
-    return exports;
-  } else {
-    window.jasmineRequire = window.jasmineRequire || {};
-    return window.jasmineRequire;
-  }
-}
-
-getJasmineRequireObj().core = function(jRequire) {
-  var j$ = {};
-
-  jRequire.base(j$);
-  j$.util = jRequire.util();
-  j$.Any = jRequire.Any();
-  j$.CallTracker = jRequire.CallTracker();
-  j$.Clock = jRequire.Clock();
-  j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
-  j$.Env = jRequire.Env(j$);
-  j$.ExceptionFormatter = jRequire.ExceptionFormatter();
-  j$.Expectation = jRequire.Expectation();
-  j$.buildExpectationResult = jRequire.buildExpectationResult();
-  j$.JsApiReporter = jRequire.JsApiReporter();
-  j$.matchersUtil = jRequire.matchersUtil(j$);
-  j$.ObjectContaining = jRequire.ObjectContaining(j$);
-  j$.pp = jRequire.pp(j$);
-  j$.QueueRunner = jRequire.QueueRunner();
-  j$.ReportDispatcher = jRequire.ReportDispatcher();
-  j$.Spec = jRequire.Spec(j$);
-  j$.SpyStrategy = jRequire.SpyStrategy();
-  j$.Suite = jRequire.Suite();
-  j$.Timer = jRequire.Timer();
-  j$.version = jRequire.version();
-
-  j$.matchers = jRequire.requireMatchers(jRequire, j$);
-
-  return j$;
-};
-
-getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
-  var availableMatchers = [
-      "toBe",
-      "toBeCloseTo",
-      "toBeDefined",
-      "toBeFalsy",
-      "toBeGreaterThan",
-      "toBeLessThan",
-      "toBeNaN",
-      "toBeNull",
-      "toBeTruthy",
-      "toBeUndefined",
-      "toContain",
-      "toEqual",
-      "toHaveBeenCalled",
-      "toHaveBeenCalledWith",
-      "toMatch",
-      "toThrow",
-      "toThrowError"
-    ],
-    matchers = {};
-
-  for (var i = 0; i < availableMatchers.length; i++) {
-    var name = availableMatchers[i];
-    matchers[name] = jRequire[name](j$);
-  }
-
-  return matchers;
-};
-
-getJasmineRequireObj().base = function(j$) {
-  j$.unimplementedMethod_ = function() {
-    throw new Error("unimplemented method");
-  };
-
-  j$.MAX_PRETTY_PRINT_DEPTH = 40;
-  j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
-
-  j$.getGlobal = function() {
-    function getGlobal() {
-      return this;
-    }
-
-    return getGlobal();
-  };
-
-  j$.getEnv = function(options) {
-    var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
-    //jasmine. singletons in here (setTimeout blah blah).
-    return env;
-  };
-
-  j$.isArray_ = function(value) {
-    return j$.isA_("Array", value);
-  };
-
-  j$.isString_ = function(value) {
-    return j$.isA_("String", value);
-  };
-
-  j$.isNumber_ = function(value) {
-    return j$.isA_("Number", value);
-  };
-
-  j$.isA_ = function(typeName, value) {
-    return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
-  };
-
-  j$.isDomNode = function(obj) {
-    return obj.nodeType > 0;
-  };
-
-  j$.any = function(clazz) {
-    return new j$.Any(clazz);
-  };
-
-  j$.objectContaining = function(sample) {
-    return new j$.ObjectContaining(sample);
-  };
-
-  j$.createSpy = function(name, originalFn) {
-
-    var spyStrategy = new j$.SpyStrategy({
-        name: name,
-        fn: originalFn,
-        getSpy: function() { return spy; }
-      }),
-      callTracker = new j$.CallTracker(),
-      spy = function() {
-        callTracker.track({
-          object: this,
-          args: Array.prototype.slice.apply(arguments)
-        });
-        return spyStrategy.exec.apply(this, arguments);
-      };
-
-    for (var prop in originalFn) {
-      if (prop === 'and' || prop === 'calls') {
-        throw new Error("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon");
-      }
-
-      spy[prop] = originalFn[prop];
-    }
-
-    spy.and = spyStrategy;
-    spy.calls = callTracker;
-
-    return spy;
-  };
-
-  j$.isSpy = function(putativeSpy) {
-    if (!putativeSpy) {
-      return false;
-    }
-    return putativeSpy.and instanceof j$.SpyStrategy &&
-      putativeSpy.calls instanceof j$.CallTracker;
-  };
-
-  j$.createSpyObj = function(baseName, methodNames) {
-    if (!j$.isArray_(methodNames) || methodNames.length === 0) {
-      throw "createSpyObj requires a non-empty array of method names to create spies for";
-    }
-    var obj = {};
-    for (var i = 0; i < methodNames.length; i++) {
-      obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
-    }
-    return obj;
-  };
-};
-
-getJasmineRequireObj().util = function() {
-
-  var util = {};
-
-  util.inherit = function(childClass, parentClass) {
-    var Subclass = function() {
-    };
-    Subclass.prototype = parentClass.prototype;
-    childClass.prototype = new Subclass();
-  };
-
-  util.htmlEscape = function(str) {
-    if (!str) {
-      return str;
-    }
-    return str.replace(/&/g, '&amp;')
-      .replace(/</g, '&lt;')
-      .replace(/>/g, '&gt;');
-  };
-
-  util.argsToArray = function(args) {
-    var arrayOfArgs = [];
-    for (var i = 0; i < args.length; i++) {
-      arrayOfArgs.push(args[i]);
-    }
-    return arrayOfArgs;
-  };
-
-  util.isUndefined = function(obj) {
-    return obj === void 0;
-  };
-
-  return util;
-};
-
-getJasmineRequireObj().Spec = function(j$) {
-  function Spec(attrs) {
-    this.expectationFactory = attrs.expectationFactory;
-    this.resultCallback = attrs.resultCallback || function() {};
-    this.id = attrs.id;
-    this.description = attrs.description || '';
-    this.fn = attrs.fn;
-    this.beforeFns = attrs.beforeFns || function() {};
-    this.afterFns = attrs.afterFns || function() {};
-    this.catchingExceptions = attrs.catchingExceptions;
-    this.onStart = attrs.onStart || function() {};
-    this.exceptionFormatter = attrs.exceptionFormatter || function() {};
-    this.getSpecName = attrs.getSpecName || function() { return ''; };
-    this.expectationResultFactory = attrs.expectationResultFactory || function() { };
-    this.queueRunner = attrs.queueRunner || function() {};
-    this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
-
-    this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout};
-
-    if (!this.fn) {
-      this.pend();
-    }
-
-    this.result = {
-      id: this.id,
-      description: this.description,
-      fullName: this.getFullName(),
-      failedExpectations: []
-    };
-  }
-
-  Spec.prototype.addExpectationResult = function(passed, data) {
-    if (passed) {
-      return;
-    }
-    this.result.failedExpectations.push(this.expectationResultFactory(data));
-  };
-
-  Spec.prototype.expect = function(actual) {
-    return this.expectationFactory(actual, this);
-  };
-
-  Spec.prototype.execute = function(onComplete) {
-    var self = this;
-
-    this.onStart(this);
-
-    if (this.markedPending || this.disabled) {
-      complete();
-      return;
-    }
-
-    function timeoutable(fn) {
-      return function(done) {
-        var timeout = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
-          onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'));
-          done();
-        }, j$.DEFAULT_TIMEOUT_INTERVAL]]);
-
-        var callDone = function() {
-          Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]);
-          done();
-        };
-
-        fn.call(this, callDone); //TODO: do we care about more than 1 arg?
-      };
-    }
-
-    var befores = this.beforeFns() || [],
-      afters = this.afterFns() || [],
-      thisOne = (this.fn.length) ? timeoutable(this.fn) : this.fn;
-    var allFns = befores.concat(thisOne).concat(afters);
-
-    this.queueRunner({
-      fns: allFns,
-      onException: onException,
-      onComplete: complete
-    });
-
-    function onException(e) {
-      if (Spec.isPendingSpecException(e)) {
-        self.pend();
-        return;
-      }
-
-      self.addExpectationResult(false, {
-        matcherName: "",
-        passed: false,
-        expected: "",
-        actual: "",
-        error: e
-      });
-    }
-
-    function complete() {
-      self.result.status = self.status();
-      self.resultCallback(self.result);
-
-      if (onComplete) {
-        onComplete();
-      }
-    }
-  };
-
-  Spec.prototype.disable = function() {
-    this.disabled = true;
-  };
-
-  Spec.prototype.pend = function() {
-    this.markedPending = true;
-  };
-
-  Spec.prototype.status = function() {
-    if (this.disabled) {
-      return 'disabled';
-    }
-
-    if (this.markedPending) {
-      return 'pending';
-    }
-
-    if (this.result.failedExpectations.length > 0) {
-      return 'failed';
-    } else {
-      return 'passed';
-    }
-  };
-
-  Spec.prototype.getFullName = function() {
-    return this.getSpecName(this);
-  };
-
-  Spec.pendingSpecExceptionMessage = "=> marked Pending";
-
-  Spec.isPendingSpecException = function(e) {
-    return e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1;
-  };
-
-  return Spec;
-};
-
-if (typeof window == void 0 && typeof exports == "object") {
-  exports.Spec = jasmineRequire.Spec;
-}
-
-getJasmineRequireObj().Env = function(j$) {
-  function Env(options) {
-    options = options || {};
-
-    var self = this;
-    var global = options.global || j$.getGlobal();
-
-    var totalSpecsDefined = 0;
-
-    var catchExceptions = true;
-
-    var realSetTimeout = j$.getGlobal().setTimeout;
-    var realClearTimeout = j$.getGlobal().clearTimeout;
-    this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler());
-
-    var runnableLookupTable = {};
-
-    var spies = [];
-
-    var currentSpec = null;
-    var currentSuite = null;
-
-    var reporter = new j$.ReportDispatcher([
-      "jasmineStarted",
-      "jasmineDone",
-      "suiteStarted",
-      "suiteDone",
-      "specStarted",
-      "specDone"
-    ]);
-
-    this.specFilter = function() {
-      return true;
-    };
-
-    var equalityTesters = [];
-
-    var customEqualityTesters = [];
-    this.addCustomEqualityTester = function(tester) {
-      customEqualityTesters.push(tester);
-    };
-
-    j$.Expectation.addCoreMatchers(j$.matchers);
-
-    var nextSpecId = 0;
-    var getNextSpecId = function() {
-      return 'spec' + nextSpecId++;
-    };
-
-    var nextSuiteId = 0;
-    var getNextSuiteId = function() {
-      return 'suite' + nextSuiteId++;
-    };
-
-    var expectationFactory = function(actual, spec) {
-      return j$.Expectation.Factory({
-        util: j$.matchersUtil,
-        customEqualityTesters: customEqualityTesters,
-        actual: actual,
-        addExpectationResult: addExpectationResult
-      });
-
-      function addExpectationResult(passed, result) {
-        return spec.addExpectationResult(passed, result);
-      }
-    };
-
-    var specStarted = function(spec) {
-      currentSpec = spec;
-      reporter.specStarted(spec.result);
-    };
-
-    var beforeFns = function(suite) {
-      return function() {
-        var befores = [];
-        while(suite) {
-          befores = befores.concat(suite.beforeFns);
-          suite = suite.parentSuite;
-        }
-        return befores.reverse();
-      };
-    };
-
-    var afterFns = function(suite) {
-      return function() {
-        var afters = [];
-        while(suite) {
-          afters = afters.concat(suite.afterFns);
-          suite = suite.parentSuite;
-        }
-        return afters;
-      };
-    };
-
-    var getSpecName = function(spec, suite) {
-      return suite.getFullName() + ' ' + spec.description;
-    };
-
-    // TODO: we may just be able to pass in the fn instead of wrapping here
-    var buildExpectationResult = j$.buildExpectationResult,
-        exceptionFormatter = new j$.ExceptionFormatter(),
-        expectationResultFactory = function(attrs) {
-          attrs.messageFormatter = exceptionFormatter.message;
-          attrs.stackFormatter = exceptionFormatter.stack;
-
-          return buildExpectationResult(attrs);
-        };
-
-    // TODO: fix this naming, and here's where the value comes in
-    this.catchExceptions = function(value) {
-      catchExceptions = !!value;
-      return catchExceptions;
-    };
-
-    this.catchingExceptions = function() {
-      return catchExceptions;
-    };
-
-    var maximumSpecCallbackDepth = 20;
-    var currentSpecCallbackDepth = 0;
-
-    function clearStack(fn) {
-      currentSpecCallbackDepth++;
-      if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) {
-        currentSpecCallbackDepth = 0;
-        realSetTimeout(fn, 0);
-      } else {
-        fn();
-      }
-    }
-
-    var catchException = function(e) {
-      return j$.Spec.isPendingSpecException(e) || catchExceptions;
-    };
-
-    var queueRunnerFactory = function(options) {
-      options.catchException = catchException;
-      options.clearStack = options.clearStack || clearStack;
-
-      new j$.QueueRunner(options).execute();
-    };
-
-    var topSuite = new j$.Suite({
-      env: this,
-      id: getNextSuiteId(),
-      description: 'Jasmine__TopLevel__Suite',
-      queueRunner: queueRunnerFactory,
-      resultCallback: function() {} // TODO - hook this up
-    });
-    runnableLookupTable[topSuite.id] = topSuite;
-    currentSuite = topSuite;
-
-    this.topSuite = function() {
-      return topSuite;
-    };
-
-    this.execute = function(runnablesToRun) {
-      runnablesToRun = runnablesToRun || [topSuite.id];
-
-      var allFns = [];
-      for(var i = 0; i < runnablesToRun.length; i++) {
-        var runnable = runnableLookupTable[runnablesToRun[i]];
-        allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable));
-      }
-
-      reporter.jasmineStarted({
-        totalSpecsDefined: totalSpecsDefined
-      });
-
-      queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
-    };
-
-    this.addReporter = function(reporterToAdd) {
-      reporter.addReporter(reporterToAdd);
-    };
-
-    this.addMatchers = function(matchersToAdd) {
-      j$.Expectation.addMatchers(matchersToAdd);
-    };
-
-    this.spyOn = function(obj, methodName) {
-      if (j$.util.isUndefined(obj)) {
-        throw new Error("spyOn could not find an object to spy upon for " + methodName + "()");
-      }
-
-      if (j$.util.isUndefined(obj[methodName])) {
-        throw new Error(methodName + '() method does not exist');
-      }
-
-      if (obj[methodName] && j$.isSpy(obj[methodName])) {
-        //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
-        throw new Error(methodName + ' has already been spied upon');
-      }
-
-      var spy = j$.createSpy(methodName, obj[methodName]);
-
-      spies.push({
-        spy: spy,
-        baseObj: obj,
-        methodName: methodName,
-        originalValue: obj[methodName]
-      });
-
-      obj[methodName] = spy;
-
-      return spy;
-    };
-
-    var suiteFactory = function(description) {
-      var suite = new j$.Suite({
-        env: self,
-        id: getNextSuiteId(),
-        description: description,
-        parentSuite: currentSuite,
-        queueRunner: queueRunnerFactory,
-        onStart: suiteStarted,
-        resultCallback: function(attrs) {
-          reporter.suiteDone(attrs);
-        }
-      });
-
-      runnableLookupTable[suite.id] = suite;
-      return suite;
-    };
-
-    this.describe = function(description, specDefinitions) {
-      var suite = suiteFactory(description);
-
-      var parentSuite = currentSuite;
-      parentSuite.addChild(suite);
-      currentSuite = suite;
-
-      var declarationError = null;
-      try {
-        specDefinitions.call(suite);
-      } catch (e) {
-        declarationError = e;
-      }
-
-      if (declarationError) {
-        this.it("encountered a declaration exception", function() {
-          throw declarationError;
-        });
-      }
-
-      currentSuite = parentSuite;
-
-      return suite;
-    };
-
-    this.xdescribe = function(description, specDefinitions) {
-      var suite = this.describe(description, specDefinitions);
-      suite.disable();
-      return suite;
-    };
-
-    var specFactory = function(description, fn, suite) {
-      totalSpecsDefined++;
-
-      var spec = new j$.Spec({
-        id: getNextSpecId(),
-        beforeFns: beforeFns(suite),
-        afterFns: afterFns(suite),
-        expectationFactory: expectationFactory,
-        exceptionFormatter: exceptionFormatter,
-        resultCallback: specResultCallback,
-        getSpecName: function(spec) {
-          return getSpecName(spec, suite);
-        },
-        onStart: specStarted,
-        description: description,
-        expectationResultFactory: expectationResultFactory,
-        queueRunner: queueRunnerFactory,
-        fn: fn,
-        timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
-      });
-
-      runnableLookupTable[spec.id] = spec;
-
-      if (!self.specFilter(spec)) {
-        spec.disable();
-      }
-
-      return spec;
-
-      function removeAllSpies() {
-        for (var i = 0; i < spies.length; i++) {
-          var spyEntry = spies[i];
-          spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
-        }
-        spies = [];
-      }
-
-      function specResultCallback(result) {
-        removeAllSpies();
-        j$.Expectation.resetMatchers();
-        customEqualityTesters = [];
-        currentSpec = null;
-        reporter.specDone(result);
-      }
-    };
-
-    var suiteStarted = function(suite) {
-      reporter.suiteStarted(suite.result);
-    };
-
-    this.it = function(description, fn) {
-      var spec = specFactory(description, fn, currentSuite);
-      currentSuite.addChild(spec);
-      return spec;
-    };
-
-    this.xit = function(description, fn) {
-      var spec = this.it(description, fn);
-      spec.pend();
-      return spec;
-    };
-
-    this.expect = function(actual) {
-      return currentSpec.expect(actual);
-    };
-
-    this.beforeEach = function(beforeEachFunction) {
-      currentSuite.beforeEach(beforeEachFunction);
-    };
-
-    this.afterEach = function(afterEachFunction) {
-      currentSuite.afterEach(afterEachFunction);
-    };
-
-    this.pending = function() {
-      throw j$.Spec.pendingSpecExceptionMessage;
-    };
-  }
-
-  return Env;
-};
-
-getJasmineRequireObj().JsApiReporter = function() {
-
-  var noopTimer = {
-    start: function(){},
-    elapsed: function(){ return 0; }
-  };
-
-  function JsApiReporter(options) {
-    var timer = options.timer || noopTimer,
-        status = "loaded";
-
-    this.started = false;
-    this.finished = false;
-
-    this.jasmineStarted = function() {
-      this.started = true;
-      status = 'started';
-      timer.start();
-    };
-
-    var executionTime;
-
-    this.jasmineDone = function() {
-      this.finished = true;
-      executionTime = timer.elapsed();
-      status = 'done';
-    };
-
-    this.status = function() {
-      return status;
-    };
-
-    var suites = {};
-
-    this.suiteStarted = function(result) {
-      storeSuite(result);
-    };
-
-    this.suiteDone = function(result) {
-      storeSuite(result);
-    };
-
-    function storeSuite(result) {
-      suites[result.id] = result;
-    }
-
-    this.suites = function() {
-      return suites;
-    };
-
-    var specs = [];
-    this.specStarted = function(result) { };
-
-    this.specDone = function(result) {
-      specs.push(result);
-    };
-
-    this.specResults = function(index, length) {
-      return specs.slice(index, index + length);
-    };
-
-    this.specs = function() {
-      return specs;
-    };
-
-    this.executionTime = function() {
-      return executionTime;
-    };
-
-  }
-
-  return JsApiReporter;
-};
-
-getJasmineRequireObj().Any = function() {
-
-  function Any(expectedObject) {
-    this.expectedObject = expectedObject;
-  }
-
-  Any.prototype.jasmineMatches = function(other) {
-    if (this.expectedObject == String) {
-      return typeof other == 'string' || other instanceof String;
-    }
-
-    if (this.expectedObject == Number) {
-      return typeof other == 'number' || other instanceof Number;
-    }
-
-    if (this.expectedObject == Function) {
-      return typeof other == 'function' || other instanceof Function;
-    }
-
-    if (this.expectedObject == Object) {
-      return typeof other == 'object';
-    }
-    
-    if (this.expectedObject == Boolean) {
-      return typeof other == 'boolean';
-    }
-
-    return other instanceof this.expectedObject;
-  };
-
-  Any.prototype.jasmineToString = function() {
-    return '<jasmine.any(' + this.expectedClass + ')>';
-  };
-
-  return Any;
-};
-
-getJasmineRequireObj().CallTracker = function() {
-
-  function CallTracker() {
-    var calls = [];
-
-    this.track = function(context) {
-      calls.push(context);
-    };
-
-    this.any = function() {
-      return !!calls.length;
-    };
-
-    this.count = function() {
-      return calls.length;
-    };
-
-    this.argsFor = function(index) {
-      var call = calls[index];
-      return call ? call.args : [];
-    };
-
-    this.all = function() {
-      return calls;
-    };
-
-    this.allArgs = function() {
-      var callArgs = [];
-      for(var i = 0; i < calls.length; i++){
-        callArgs.push(calls[i].args);
-      }
-
-      return callArgs;
-    };
-
-    this.first = function() {
-      return calls[0];
-    };
-
-    this.mostRecent = function() {
-      return calls[calls.length - 1];
-    };
-
-    this.reset = function() {
-      calls = [];
-    };
-  }
-
-  return CallTracker;
-};
-
-getJasmineRequireObj().Clock = function() {
-  function Clock(global, delayedFunctionScheduler) {
-    var self = this,
-      realTimingFunctions = {
-        setTimeout: global.setTimeout,
-        clearTimeout: global.clearTimeout,
-        setInterval: global.setInterval,
-        clearInterval: global.clearInterval
-      },
-      fakeTimingFunctions = {
-        setTimeout: setTimeout,
-        clearTimeout: clearTimeout,
-        setInterval: setInterval,
-        clearInterval: clearInterval
-      },
-      installed = false,
-      timer;
-
-    self.install = function() {
-      replace(global, fakeTimingFunctions);
-      timer = fakeTimingFunctions;
-      installed = true;
-    };
-
-    self.uninstall = function() {
-      delayedFunctionScheduler.reset();
-      replace(global, realTimingFunctions);
-      timer = realTimingFunctions;
-      installed = false;
-    };
-
-    self.setTimeout = function(fn, delay, params) {
-      if (legacyIE()) {
-        if (arguments.length > 2) {
-          throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill");
-        }
-        return timer.setTimeout(fn, delay);
-      }
-      return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]);
-    };
-
-    self.setInterval = function(fn, delay, params) {
-      if (legacyIE()) {
-        if (arguments.length > 2) {
-          throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill");
-        }
-        return timer.setInterval(fn, delay);
-      }
-      return Function.prototype.apply.apply(timer.setInterval, [global, arguments]);
-    };
-
-    self.clearTimeout = function(id) {
-      return Function.prototype.call.apply(timer.clearTimeout, [global, id]);
-    };
-
-    self.clearInterval = function(id) {
-      return Function.prototype.call.apply(timer.clearInterval, [global, id]);
-    };
-
-    self.tick = function(millis) {
-      if (installed) {
-        delayedFunctionScheduler.tick(millis);
-      } else {
-        throw new Error("Mock clock is not installed, use jasmine.clock().install()");
-      }
-    };
-
-    return self;
-
-    function legacyIE() {
-      //if these methods are polyfilled, apply will be present
-      return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply;
-    }
-
-    function replace(dest, source) {
-      for (var prop in source) {
-        dest[prop] = source[prop];
-      }
-    }
-
-    function setTimeout(fn, delay) {
-      return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
-    }
-
-    function clearTimeout(id) {
-      return delayedFunctionScheduler.removeFunctionWithId(id);
-    }
-
-    function setInterval(fn, interval) {
-      return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
-    }
-
-    function clearInterval(id) {
-      return delayedFunctionScheduler.removeFunctionWithId(id);
-    }
-
-    function argSlice(argsObj, n) {
-      return Array.prototype.slice.call(argsObj, 2);
-    }
-  }
-
-  return Clock;
-};
-
-getJasmineRequireObj().DelayedFunctionScheduler = function() {
-  function DelayedFunctionScheduler() {
-    var self = this;
-    var scheduledFunctions = {};
-    var currentTime = 0;
-    var delayedFnCount = 0;
-
-    self.tick = function(millis) {
-      millis = millis || 0;
-      currentTime = currentTime + millis;
-      runFunctionsWithinRange(currentTime - millis, currentTime);
-    };
-
-    self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
-      var f;
-      if (typeof(funcToCall) === 'string') {
-        /* jshint evil: true */
-        f = function() { return eval(funcToCall); };
-        /* jshint evil: false */
-      } else {
-        f = funcToCall;
-      }
-
-      millis = millis || 0;
-      timeoutKey = timeoutKey || ++delayedFnCount;
-      runAtMillis = runAtMillis || (currentTime + millis);
-      scheduledFunctions[timeoutKey] = {
-        runAtMillis: runAtMillis,
-        funcToCall: f,
-        recurring: recurring,
-        params: params,
-        timeoutKey: timeoutKey,
-        millis: millis
-      };
-      return timeoutKey;
-    };
-
-    self.removeFunctionWithId = function(timeoutKey) {
-      delete scheduledFunctions[timeoutKey];
-    };
-
-    self.reset = function() {
-      currentTime = 0;
-      scheduledFunctions = {};
-      delayedFnCount = 0;
-    };
-
-    return self;
-
-    // finds/dupes functions within range and removes them.
-    function functionsWithinRange(startMillis, endMillis) {
-      var fnsToRun = [];
-      for (var timeoutKey in scheduledFunctions) {
-        var scheduledFunc = scheduledFunctions[timeoutKey];
-        if (scheduledFunc &&
-          scheduledFunc.runAtMillis >= startMillis &&
-          scheduledFunc.runAtMillis <= endMillis) {
-
-          // remove fn -- we'll reschedule later if it is recurring.
-          self.removeFunctionWithId(timeoutKey);
-          if (!scheduledFunc.recurring) {
-            fnsToRun.push(scheduledFunc); // schedules each function only once
-          } else {
-            fnsToRun.push(buildNthInstanceOf(scheduledFunc, 0));
-            var additionalTimesFnRunsInRange =
-              Math.floor((endMillis - scheduledFunc.runAtMillis) / scheduledFunc.millis);
-            for (var i = 0; i < additionalTimesFnRunsInRange; i++) {
-              fnsToRun.push(buildNthInstanceOf(scheduledFunc, i + 1));
-            }
-            reschedule(buildNthInstanceOf(scheduledFunc, additionalTimesFnRunsInRange));
-          }
-        }
-      }
-
-      return fnsToRun;
-    }
-
-    function buildNthInstanceOf(scheduledFunc, n) {
-      return {
-        runAtMillis: scheduledFunc.runAtMillis + (scheduledFunc.millis * n),
-        funcToCall: scheduledFunc.funcToCall,
-        params: scheduledFunc.params,
-        millis: scheduledFunc.millis,
-        recurring: scheduledFunc.recurring,
-        timeoutKey: scheduledFunc.timeoutKey
-      };
-    }
-
-    function reschedule(scheduledFn) {
-      self.scheduleFunction(scheduledFn.funcToCall,
-        scheduledFn.millis,
-        scheduledFn.params,
-        true,
-        scheduledFn.timeoutKey,
-        scheduledFn.runAtMillis + scheduledFn.millis);
-    }
-
-
-    function runFunctionsWithinRange(startMillis, endMillis) {
-      var funcsToRun = functionsWithinRange(startMillis, endMillis);
-      if (funcsToRun.length === 0) {
-        return;
-      }
-
-      funcsToRun.sort(function(a, b) {
-        return a.runAtMillis - b.runAtMillis;
-      });
-
-      for (var i = 0; i < funcsToRun.length; ++i) {
-        var funcToRun = funcsToRun[i];
-        funcToRun.funcToCall.apply(null, funcToRun.params || []);
-      }
-    }
-  }
-
-  return DelayedFunctionScheduler;
-};
-
-getJasmineRequireObj().ExceptionFormatter = function() {
-  function ExceptionFormatter() {
-    this.message = function(error) {
-      var message = error.name +
-        ': ' +
-        error.message;
-
-      if (error.fileName || error.sourceURL) {
-        message += " in " + (error.fileName || error.sourceURL);
-      }
-
-      if (error.line || error.lineNumber) {
-        message += " (line " + (error.line || error.lineNumber) + ")";
-      }
-
-      return message;
-    };
-
-    this.stack = function(error) {
-      return error ? error.stack : null;
-    };
-  }
-
-  return ExceptionFormatter;
-};
-
-getJasmineRequireObj().Expectation = function() {
-
-  var matchers = {};
-
-  function Expectation(options) {
-    this.util = options.util || { buildFailureMessage: function() {} };
-    this.customEqualityTesters = options.customEqualityTesters || [];
-    this.actual = options.actual;
-    this.addExpectationResult = options.addExpectationResult || function(){};
-    this.isNot = options.isNot;
-
-    for (var matcherName in matchers) {
-      this[matcherName] = matchers[matcherName];
-    }
-  }
-
-  Expectation.prototype.wrapCompare = function(name, matcherFactory) {
-    return function() {
-      var args = Array.prototype.slice.call(arguments, 0),
-        expected = args.slice(0),
-        message = "";
-
-      args.unshift(this.actual);
-
-      var matcher = matcherFactory(this.util, this.customEqualityTesters),
-          matcherCompare = matcher.compare;
-
-      function defaultNegativeCompare() {
-        var result = matcher.compare.apply(null, args);
-        result.pass = !result.pass;
-        return result;
-      }
-
-      if (this.isNot) {
-        matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
-      }
-
-      var result = matcherCompare.apply(null, args);
-
-      if (!result.pass) {
-        if (!result.message) {
-          args.unshift(this.isNot);
-          args.unshift(name);
-          message = this.util.buildFailureMessage.apply(null, args);
-        } else {
-          message = result.message;
-        }
-      }
-
-      if (expected.length == 1) {
-        expected = expected[0];
-      }
-
-      // TODO: how many of these params are needed?
-      this.addExpectationResult(
-        result.pass,
-        {
-          matcherName: name,
-          passed: result.pass,
-          message: message,
-          actual: this.actual,
-          expected: expected // TODO: this may need to be arrayified/sliced
-        }
-      );
-    };
-  };
-
-  Expectation.addCoreMatchers = function(matchers) {
-    var prototype = Expectation.prototype;
-    for (var matcherName in matchers) {
-      var matcher = matchers[matcherName];
-      prototype[matcherName] = prototype.wrapCompare(matcherName, matcher);
-    }
-  };
-
-  Expectation.addMatchers = function(matchersToAdd) {
-    for (var name in matchersToAdd) {
-      var matcher = matchersToAdd[name];
-      matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
-    }
-  };
-
-  Expectation.resetMatchers = function() {
-    for (var name in matchers) {
-      delete matchers[name];
-    }
-  };
-
-  Expectation.Factory = function(options) {
-    options = options || {};
-
-    var expect = new Expectation(options);
-
-    // TODO: this would be nice as its own Object - NegativeExpectation
-    // TODO: copy instead of mutate options
-    options.isNot = true;
-    expect.not = new Expectation(options);
-
-    return expect;
-  };
-
-  return Expectation;
-};
-
-//TODO: expectation result may make more sense as a presentation of an expectation.
-getJasmineRequireObj().buildExpectationResult = function() {
-  function buildExpectationResult(options) {
-    var messageFormatter = options.messageFormatter || function() {},
-      stackFormatter = options.stackFormatter || function() {};
-
-    return {
-      matcherName: options.matcherName,
-      expected: options.expected,
-      actual: options.actual,
-      message: message(),
-      stack: stack(),
-      passed: options.passed
-    };
-
-    function message() {
-      if (options.passed) {
-        return "Passed.";
-      } else if (options.message) {
-        return options.message;
-      } else if (options.error) {
-        return messageFormatter(options.error);
-      }
-      return "";
-    }
-
-    function stack() {
-      if (options.passed) {
-        return "";
-      }
-
-      var error = options.error;
-      if (!error) {
-        try {
-          throw new Error(message());
-        } catch (e) {
-          error = e;
-        }
-      }
-      return stackFormatter(error);
-    }
-  }
-
-  return buildExpectationResult;
-};
-
-getJasmineRequireObj().ObjectContaining = function(j$) {
-
-  function ObjectContaining(sample) {
-    this.sample = sample;
-  }
-
-  ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
-    if (typeof(this.sample) !== "object") { throw new Error("You must provide an object to objectContaining, not '"+this.sample+"'."); }
-
-    mismatchKeys = mismatchKeys || [];
-    mismatchValues = mismatchValues || [];
-
-    var hasKey = function(obj, keyName) {
-      return obj !== null && !j$.util.isUndefined(obj[keyName]);
-    };
-
-    for (var property in this.sample) {
-      if (!hasKey(other, property) && hasKey(this.sample, property)) {
-        mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
-      }
-      else if (!j$.matchersUtil.equals(this.sample[property], other[property])) {
-        mismatchValues.push("'" + property + "' was '" + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + "' in actual, but was '" + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in expected.");
-      }
-    }
-
-    return (mismatchKeys.length === 0 && mismatchValues.length === 0);
-  };
-
-  ObjectContaining.prototype.jasmineToString = function() {
-    return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>";
-  };
-
-  return ObjectContaining;
-};
-
-getJasmineRequireObj().pp = function(j$) {
-
-  function PrettyPrinter() {
-    this.ppNestLevel_ = 0;
-  }
-
-  PrettyPrinter.prototype.format = function(value) {
-    this.ppNestLevel_++;
-    try {
-      if (j$.util.isUndefined(value)) {
-        this.emitScalar('undefined');
-      } else if (value === null) {
-        this.emitScalar('null');
-      } else if (value === j$.getGlobal()) {
-        this.emitScalar('<global>');
-      } else if (value.jasmineToString) {
-        this.emitScalar(value.jasmineToString());
-      } else if (typeof value === 'string') {
-        this.emitString(value);
-      } else if (j$.isSpy(value)) {
-        this.emitScalar("spy on " + value.and.identity());
-      } else if (value instanceof RegExp) {
-        this.emitScalar(value.toString());
-      } else if (typeof value === 'function') {
-        this.emitScalar('Function');
-      } else if (typeof value.nodeType === 'number') {
-        this.emitScalar('HTMLNode');
-      } else if (value instanceof Date) {
-        this.emitScalar('Date(' + value + ')');
-      } else if (value.__Jasmine_been_here_before__) {
-        this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
-      } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
-        value.__Jasmine_been_here_before__ = true;
-        if (j$.isArray_(value)) {
-          this.emitArray(value);
-        } else {
-          this.emitObject(value);
-        }
-        delete value.__Jasmine_been_here_before__;
-      } else {
-        this.emitScalar(value.toString());
-      }
-    } finally {
-      this.ppNestLevel_--;
-    }
-  };
-
-  PrettyPrinter.prototype.iterateObject = function(obj, fn) {
-    for (var property in obj) {
-      if (!obj.hasOwnProperty(property)) { continue; }
-      if (property == '__Jasmine_been_here_before__') { continue; }
-      fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
-          obj.__lookupGetter__(property) !== null) : false);
-    }
-  };
-
-  PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
-  PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
-  PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
-  PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
-
-  function StringPrettyPrinter() {
-    PrettyPrinter.call(this);
-
-    this.string = '';
-  }
-
-  j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
-
-  StringPrettyPrinter.prototype.emitScalar = function(value) {
-    this.append(value);
-  };
-
-  StringPrettyPrinter.prototype.emitString = function(value) {
-    this.append("'" + value + "'");
-  };
-
-  StringPrettyPrinter.prototype.emitArray = function(array) {
-    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
-      this.append("Array");
-      return;
-    }
-
-    this.append('[ ');
-    for (var i = 0; i < array.length; i++) {
-      if (i > 0) {
-        this.append(', ');
-      }
-      this.format(array[i]);
-    }
-    this.append(' ]');
-  };
-
-  StringPrettyPrinter.prototype.emitObject = function(obj) {
-    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
-      this.append("Object");
-      return;
-    }
-
-    var self = this;
-    this.append('{ ');
-    var first = true;
-
-    this.iterateObject(obj, function(property, isGetter) {
-      if (first) {
-        first = false;
-      } else {
-        self.append(', ');
-      }
-
-      self.append(property);
-      self.append(' : ');
-      if (isGetter) {
-        self.append('<getter>');
-      } else {
-        self.format(obj[property]);
-      }
-    });
-
-    this.append(' }');
-  };
-
-  StringPrettyPrinter.prototype.append = function(value) {
-    this.string += value;
-  };
-
-  return function(value) {
-    var stringPrettyPrinter = new StringPrettyPrinter();
-    stringPrettyPrinter.format(value);
-    return stringPrettyPrinter.string;
-  };
-};
-
-getJasmineRequireObj().QueueRunner = function() {
-
-  function QueueRunner(attrs) {
-    this.fns = attrs.fns || [];
-    this.onComplete = attrs.onComplete || function() {};
-    this.clearStack = attrs.clearStack || function(fn) {fn();};
-    this.onException = attrs.onException || function() {};
-    this.catchException = attrs.catchException || function() { return true; };
-    this.userContext = {};
-  }
-
-  QueueRunner.prototype.execute = function() {
-    this.run(this.fns, 0);
-  };
-
-  QueueRunner.prototype.run = function(fns, recursiveIndex) {
-    var length = fns.length,
-        self = this,
-        iterativeIndex;
-
-    for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
-      var fn = fns[iterativeIndex];
-      if (fn.length > 0) {
-        return attemptAsync(fn);
-      } else {
-        attemptSync(fn);
-      }
-    }
-
-    var runnerDone = iterativeIndex >= length;
-
-    if (runnerDone) {
-      this.clearStack(this.onComplete);
-    }
-
-    function attemptSync(fn) {
-      try {
-        fn.call(self.userContext);
-      } catch (e) {
-        handleException(e);
-      }
-    }
-
-    function attemptAsync(fn) {
-      var next = function () { self.run(fns, iterativeIndex + 1); };
-
-      try {
-        fn.call(self.userContext, next);
-      } catch (e) {
-        handleException(e);
-        next();
-      }
-    }
-
-    function handleException(e) {
-      self.onException(e);
-      if (!self.catchException(e)) {
-        //TODO: set a var when we catch an exception and
-        //use a finally block to close the loop in a nice way..
-        throw e;
-      }
-    }
-  };
-
-  return QueueRunner;
-};
-
-getJasmineRequireObj().ReportDispatcher = function() {
-  function ReportDispatcher(methods) {
-
-    var dispatchedMethods = methods || [];
-
-    for (var i = 0; i < dispatchedMethods.length; i++) {
-      var method = dispatchedMethods[i];
-      this[method] = (function(m) {
-        return function() {
-          dispatch(m, arguments);
-        };
-      }(method));
-    }
-
-    var reporters = [];
-
-    this.addReporter = function(reporter) {
-      reporters.push(reporter);
-    };
-
-    return this;
-
-    function dispatch(method, args) {
-      for (var i = 0; i < reporters.length; i++) {
-        var reporter = reporters[i];
-        if (reporter[method]) {
-          reporter[method].apply(reporter, args);
-        }
-      }
-    }
-  }
-
-  return ReportDispatcher;
-};
-
-
-getJasmineRequireObj().SpyStrategy = function() {
-
-  function SpyStrategy(options) {
-    options = options || {};
-
-    var identity = options.name || "unknown",
-        originalFn = options.fn || function() {},
-        getSpy = options.getSpy || function() {},
-        plan = function() {};
-
-    this.identity = function() {
-      return identity;
-    };
-
-    this.exec = function() {
-      return plan.apply(this, arguments);
-    };
-
-    this.callThrough = function() {
-      plan = originalFn;
-      return getSpy();
-    };
-
-    this.returnValue = function(value) {
-      plan = function() {
-        return value;
-      };
-      return getSpy();
-    };
-
-    this.throwError = function(something) {
-      var error = (something instanceof Error) ? something : new Error(something);
-      plan = function() {
-        throw error;
-      };
-      return getSpy();
-    };
-
-    this.callFake = function(fn) {
-      plan = fn;
-      return getSpy();
-    };
-
-    this.stub = function(fn) {
-      plan = function() {};
-      return getSpy();
-    };
-  }
-
-  return SpyStrategy;
-};
-
-getJasmineRequireObj().Suite = function() {
-  function Suite(attrs) {
-    this.env = attrs.env;
-    this.id = attrs.id;
-    this.parentSuite = attrs.parentSuite;
-    this.description = attrs.description;
-    this.onStart = attrs.onStart || function() {};
-    this.resultCallback = attrs.resultCallback || function() {};
-    this.clearStack = attrs.clearStack || function(fn) {fn();};
-
-    this.beforeFns = [];
-    this.afterFns = [];
-    this.queueRunner = attrs.queueRunner || function() {};
-    this.disabled = false;
-
-    this.children = [];
-
-    this.result = {
-      id: this.id,
-      status: this.disabled ? 'disabled' : '',
-      description: this.description,
-      fullName: this.getFullName()
-    };
-  }
-
-  Suite.prototype.getFullName = function() {
-    var fullName = this.description;
-    for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
-      if (parentSuite.parentSuite) {
-        fullName = parentSuite.description + ' ' + fullName;
-      }
-    }
-    return fullName;
-  };
-
-  Suite.prototype.disable = function() {
-    this.disabled = true;
-  };
-
-  Suite.prototype.beforeEach = function(fn) {
-    this.beforeFns.unshift(fn);
-  };
-
-  Suite.prototype.afterEach = function(fn) {
-    this.afterFns.unshift(fn);
-  };
-
-  Suite.prototype.addChild = function(child) {
-    this.children.push(child);
-  };
-
-  Suite.prototype.execute = function(onComplete) {
-    var self = this;
-    if (this.disabled) {
-      complete();
-      return;
-    }
-
-    var allFns = [];
-
-    for (var i = 0; i < this.children.length; i++) {
-      allFns.push(wrapChildAsAsync(this.children[i]));
-    }
-
-    this.onStart(this);
-
-    this.queueRunner({
-      fns: allFns,
-      onComplete: complete
-    });
-
-    function complete() {
-      self.resultCallback(self.result);
-
-      if (onComplete) {
-        onComplete();
-      }
-    }
-
-    function wrapChildAsAsync(child) {
-      return function(done) { child.execute(done); };
-    }
-  };
-
-  return Suite;
-};
-
-if (typeof window == void 0 && typeof exports == "object") {
-  exports.Suite = jasmineRequire.Suite;
-}
-
-getJasmineRequireObj().Timer = function() {
-  function Timer(options) {
-    options = options || {};
-
-    var now = options.now || function() { return new Date().getTime(); },
-        startTime;
-
-    this.start = function() {
-      startTime = now();
-    };
-
-    this.elapsed = function() {
-      return now() - startTime;
-    };
-  }
-
-  return Timer;
-};
-
-getJasmineRequireObj().matchersUtil = function(j$) {
-  // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
-
-  return {
-    equals: function(a, b, customTesters) {
-      customTesters = customTesters || [];
-
-      return eq(a, b, [], [], customTesters);
-    },
-
-    contains: function(haystack, needle, customTesters) {
-      customTesters = customTesters || [];
-
-      if (Object.prototype.toString.apply(haystack) === "[object Array]") {
-        for (var i = 0; i < haystack.length; i++) {
-          if (eq(haystack[i], needle, [], [], customTesters)) {
-            return true;
-          }
-        }
-        return false;
-      }
-      return haystack.indexOf(needle) >= 0;
-    },
-
-    buildFailureMessage: function() {
-      var args = Array.prototype.slice.call(arguments, 0),
-        matcherName = args[0],
-        isNot = args[1],
-        actual = args[2],
-        expected = args.slice(3),
-        englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
-
-      var message = "Expected " +
-        j$.pp(actual) +
-        (isNot ? " not " : " ") +
-        englishyPredicate;
-
-      if (expected.length > 0) {
-        for (var i = 0; i < expected.length; i++) {
-          if (i > 0) {
-            message += ",";
-          }
-          message += " " + j$.pp(expected[i]);
-        }
-      }
-
-      return message + ".";
-    }
-  };
-
-  // Equality function lovingly adapted from isEqual in
-  //   [Underscore](http://underscorejs.org)
-  function eq(a, b, aStack, bStack, customTesters) {
-    var result = true;
-
-    for (var i = 0; i < customTesters.length; i++) {
-      var customTesterResult = customTesters[i](a, b);
-      if (!j$.util.isUndefined(customTesterResult)) {
-        return customTesterResult;
-      }
-    }
-
-    if (a instanceof j$.Any) {
-      result = a.jasmineMatches(b);
-      if (result) {
-        return true;
-      }
-    }
-
-    if (b instanceof j$.Any) {
-      result = b.jasmineMatches(a);
-      if (result) {
-        return true;
-      }
-    }
-
-    if (b instanceof j$.ObjectContaining) {
-      result = b.jasmineMatches(a);
-      if (result) {
-        return true;
-      }
-    }
-
-    if (a instanceof Error && b instanceof Error) {
-      return a.message == b.message;
-    }
-
-    // Identical objects are equal. `0 === -0`, but they aren't identical.
-    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
-    if (a === b) { return a !== 0 || 1 / a == 1 / b; }
-    // A strict comparison is necessary because `null == undefined`.
-    if (a === null || b === null) { return a === b; }
-    var className = Object.prototype.toString.call(a);
-    if (className != Object.prototype.toString.call(b)) { return false; }
-    switch (className) {
-      // Strings, numbers, dates, and booleans are compared by value.
-      case '[object String]':
-        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
-        // equivalent to `new String("5")`.
-        return a == String(b);
-      case '[object Number]':
-        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
-        // other numeric values.
-        return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
-      case '[object Date]':
-      case '[object Boolean]':
-        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
-        // millisecond representations. Note that invalid dates with millisecond representations
-        // of `NaN` are not equivalent.
-        return +a == +b;
-      // RegExps are compared by their source patterns and flags.
-      case '[object RegExp]':
-        return a.source == b.source &&
-          a.global == b.global &&
-          a.multiline == b.multiline &&
-          a.ignoreCase == b.ignoreCase;
-    }
-    if (typeof a != 'object' || typeof b != 'object') { return false; }
-    // Assume equality for cyclic structures. The algorithm for detecting cyclic
-    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
-    var length = aStack.length;
-    while (length--) {
-      // Linear search. Performance is inversely proportional to the number of
-      // unique nested structures.
-      if (aStack[length] == a) { return bStack[length] == b; }
-    }
-    // Add the first object to the stack of traversed objects.
-    aStack.push(a);
-    bStack.push(b);
-    var size = 0;
-    // Recursively compare objects and arrays.
-    if (className == '[object Array]') {
-      // Compare array lengths to determine if a deep comparison is necessary.
-      size = a.length;
-      result = size == b.length;
-      if (result) {
-        // Deep compare the contents, ignoring non-numeric properties.
-        while (size--) {
-          if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) { break; }
-        }
-      }
-    } else {
-      // Objects with different constructors are not equivalent, but `Object`s
-      // from different frames are.
-      var aCtor = a.constructor, bCtor = b.constructor;
-      if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) &&
-        isFunction(bCtor) && (bCtor instanceof bCtor))) {
-        return false;
-      }
-      // Deep compare objects.
-      for (var key in a) {
-        if (has(a, key)) {
-          // Count the expected number of properties.
-          size++;
-          // Deep compare each member.
-          if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; }
-        }
-      }
-      // Ensure that both objects contain the same number of properties.
-      if (result) {
-        for (key in b) {
-          if (has(b, key) && !(size--)) { break; }
-        }
-        result = !size;
-      }
-    }
-    // Remove the first object from the stack of traversed objects.
-    aStack.pop();
-    bStack.pop();
-
-    return result;
-
-    function has(obj, key) {
-      return obj.hasOwnProperty(key);
-    }
-
-    function isFunction(obj) {
-      return typeof obj === 'function';
-    }
-  }
-};
-
-getJasmineRequireObj().toBe = function() {
-  function toBe() {
-    return {
-      compare: function(actual, expected) {
-        return {
-          pass: actual === expected
-        };
-      }
-    };
-  }
-
-  return toBe;
-};
-
-getJasmineRequireObj().toBeCloseTo = function() {
-
-  function toBeCloseTo() {
-    return {
-      compare: function(actual, expected, precision) {
-        if (precision !== 0) {
-          precision = precision || 2;
-        }
-
-        return {
-          pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
-        };
-      }
-    };
-  }
-
-  return toBeCloseTo;
-};
-
-getJasmineRequireObj().toBeDefined = function() {
-  function toBeDefined() {
-    return {
-      compare: function(actual) {
-        return {
-          pass: (void 0 !== actual)
-        };
-      }
-    };
-  }
-
-  return toBeDefined;
-};
-
-getJasmineRequireObj().toBeFalsy = function() {
-  function toBeFalsy() {
-    return {
-      compare: function(actual) {
-        return {
-          pass: !!!actual
-        };
-      }
-    };
-  }
-
-  return toBeFalsy;
-};
-
-getJasmineRequireObj().toBeGreaterThan = function() {
-
-  function toBeGreaterThan() {
-    return {
-      compare: function(actual, expected) {
-        return {
-          pass: actual > expected
-        };
-      }
-    };
-  }
-
-  return toBeGreaterThan;
-};
-
-
-getJasmineRequireObj().toBeLessThan = function() {
-  function toBeLessThan() {
-    return {
-
-      compare: function(actual, expected) {
-        return {
-          pass: actual < expected
-        };
-      }
-    };
-  }
-
-  return toBeLessThan;
-};
-getJasmineRequireObj().toBeNaN = function(j$) {
-
-  function toBeNaN() {
-    return {
-      compare: function(actual) {
-        var result = {
-          pass: (actual !== actual)
-        };
-
-        if (result.pass) {
-          result.message = "Expected actual not to be NaN.";
-        } else {
-          result.message = "Expected " + j$.pp(actual) + " to be NaN.";
-        }
-
-        return result;
-      }
-    };
-  }
-
-  return toBeNaN;
-};
-
-getJasmineRequireObj().toBeNull = function() {
-
-  function toBeNull() {
-    return {
-      compare: function(actual) {
-        return {
-          pass: actual === null
-        };
-      }
-    };
-  }
-
-  return toBeNull;
-};
-
-getJasmineRequireObj().toBeTruthy = function() {
-
-  function toBeTruthy() {
-    return {
-      compare: function(actual) {
-        return {
-          pass: !!actual
-        };
-      }
-    };
-  }
-
-  return toBeTruthy;
-};
-
-getJasmineRequireObj().toBeUndefined = function() {
-
-  function toBeUndefined() {
-    return {
-      compare: function(actual) {
-        return {
-          pass: void 0 === actual
-        };
-      }
-    };
-  }
-
-  return toBeUndefined;
-};
-
-getJasmineRequireObj().toContain = function() {
-  function toContain(util, customEqualityTesters) {
-    customEqualityTesters = customEqualityTesters || [];
-
-    return {
-      compare: function(actual, expected) {
-
-        return {
-          pass: util.contains(actual, expected, customEqualityTesters)
-        };
-      }
-    };
-  }
-
-  return toContain;
-};
-
-getJasmineRequireObj().toEqual = function() {
-
-  function toEqual(util, customEqualityTesters) {
-    customEqualityTesters = customEqualityTesters || [];
-
-    return {
-      compare: function(actual, expected) {
-        var result = {
-          pass: false
-        };
-
-        result.pass = util.equals(actual, expected, customEqualityTesters);
-
-        return result;
-      }
-    };
-  }
-
-  return toEqual;
-};
-
-getJasmineRequireObj().toHaveBeenCalled = function(j$) {
-
-  function toHaveBeenCalled() {
-    return {
-      compare: function(actual) {
-        var result = {};
-
-        if (!j$.isSpy(actual)) {
-          throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
-        }
-
-        if (arguments.length > 1) {
-          throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
-        }
-
-        result.pass = actual.calls.any();
-
-        result.message = result.pass ?
-          "Expected spy " + actual.and.identity() + " not to have been called." :
-          "Expected spy " + actual.and.identity() + " to have been called.";
-
-        return result;
-      }
-    };
-  }
-
-  return toHaveBeenCalled;
-};
-
-getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
-
-  function toHaveBeenCalledWith(util) {
-    return {
-      compare: function() {
-        var args = Array.prototype.slice.call(arguments, 0),
-          actual = args[0],
-          expectedArgs = args.slice(1),
-          result = { pass: false };
-
-        if (!j$.isSpy(actual)) {
-          throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
-        }
-
-        if (!actual.calls.any()) {
-          result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but it was never called.";
-          return result;
-        }
-
-        if (util.contains(actual.calls.allArgs(), expectedArgs)) {
-          result.pass = true;
-          result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was.";
-        } else {
-          result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but actual calls were " + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + ".";
-        }
-
-        return result;
-      }
-    };
-  }
-
-  return toHaveBeenCalledWith;
-};
-
-getJasmineRequireObj().toMatch = function() {
-
-  function toMatch() {
-    return {
-      compare: function(actual, expected) {
-        var regexp = new RegExp(expected);
-
-        return {
-          pass: regexp.test(actual)
-        };
-      }
-    };
-  }
-
-  return toMatch;
-};
-
-getJasmineRequireObj().toThrow = function(j$) {
-
-  function toThrow(util) {
-    return {
-      compare: function(actual, expected) {
-        var result = { pass: false },
-          threw = false,
-          thrown;
-
-        if (typeof actual != "function") {
-          throw new Error("Actual is not a Function");
-        }
-
-        try {
-          actual();
-        } catch (e) {
-          threw = true;
-          thrown = e;
-        }
-
-        if (!threw) {
-          result.message = "Expected function to throw an exception.";
-          return result;
-        }
-
-        if (arguments.length == 1) {
-          result.pass = true;
-          result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + ".";
-
-          return result;
-        }
-
-        if (util.equals(thrown, expected)) {
-          result.pass = true;
-          result.message = "Expected function not to throw " + j$.pp(expected) + ".";
-        } else {
-          result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " +  j$.pp(thrown) + ".";
-        }
-
-        return result;
-      }
-    };
-  }
-
-  return toThrow;
-};
-
-getJasmineRequireObj().toThrowError = function(j$) {
-  function toThrowError (util) {
-    return {
-      compare: function(actual) {
-        var threw = false,
-          thrown,
-          errorType,
-          message,
-          regexp,
-          name,
-          constructorName;
-
-        if (typeof actual != "function") {
-          throw new Error("Actual is not a Function");
-        }
-
-        extractExpectedParams.apply(null, arguments);
-
-        try {
-          actual();
-        } catch (e) {
-          threw = true;
-          thrown = e;
-        }
-
-        if (!threw) {
-          return fail("Expected function to throw an Error.");
-        }
-
-        if (!(thrown instanceof Error)) {
-          return fail("Expected function to throw an Error, but it threw " + thrown + ".");
-        }
-
-        if (arguments.length == 1) {
-          return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + ".");
-        }
-
-        if (errorType) {
-          name = fnNameFor(errorType);
-          constructorName = fnNameFor(thrown.constructor);
-        }
-
-        if (errorType && message) {
-          if (thrown.constructor == errorType && util.equals(thrown.message, message)) {
-            return pass("Expected function not to throw " + name + " with message \"" + message + "\".");
-          } else {
-            return fail("Expected function to throw " + name + " with message \"" + message +
-                        "\", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
-          }
-        }
-
-        if (errorType && regexp) {
-          if (thrown.constructor == errorType && regexp.test(thrown.message)) {
-            return pass("Expected function not to throw " + name + " with message matching " + regexp + ".");
-          } else {
-            return fail("Expected function to throw " + name + " with message matching " + regexp +
-                        ", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
-          }
-        }
-
-        if (errorType) {
-          if (thrown.constructor == errorType) {
-            return pass("Expected function not to throw " + name + ".");
-          } else {
-            return fail("Expected function to throw " + name + ", but it threw " + constructorName + ".");
-          }
-        }
-
-        if (message) {
-          if (thrown.message == message) {
-            return pass("Expected function not to throw an exception with message " + j$.pp(message) + ".");
-          } else {
-            return fail("Expected function to throw an exception with message " + j$.pp(message) +
-                        ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
-          }
-        }
-
-        if (regexp) {
-          if (regexp.test(thrown.message)) {
-            return pass("Expected function not to throw an exception with a message matching " + j$.pp(regexp) + ".");
-          } else {
-            return fail("Expected function to throw an exception with a message matching " + j$.pp(regexp) +
-                        ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
-          }
-        }
-
-        function fnNameFor(func) {
-            return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
-        }
-
-        function pass(notMessage) {
-          return {
-            pass: true,
-            message: notMessage
-          };
-        }
-
-        function fail(message) {
-          return {
-            pass: false,
-            message: message
-          };
-        }
-
-        function extractExpectedParams() {
-          if (arguments.length == 1) {
-            return;
-          }
-
-          if (arguments.length == 2) {
-            var expected = arguments[1];
-
-            if (expected instanceof RegExp) {
-              regexp = expected;
-            } else if (typeof expected == "string") {
-              message = expected;
-            } else if (checkForAnErrorType(expected)) {
-              errorType = expected;
-            }
-
-            if (!(errorType || message || regexp)) {
-              throw new Error("Expected is not an Error, string, or RegExp.");
-            }
-          } else {
-            if (checkForAnErrorType(arguments[1])) {
-              errorType = arguments[1];
-            } else {
-              throw new Error("Expected error type is not an Error.");
-            }
-
-            if (arguments[2] instanceof RegExp) {
-              regexp = arguments[2];
-            } else if (typeof arguments[2] == "string") {
-              message = arguments[2];
-            } else {
-              throw new Error("Expected error message is not a string or RegExp.");
-            }
-          }
-        }
-
-        function checkForAnErrorType(type) {
-          if (typeof type !== "function") {
-            return false;
-          }
-
-          var Surrogate = function() {};
-          Surrogate.prototype = type.prototype;
-          return (new Surrogate()) instanceof Error;
-        }
-      }
-    };
-  }
-
-  return toThrowError;
-};
-
-getJasmineRequireObj().version = function() {
-  return "2.0.0-rc5";
-};

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine_favicon.png
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine_favicon.png b/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine_favicon.png
deleted file mode 100755
index 3562e27..0000000
Binary files a/cordova-app-test-harness/www/assets/jasmine-2.0.0-rc5/jasmine_favicon.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0/boot.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0/boot.js b/cordova-app-test-harness/www/assets/jasmine-2.0.0/boot.js
new file mode 100755
index 0000000..ec8baa0
--- /dev/null
+++ b/cordova-app-test-harness/www/assets/jasmine-2.0.0/boot.js
@@ -0,0 +1,181 @@
+/**
+ Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
+
+ If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
+
+ The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
+
+ [jasmine-gem]: http://github.com/pivotal/jasmine-gem
+ */
+
+(function() {
+
+  /**
+   * ## Require &amp; Instantiate
+   *
+   * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
+   */
+  window.jasmine = jasmineRequire.core(jasmineRequire);
+
+  /**
+   * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
+   */
+  jasmineRequire.html(jasmine);
+
+  /**
+   * Create the Jasmine environment. This is used to run all specs in a project.
+   */
+  var env = jasmine.getEnv();
+
+  /**
+   * ## The Global Interface
+   *
+   * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
+   */
+  var jasmineInterface = {
+    describe: function(description, specDefinitions) {
+      return env.describe(description, specDefinitions);
+    },
+
+    xdescribe: function(description, specDefinitions) {
+      return env.xdescribe(description, specDefinitions);
+    },
+
+    it: function(desc, func) {
+      return env.it(desc, func);
+    },
+
+    xit: function(desc, func) {
+      return env.xit(desc, func);
+    },
+
+    beforeEach: function(beforeEachFunction) {
+      return env.beforeEach(beforeEachFunction);
+    },
+
+    afterEach: function(afterEachFunction) {
+      return env.afterEach(afterEachFunction);
+    },
+
+    expect: function(actual) {
+      return env.expect(actual);
+    },
+
+    pending: function() {
+      return env.pending();
+    },
+
+    spyOn: function(obj, methodName) {
+      return env.spyOn(obj, methodName);
+    },
+
+    jsApiReporter: new jasmine.JsApiReporter({
+      timer: new jasmine.Timer()
+    })
+  };
+
+  /**
+   * Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
+   */
+  if (typeof window == "undefined" && typeof exports == "object") {
+    extend(exports, jasmineInterface);
+  } else {
+    extend(window, jasmineInterface);
+  }
+
+  /**
+   * Expose the interface for adding custom equality testers.
+   */
+  jasmine.addCustomEqualityTester = function(tester) {
+    env.addCustomEqualityTester(tester);
+  };
+
+  /**
+   * Expose the interface for adding custom expectation matchers
+   */
+  jasmine.addMatchers = function(matchers) {
+    return env.addMatchers(matchers);
+  };
+
+  /**
+   * Expose the mock interface for the JavaScript timeout functions
+   */
+  jasmine.clock = function() {
+    return env.clock;
+  };
+
+  /**
+   * ## Runner Parameters
+   *
+   * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
+   */
+
+  var queryString = new jasmine.QueryString({
+    getWindowLocation: function() { return window.location; }
+  });
+
+  var catchingExceptions = queryString.getParam("catch");
+  env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
+
+  /**
+   * ## Reporters
+   * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
+   */
+  var htmlReporter = new jasmine.HtmlReporter({
+    env: env,
+    onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); },
+    getContainer: function() { return document.body; },
+    createElement: function() { return document.createElement.apply(document, arguments); },
+    createTextNode: function() { return document.createTextNode.apply(document, arguments); },
+    timer: new jasmine.Timer()
+  });
+
+  /**
+   * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results  from JavaScript.
+   */
+  env.addReporter(jasmineInterface.jsApiReporter);
+  env.addReporter(htmlReporter);
+
+  /**
+   * Filter which specs will be run by matching the start of the full name against the `spec` query param.
+   */
+  var specFilter = new jasmine.HtmlSpecFilter({
+    filterString: function() { return queryString.getParam("spec"); }
+  });
+
+  env.specFilter = function(spec) {
+    return specFilter.matches(spec.getFullName());
+  };
+
+  /**
+   * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
+   */
+  window.setTimeout = window.setTimeout;
+  window.setInterval = window.setInterval;
+  window.clearTimeout = window.clearTimeout;
+  window.clearInterval = window.clearInterval;
+
+  /**
+   * ## Execution
+   *
+   * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
+   */
+  var currentWindowOnload = window.onload;
+
+  window.onload = function() {
+    if (currentWindowOnload) {
+      currentWindowOnload();
+    }
+    htmlReporter.initialize();
+    env.execute();
+  };
+
+  /**
+   * Helper function for readability above.
+   */
+  function extend(destination, source) {
+    for (var property in source) destination[property] = source[property];
+    return destination;
+  }
+
+}());

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0/console.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0/console.js b/cordova-app-test-harness/www/assets/jasmine-2.0.0/console.js
new file mode 100755
index 0000000..33c1698
--- /dev/null
+++ b/cordova-app-test-harness/www/assets/jasmine-2.0.0/console.js
@@ -0,0 +1,160 @@
+/*
+Copyright (c) 2008-2013 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+function getJasmineRequireObj() {
+  if (typeof module !== "undefined" && module.exports) {
+    return exports;
+  } else {
+    window.jasmineRequire = window.jasmineRequire || {};
+    return window.jasmineRequire;
+  }
+}
+
+getJasmineRequireObj().console = function(jRequire, j$) {
+  j$.ConsoleReporter = jRequire.ConsoleReporter();
+};
+
+getJasmineRequireObj().ConsoleReporter = function() {
+
+  var noopTimer = {
+    start: function(){},
+    elapsed: function(){ return 0; }
+  };
+
+  function ConsoleReporter(options) {
+    var print = options.print,
+      showColors = options.showColors || false,
+      onComplete = options.onComplete || function() {},
+      timer = options.timer || noopTimer,
+      specCount,
+      failureCount,
+      failedSpecs = [],
+      pendingCount,
+      ansi = {
+        green: '\x1B[32m',
+        red: '\x1B[31m',
+        yellow: '\x1B[33m',
+        none: '\x1B[0m'
+      };
+
+    this.jasmineStarted = function() {
+      specCount = 0;
+      failureCount = 0;
+      pendingCount = 0;
+      print("Started");
+      printNewline();
+      timer.start();
+    };
+
+    this.jasmineDone = function() {
+      printNewline();
+      for (var i = 0; i < failedSpecs.length; i++) {
+        specFailureDetails(failedSpecs[i]);
+      }
+
+      printNewline();
+      var specCounts = specCount + " " + plural("spec", specCount) + ", " +
+        failureCount + " " + plural("failure", failureCount);
+
+      if (pendingCount) {
+        specCounts += ", " + pendingCount + " pending " + plural("spec", pendingCount);
+      }
+
+      print(specCounts);
+
+      printNewline();
+      var seconds = timer.elapsed() / 1000;
+      print("Finished in " + seconds + " " + plural("second", seconds));
+
+      printNewline();
+
+      onComplete(failureCount === 0);
+    };
+
+    this.specDone = function(result) {
+      specCount++;
+
+      if (result.status == "pending") {
+        pendingCount++;
+        print(colored("yellow", "*"));
+        return;
+      }
+
+      if (result.status == "passed") {
+        print(colored("green", '.'));
+        return;
+      }
+
+      if (result.status == "failed") {
+        failureCount++;
+        failedSpecs.push(result);
+        print(colored("red", 'F'));
+      }
+    };
+
+    return this;
+
+    function printNewline() {
+      print("\n");
+    }
+
+    function colored(color, str) {
+      return showColors ? (ansi[color] + str + ansi.none) : str;
+    }
+
+    function plural(str, count) {
+      return count == 1 ? str : str + "s";
+    }
+
+    function repeat(thing, times) {
+      var arr = [];
+      for (var i = 0; i < times; i++) {
+        arr.push(thing);
+      }
+      return arr;
+    }
+
+    function indent(str, spaces) {
+      var lines = (str || '').split("\n");
+      var newArr = [];
+      for (var i = 0; i < lines.length; i++) {
+        newArr.push(repeat(" ", spaces).join("") + lines[i]);
+      }
+      return newArr.join("\n");
+    }
+
+    function specFailureDetails(result) {
+      printNewline();
+      print(result.fullName);
+
+      for (var i = 0; i < result.failedExpectations.length; i++) {
+        var failedExpectation = result.failedExpectations[i];
+        printNewline();
+        print(indent(failedExpectation.stack, 2));
+      }
+
+      printNewline();
+    }
+  }
+
+  return ConsoleReporter;
+};

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/fce98946/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine-html.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine-html.js b/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine-html.js
new file mode 100755
index 0000000..985d0d1
--- /dev/null
+++ b/cordova-app-test-harness/www/assets/jasmine-2.0.0/jasmine-html.js
@@ -0,0 +1,359 @@
+/*
+Copyright (c) 2008-2013 Pivotal Labs
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+jasmineRequire.html = function(j$) {
+  j$.ResultsNode = jasmineRequire.ResultsNode();
+  j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
+  j$.QueryString = jasmineRequire.QueryString();
+  j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
+};
+
+jasmineRequire.HtmlReporter = function(j$) {
+
+  var noopTimer = {
+    start: function() {},
+    elapsed: function() { return 0; }
+  };
+
+  function HtmlReporter(options) {
+    var env = options.env || {},
+      getContainer = options.getContainer,
+      createElement = options.createElement,
+      createTextNode = options.createTextNode,
+      onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
+      timer = options.timer || noopTimer,
+      results = [],
+      specsExecuted = 0,
+      failureCount = 0,
+      pendingSpecCount = 0,
+      htmlReporterMain,
+      symbols;
+
+    this.initialize = function() {
+      htmlReporterMain = createDom("div", {className: "html-reporter"},
+        createDom("div", {className: "banner"},
+          createDom("span", {className: "title"}, "Jasmine"),
+          createDom("span", {className: "version"}, j$.version)
+        ),
+        createDom("ul", {className: "symbol-summary"}),
+        createDom("div", {className: "alert"}),
+        createDom("div", {className: "results"},
+          createDom("div", {className: "failures"})
+        )
+      );
+      getContainer().appendChild(htmlReporterMain);
+
+      symbols = find(".symbol-summary");
+    };
+
+    var totalSpecsDefined;
+    this.jasmineStarted = function(options) {
+      totalSpecsDefined = options.totalSpecsDefined || 0;
+      timer.start();
+    };
+
+    var summary = createDom("div", {className: "summary"});
+
+    var topResults = new j$.ResultsNode({}, "", null),
+      currentParent = topResults;
+
+    this.suiteStarted = function(result) {
+      currentParent.addChild(result, "suite");
+      currentParent = currentParent.last();
+    };
+
+    this.suiteDone = function(result) {
+      if (currentParent == topResults) {
+        return;
+      }
+
+      currentParent = currentParent.parent;
+    };
+
+    this.specStarted = function(result) {
+      currentParent.addChild(result, "spec");
+    };
+
+    var failures = [];
+    this.specDone = function(result) {
+      if (result.status != "disabled") {
+        specsExecuted++;
+      }
+
+      symbols.appendChild(createDom("li", {
+          className: result.status,
+          id: "spec_" + result.id,
+          title: result.fullName
+        }
+      ));
+
+      if (result.status == "failed") {
+        failureCount++;
+
+        var failure =
+          createDom("div", {className: "spec-detail failed"},
+            createDom("div", {className: "description"},
+              createDom("a", {title: result.fullName, href: specHref(result)}, result.fullName)
+            ),
+            createDom("div", {className: "messages"})
+          );
+        var messages = failure.childNodes[1];
+
+        for (var i = 0; i < result.failedExpectations.length; i++) {
+          var expectation = result.failedExpectations[i];
+          messages.appendChild(createDom("div", {className: "result-message"}, expectation.message));
+          messages.appendChild(createDom("div", {className: "stack-trace"}, expectation.stack));
+        }
+
+        failures.push(failure);
+      }
+
+      if (result.status == "pending") {
+        pendingSpecCount++;
+      }
+    };
+
+    this.jasmineDone = function() {
+      var banner = find(".banner");
+      banner.appendChild(createDom("span", {className: "duration"}, "finished in " + timer.elapsed() / 1000 + "s"));
+
+      var alert = find(".alert");
+
+      alert.appendChild(createDom("span", { className: "exceptions" },
+        createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"),
+        createDom("input", {
+          className: "raise",
+          id: "raise-exceptions",
+          type: "checkbox"
+        })
+      ));
+      var checkbox = find("input");
+
+      checkbox.checked = !env.catchingExceptions();
+      checkbox.onclick = onRaiseExceptionsClick;
+
+      if (specsExecuted < totalSpecsDefined) {
+        var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all";
+        alert.appendChild(
+          createDom("span", {className: "bar skipped"},
+            createDom("a", {href: "?", title: "Run all specs"}, skippedMessage)
+          )
+        );
+      }
+      var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount);
+      if (pendingSpecCount) { statusBarMessage += ", " + pluralize("pending spec", pendingSpecCount); }
+
+      var statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed");
+      alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage));
+
+      var results = find(".results");
+      results.appendChild(summary);
+
+      summaryList(topResults, summary);
+
+      function summaryList(resultsTree, domParent) {
+        var specListNode;
+        for (var i = 0; i < resultsTree.children.length; i++) {
+          var resultNode = resultsTree.children[i];
+          if (resultNode.type == "suite") {
+            var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id},
+              createDom("li", {className: "suite-detail"},
+                createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
+              )
+            );
+
+            summaryList(resultNode, suiteListNode);
+            domParent.appendChild(suiteListNode);
+          }
+          if (resultNode.type == "spec") {
+            if (domParent.getAttribute("class") != "specs") {
+              specListNode = createDom("ul", {className: "specs"});
+              domParent.appendChild(specListNode);
+            }
+            specListNode.appendChild(
+              createDom("li", {
+                  className: resultNode.result.status,
+                  id: "spec-" + resultNode.result.id
+                },
+                createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
+              )
+            );
+          }
+        }
+      }
+
+      if (failures.length) {
+        alert.appendChild(
+          createDom('span', {className: "menu bar spec-list"},
+            createDom("span", {}, "Spec List | "),
+            createDom('a', {className: "failures-menu", href: "#"}, "Failures")));
+        alert.appendChild(
+          createDom('span', {className: "menu bar failure-list"},
+            createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"),
+            createDom("span", {}, " | Failures ")));
+
+        find(".failures-menu").onclick = function() {
+          setMenuModeTo('failure-list');
+        };
+        find(".spec-list-menu").onclick = function() {
+          setMenuModeTo('spec-list');
+        };
+
+        setMenuModeTo('failure-list');
+
+        var failureNode = find(".failures");
+        for (var i = 0; i < failures.length; i++) {
+          failureNode.appendChild(failures[i]);
+        }
+      }
+    };
+
+    return this;
+
+    function find(selector) {
+      return getContainer().querySelector(selector);
+    }
+
+    function createDom(type, attrs, childrenVarArgs) {
+      var el = createElement(type);
+
+      for (var i = 2; i < arguments.length; i++) {
+        var child = arguments[i];
+
+        if (typeof child === 'string') {
+          el.appendChild(createTextNode(child));
+        } else {
+          if (child) {
+            el.appendChild(child);
+          }
+        }
+      }
+
+      for (var attr in attrs) {
+        if (attr == "className") {
+          el[attr] = attrs[attr];
+        } else {
+          el.setAttribute(attr, attrs[attr]);
+        }
+      }
+
+      return el;
+    }
+
+    function pluralize(singular, count) {
+      var word = (count == 1 ? singular : singular + "s");
+
+      return "" + count + " " + word;
+    }
+
+    function specHref(result) {
+      return "?spec=" + encodeURIComponent(result.fullName);
+    }
+
+    function setMenuModeTo(mode) {
+      htmlReporterMain.setAttribute("class", "html-reporter " + mode);
+    }
+  }
+
+  return HtmlReporter;
+};
+
+jasmineRequire.HtmlSpecFilter = function() {
+  function HtmlSpecFilter(options) {
+    var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+    var filterPattern = new RegExp(filterString);
+
+    this.matches = function(specName) {
+      return filterPattern.test(specName);
+    };
+  }
+
+  return HtmlSpecFilter;
+};
+
+jasmineRequire.ResultsNode = function() {
+  function ResultsNode(result, type, parent) {
+    this.result = result;
+    this.type = type;
+    this.parent = parent;
+
+    this.children = [];
+
+    this.addChild = function(result, type) {
+      this.children.push(new ResultsNode(result, type, this));
+    };
+
+    this.last = function() {
+      return this.children[this.children.length - 1];
+    };
+  }
+
+  return ResultsNode;
+};
+
+jasmineRequire.QueryString = function() {
+  function QueryString(options) {
+
+    this.setParam = function(key, value) {
+      var paramMap = queryStringToParamMap();
+      paramMap[key] = value;
+      options.getWindowLocation().search = toQueryString(paramMap);
+    };
+
+    this.getParam = function(key) {
+      return queryStringToParamMap()[key];
+    };
+
+    return this;
+
+    function toQueryString(paramMap) {
+      var qStrPairs = [];
+      for (var prop in paramMap) {
+        qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop]));
+      }
+      return "?" + qStrPairs.join('&');
+    }
+
+    function queryStringToParamMap() {
+      var paramStr = options.getWindowLocation().search.substring(1),
+        params = [],
+        paramMap = {};
+
+      if (paramStr.length > 0) {
+        params = paramStr.split('&');
+        for (var i = 0; i < params.length; i++) {
+          var p = params[i].split('=');
+          var value = decodeURIComponent(p[1]);
+          if (value === "true" || value === "false") {
+            value = JSON.parse(value);
+          }
+          paramMap[decodeURIComponent(p[0])] = value;
+        }
+      }
+
+      return paramMap;
+    }
+
+  }
+
+  return QueryString;
+};


[7/9] git commit: Replacing with new test harness

Posted by mm...@apache.org.
Replacing with new test harness


Project: http://git-wip-us.apache.org/repos/asf/cordova-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-labs/commit/908dd288
Tree: http://git-wip-us.apache.org/repos/asf/cordova-labs/tree/908dd288
Diff: http://git-wip-us.apache.org/repos/asf/cordova-labs/diff/908dd288

Branch: refs/heads/cdvtest
Commit: 908dd2888583b07bed661a1e33d63cdad902270a
Parents: fce9894
Author: Michal Mocny <mm...@gmail.com>
Authored: Tue Apr 22 11:09:24 2014 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Thu Apr 24 11:07:06 2014 -0400

----------------------------------------------------------------------
 cordova-app-test-harness/www/index.html         |  18 +-
 .../www/jasmine-jsreporter.js                   | 256 -------------------
 cordova-app-test-harness/www/jasmine-medic.js   | 129 ++++++++++
 cordova-app-test-harness/www/jasmine_helpers.js |  77 ++++++
 cordova-app-test-harness/www/main.css           |  53 +++-
 cordova-app-test-harness/www/main.js            | 256 ++++++-------------
 cordova-app-test-harness/www/medic.js           |  38 +++
 cordova-app-test-harness/www/tests.js           |  64 +++++
 8 files changed, 436 insertions(+), 455 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/908dd288/cordova-app-test-harness/www/index.html
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/index.html b/cordova-app-test-harness/www/index.html
index 2d0c2c7..1af7178 100644
--- a/cordova-app-test-harness/www/index.html
+++ b/cordova-app-test-harness/www/index.html
@@ -12,14 +12,26 @@
 
     <script type="text/javascript" src="assets/jasmine-2.0.0/jasmine.js"></script>
     <script type="text/javascript" src="assets/jasmine-2.0.0/jasmine-html.js"></script>
-    <script type="text/javascript" src="jasmine-jsreporter.js"></script>
+
     <script type="text/javascript" src="cordova.js"></script>
+
+    <!-- App scripts -->
+    <script type="text/javascript" src="tests.js"></script>
+    <script type="text/javascript" src="jasmine_helpers.js"></script>
+    <script type="text/javascript" src="jasmine-medic.js"></script>
+    <script type="text/javascript" src="medic.js"></script>
     <script type="text/javascript" src="main.js"></script>
   </head>
 
   <body>
     <div id='title'></div>
-    <div id='content'></div>
-    <div id='log'></div>
+    <div id='middle'>
+      <div id='buttons'></div>
+      <div id='content'></div>
+    </div>
+    <div id='log'>
+      <div id='log--title'>Log</div>
+      <div id='log--content'></div>
+    </div>
   </body>
 </html>

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/908dd288/cordova-app-test-harness/www/jasmine-jsreporter.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/jasmine-jsreporter.js b/cordova-app-test-harness/www/jasmine-jsreporter.js
deleted file mode 100644
index de59eb6..0000000
--- a/cordova-app-test-harness/www/jasmine-jsreporter.js
+++ /dev/null
@@ -1,256 +0,0 @@
-jasmineRequire.CouchDB = function(j$) {
-  j$.CouchDBReporter = jasmineRequire.CouchDBReporter(j$);
-};
-
-jasmineRequire.CouchDBReporter = function(j$) {
-  
-  var noopTimer = {
-  start: function() {},
-  elapsed: function() { return 0; }
-  };
-  
-  function CouchDBReporter(options) {
-    var env = options.env || {},
-    couch = options.couch || {serverip: 'http://localhost:5900',serverpublic: 'http://localhost:5900',sha: 'test'},
-    getContainer = options.getContainer,
-    createElement = options.createElement,
-    createTextNode = options.createTextNode,
-    onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
-    timer = options.timer || noopTimer,
-    results = [],
-    specsExecuted = 0,
-    failureCount = 0,
-    pendingSpecCount = 0,
-    symbols;
-
-
-    var serverip = couch.serverip,
-    serverpublic = couch.serverpublic || serverip,
-    sha = couch.sha;
-    
-    var totalSpecsDefined;
-    this.jasmineStarted = function(options) {
-      totalSpecsDefined = options.totalSpecsDefined || 0;
-      timer.start();
-    };
-    
-    var topResults = new j$.ResultsNode({}, "", null),
-    currentParent = topResults;
-    
-    this.suiteStarted = function(result) {
-    };
-    
-    this.suiteDone = function(result) {
-
-    };
-    
-    this.specStarted = function(result) {
-      // Start timing this spec
-    };
-    
-    var failures = [];
-    this.specDone = function(result) {
-      if (result.status != "disabled") {
-        specsExecuted++;
-      }
-      if (result.status == "failed") {
-        failureCount++;
-      }
-      if (result.status == "pending") {
-        pendingSpecCount++;
-      }
-    };
-    
-    this.jasmineDone = function() {
-      var p = device.platform.toLowerCase();
-      this.postTests({
-                     mobilespec:results,
-                     sha:this.sha,
-                     platform:(platformMap.hasOwnProperty(p) ? platformMap[p] : p),
-                     version:device.version.toLowerCase(),
-                     timestamp:Math.round(Math.floor((new Date()).getTime() / 1000)),
-                     model:device.model || device.name
-                     });
-      
-    };
-    
-
-    logresult = function(){
-      if(failureCount>0 ) {
-        console.log('[[[ TEST OK ]]]');
-      } else {
-        console.log('[[[ TEST FAILED ]]]');
-      }
-      logfinished();
-    };
-    
-    var logfinished = function(){
-      console.log('>>> DONE <<<');
-    };
-    
-    this.postTests = function(json) {
-      console.log('posting tests');
-      var doc_id = [  sha, json.version, json.model].map(encodeURIComponent).join('__');
-      var doc_url =  serverip + '/mobilespec_results/' + doc_id;
-      var publicdoc_url =  serverpublic + '/mobilespec_results/' + doc_id;
-      console.log('Test Results URL = '+publicdoc_url+' <<<end test result>>>');
-
-      var xhr = new XMLHttpRequest();
-      xhr.open("PUT", doc_url, true);
-      xhr.onreadystatechange=function() {
-        console.log('onreadystatechange');
-        if (xhr.readyState==4) {
-          console.log('readystate==4, status: ' + xhr.status);
-          if (xhr.status==201) { // HTTP 201 Created the doc successfully
-            logresult();
-          } else if (xhr.status == 409) { // HTTP 409 Conflict - doc exists already
-            console.log('conflict on couch');
-            // doc already exists. now let's GET it, grab the rev, delete it, and try again.
-            var exehar = new XMLHttpRequest();
-            exehar.open('GET', doc_url, true);
-            exehar.onreadystatechange=function() {
-              if (exehar.readyState==4) {
-                if (exehar.status==200) {
-                  var existing_doc = JSON.parse(exehar.responseText);
-                  var rev = existing_doc._rev;
-                  var eksatschargh = new XMLHttpRequest();
-                  eksatschargh.open('DELETE', doc_url + '?rev=' + rev, true);
-                  eksatschargh.onreadystatechange=function() {
-                    if (eksatschargh.readyState==4) {
-                      if (eksatschargh.status==200) {
-                        var x_h_r = new XMLHttpRequest();
-                        x_h_r.open('PUT', doc_url, true);
-                        x_h_r.onreadystatechange=function() {
-                          if (x_h_r.readyState==4) {
-                            if (x_h_r.status==201) {
-                              logresult();
-                            } else {
-                              console.log('the round trip delete+create failed. i give up. status was: ' + x_h_r.status);
-                              console.log(x_h_r.responseText);
-                            }
-                          }
-                        };
-                        x_h_r.send(JSON.stringify(json));
-                      } else {
-                        console.log('We tried to add the results to couch. it said it already exists. now im trying to DELETE it. delete failed. status on the DELETE: ' + eksatschargh.status);
-                      }
-                    }
-                  };
-                  eksatschargh.send(null);
-                } else {
-                  console.log('look, we tried to add the results to couch. it said it already exists. now im trying to GET it so i can DELETE it. Get failed. status on the GET: ' + exehar.status);
-                }
-              }
-            };
-            exehar.send(null);
-          } else {
-            console.log('Unexpected couchDB error. status code: ' + xhr.status);
-            console.log(xhr.responseText);
-            logfinished();
-          }
-        }
-      };
-      xhr.send(JSON.stringify(json));
-    }
-    return this;
-  }
-  
-  /*
-postTests: function(json) {
-  console.log('posting tests');
-  var xhr = new XMLHttpRequest();
-  var doc_id = [ this.sha, json.version, json.model].map(encodeURIComponent).join('__');
-  // TODO: expose the db in this url for customization
-  var doc_url = this.serverip + '/mobilespec_results/' + doc_id;
-  var publicdoc_url = this.serverpublic + '/mobilespec_results/' + doc_id;
-  console.log('Test Results URL = '+publicdoc_url+' <<<end test result>>>');
-  xhr.open("PUT", doc_url, true);
-  
-  xhr.onreadystatechange=function() {
-    console.log('onreadystatechange');
-    if (xhr.readyState==4) {
-      console.log('readystate==4, status: ' + xhr.status);
-      if (xhr.status==201) {
-        // HTTP 201 Created
-        // we added the doc, hooray
-        if(!(jasmine.runnerResults.failed)) {
-          console.log('[[[ TEST OK ]]]');
-        } else {
-          console.log('[[[ TEST FAILED ]]]');
-        }
-        console.log('>>> DONE <<<');
-       } else if (xhr.status == 409) {
-        console.log('conflict on couch');
-        // HTTP 409 Conflict
-        // doc already exists. now let's GET it, grab the rev, delete it, and try again.
-        var exehar = new XMLHttpRequest();
-        exehar.open('GET', doc_url, true);
-        exehar.onreadystatechange=function() {
-          if (exehar.readyState==4) {
-            if (exehar.status==200) {
-              var existing_doc = JSON.parse(exehar.responseText);
-              var rev = existing_doc._rev;
-              var eksatschargh = new XMLHttpRequest();
-              eksatschargh.open('DELETE', doc_url + '?rev=' + rev, true);
-              eksatschargh.onreadystatechange=function() {
-                if (eksatschargh.readyState==4) {
-                  if (eksatschargh.status==200) {
-                    var x_h_r = new XMLHttpRequest();
-                    x_h_r.open('PUT', doc_url, true);
-                    x_h_r.onreadystatechange=function() {
-                      if (x_h_r.readyState==4) {
-                        if (x_h_r.status==201) {
-                          if(!(jasmine.runnerResults.failed)) {
-                            console.log('[[[ TEST OK ]]]');
-                          } else {
-                            console.log('[[[ TEST FAILED ]]]');
-                          }
-                          console.log('>>> DONE <<<');
-                        } else {
-                          console.log('the round trip delete+create failed. i give up. status was: ' + x_h_r.status);
-                          console.log(x_h_r.responseText);
-                        }
-                      }
-                    };
-                    x_h_r.send(JSON.stringify(json));
-                  } else {
-                    console.log('We tried to add the results to couch. it said it already exists. now im trying to DELETE it. delete failed. status on the DELETE: ' + eksatschargh.status);
-                  }
-                }
-              };
-              eksatschargh.send(null);
-            } else {
-              console.log('look, we tried to add the results to couch. it said it already exists. now im trying to GET it so i can DELETE it. Get failed. status on the GET: ' + exehar.status);
-            }
-          }
-        };
-        exehar.send(null);
-      } else {
-        console.log('Unexpected couchDB error. status code: ' + xhr.status);
-        console.log(xhr.responseText);
-        console.log('>>> DONE <<<');
-      }
-    }
-  };
-  xhr.send(JSON.stringify(json));
-}
-   */
-  
-   /**
-   * Calculate elapsed time, in Seconds.
-   * @param startMs Start time in Milliseconds
-   * @param finishMs Finish time in Milliseconds
-   * @return Elapsed time in Seconds */
-  function elapsedSec (startMs, finishMs) {
-    return (finishMs - startMs) / 1000;
-  }
-
-  var platformMap = {
-    'ipod touch':'ios',
-    'iphone':'ios'
-  };
-
-  return CouchDBReporter;
-};
-
-

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/908dd288/cordova-app-test-harness/www/jasmine-medic.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/jasmine-medic.js b/cordova-app-test-harness/www/jasmine-medic.js
new file mode 100644
index 0000000..5f6d13c
--- /dev/null
+++ b/cordova-app-test-harness/www/jasmine-medic.js
@@ -0,0 +1,129 @@
+jasmineRequire.medic = function(j$) {
+  j$.MedicReporter = jasmineRequire.MedicReporter(j$);
+};
+
+jasmineRequire.MedicReporter = function(j$) {
+  
+  var noopTimer = {
+  start: function() {},
+  elapsed: function() { return 0; }
+  };
+  
+  function MedicReporter(options) {
+    var env = options.env || {},
+    logoptions = options.log || {logurl: 'http://localhost:6800'},
+    getContainer = options.getContainer,
+    createElement = options.createElement,
+    createTextNode = options.createTextNode,
+    onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
+    timer = options.timer || noopTimer,
+    results = [],
+    specsExecuted = 0,
+    failureCount = 0,
+    pendingSpecCount = 0,
+    symbols;
+
+
+    var serverurl = logoptions.logurl;
+
+    this.initialize = function() {
+    }
+    
+    var totalSpecsDefined;
+    this.jasmineStarted = function(options) {
+      totalSpecsDefined = options.totalSpecsDefined || 0;
+      timer.start();
+    };
+    
+    var topResults = new j$.ResultsNode({}, "", null),
+    currentParent = topResults;
+    
+    this.suiteStarted = function(result) {
+    };
+    
+    this.suiteDone = function(result) {
+
+    };
+    
+    this.specStarted = function(result) {
+      // Start timing this spec
+    };
+    
+    var failures = [];
+    this.specDone = function(result) {
+      if (result.status != "disabled") {
+        specsExecuted++;
+      }
+      if (result.status == "failed") {
+        failureCount++;
+        results.push(result);
+      }
+      if (result.status == "pending") {
+        pendingSpecCount++;
+      }
+    };
+
+    buildResults = function(){
+      var json ={specs:specsExecuted, failures:failureCount, results: results};
+      return json;
+    }
+    
+    this.jasmineDone = function() {
+      var p = 'Desktop';
+      var devmodel='none';
+      if(typeof device != 'undefined') {
+        p = device.platform.toLowerCase();
+        devmodel=device.model || device.name;
+      }
+
+      this.postTests({
+          mobilespec:buildResults(),
+          platform:(platformMap.hasOwnProperty(p) ? platformMap[p] : p),
+          version:p,
+          timestamp:Math.round(Math.floor((new Date()).getTime() / 1000)),
+          model:devmodel
+          });
+      
+    };
+    
+
+    logresult = function(){
+      if(failureCount>0 ) {
+        console.log('[[[ TEST OK ]]]');
+      } else {
+        console.log('[[[ TEST FAILED ]]]');
+      }
+      logfinished();
+    };
+    
+    var logfinished = function(){
+      console.log('>>> DONE <<<');
+    };
+    
+    this.postTests = function(json) {
+      console.log('posting tests');
+
+      var xhr = new XMLHttpRequest();
+      xhr.open("POST", serverurl+'/result', true);
+      xhr.setRequestHeader("Content-Type","application/json")
+      xhr.send(JSON.stringify(json));
+    }
+    return this;
+  }
+  
+   /**
+   * Calculate elapsed time, in Seconds.
+   * @param startMs Start time in Milliseconds
+   * @param finishMs Finish time in Milliseconds
+   * @return Elapsed time in Seconds */
+  function elapsedSec(startMs, finishMs) {
+    return (finishMs - startMs) / 1000;
+  }
+
+  var platformMap = {
+    'ipod touch':'ios',
+    'iphone':'ios'
+  };
+
+  return MedicReporter;
+};

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/908dd288/cordova-app-test-harness/www/jasmine_helpers.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/jasmine_helpers.js b/cordova-app-test-harness/www/jasmine_helpers.js
new file mode 100644
index 0000000..1224909
--- /dev/null
+++ b/cordova-app-test-harness/www/jasmine_helpers.js
@@ -0,0 +1,77 @@
+(function() {
+
+'use strict';
+
+var exports = window;
+
+exports.setUpJasmine = function() {
+  // Set up jasmine
+  var jasmine = jasmineRequire.core(jasmineRequire);
+  jasmineRequire.html(jasmine);
+  var jasmineEnv = jasmine.currentEnv_ = new jasmine.Env();
+
+  jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+  jasmineEnv.catchExceptions(false);
+
+  // Set up jasmine interface
+  var jasmineInterface = Object.create(null);
+  jasmineInterface.jasmine = jasmine;
+
+  // Fill in jasmineInterface with built-ins
+  var jasmine_env_functions = ['describe',
+                               'xdescribe',
+                               'it',
+                               'xit',
+                               'beforeEach',
+                               'afterEach',
+                               'expect',
+                               'pending',
+                               'spyOn',
+                               'addCustomEqualityTester',
+                               'addMatchers'];
+
+  jasmine_env_functions.forEach(function(fn) {
+    jasmineInterface[fn] = jasmineEnv[fn].bind(jasmineEnv);
+  });
+  jasmineInterface.clock = jasmineEnv.clock;
+
+  // Add Reporters
+  addJasmineReporters(jasmineInterface, jasmineEnv);
+
+  // Add Spec Filter
+  jasmineEnv.specFilter = function(spec) {
+    //console.log(spec.getFullName());
+    return true;
+  };
+
+  return jasmineInterface;
+}
+
+function addJasmineReporters(jasmineInterface, jasmineEnv) {
+  jasmineInterface.jsApiReporter = new jasmineInterface.jasmine.JsApiReporter({ timer: new jasmineInterface.jasmine.Timer() });
+  jasmineEnv.addReporter(jasmineInterface.jsApiReporter);
+
+  jasmineInterface.htmlReporter = new jasmineInterface.jasmine.HtmlReporter({
+    env: jasmineEnv,
+    queryString: function() { return null; },
+    onRaiseExceptionsClick: function() { },
+    getContainer: function() { return document.getElementById('content'); },
+    createElement: function() { return document.createElement.apply(document, arguments); },
+    createTextNode: function() { return document.createTextNode.apply(document, arguments); },
+    timer: new jasmineInterface.jasmine.Timer()
+  });
+  jasmineInterface.htmlReporter.initialize();
+  jasmineEnv.addReporter(jasmineInterface.htmlReporter);
+
+  if (window.medic.enabled) {
+    jasmineRequire.medic(jasmineInterface.jasmine);
+    jasmineInterface.MedicReporter = new jasmineInterface.jasmine.MedicReporter({
+      env: jasmineEnv,
+      log: { logurl: window.medic.logurl }
+    });
+    jasmineInterface.MedicReporter.initialize();
+    jasmineEnv.addReporter(jasmineInterface.MedicReporter);
+  }
+}
+
+}());

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/908dd288/cordova-app-test-harness/www/main.css
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/main.css b/cordova-app-test-harness/www/main.css
index c85be21..7475c90 100644
--- a/cordova-app-test-harness/www/main.css
+++ b/cordova-app-test-harness/www/main.css
@@ -1,13 +1,13 @@
+*, *:before, *:after {
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+}
+
 html, body {
   height: 100%;
   width: 100%;
-  padding: 0;
   margin: 0;
-}
-
-*, *:before, *:after {
-  -webkit-box-sizing: border-box;
-  box-sizing: border-box;
+  padding: 0;
 }
 
 #title {
@@ -17,29 +17,54 @@ html, body {
   top: 0;
   z-index: 1000;
 
-  background-color: #58b;
+  background-color: #75B2F0;
   font-size: 25px;
   text-align: center;
   font-weight: bold;
 }
 
-#content {
-  padding-top: 30px;
-  padding-bottom: 150px;
+#middle {
+  position: absolute;
+  top: 30px;
+  bottom: 20px;
+  width: 100%;
+  overflow-y: auto;
+  overflow-x: auto;
 }
 
 #log {
   position: fixed;
-  height: 150px;
+  height: 20px;
   width: 100%;
   bottom: 0;
   z-index: 1000;
+  border-top: 2px solid #777;
+  transition: 0.25s ease;
+}
+
+#log.expanded {
+  height: 60%;
+}
 
+#log--title {
+  position: absolute;
+  top: 0;
+  height: 20px;
+  width: 100%;
+  background-color: #93AAC2;
+}
+
+#log--content {
+  position: absolute;
+  top: 20px;
+  bottom: 0;
+  width: 100%;
+  overflow-x: none;
+  overflow-y: auto;
   background-color: white;
-  border-top: 2px solid #777;
-  white-space: pre;
 }
 
-#log > div {
+#log--content--line {
   border-bottom: 1px solid #ccc;
+  white-space: pre;
 }

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/908dd288/cordova-app-test-harness/www/main.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/main.js b/cordova-app-test-harness/www/main.js
index 4be5c47..54750b0 100644
--- a/cordova-app-test-harness/www/main.js
+++ b/cordova-app-test-harness/www/main.js
@@ -1,31 +1,49 @@
 (function() {
 
-/******************************************************************************/
-
 'use strict';
 
-function getURLParameter(name) {
-  return decodeURIComponent(
-      (new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [,""])[1].replace(/\+/g, '%20')
-    ) || null;
-}
+/******************************************************************************/
 
-function getMode() {
-  return getURLParameter('mode') || localStorage['mode'] || 'main';
+function getMode(callback) {
+  var mode = localStorage.getItem('mode') || 'main';
+  console.log(mode);
+  callback(mode);
 }
 
 function setMode(mode) {
-  localStorage['mode'] = mode;
-  location.href = 'index.html?mode=' + mode;
+  var handlers = {
+    'main': runMain,
+    'auto': runAutoTests,
+    'manual': runManualTests
+  }
+  if (!handlers.hasOwnProperty(mode)) {
+    return console.error("Unsopported mode: " + mode);
+  }
+
+  localStorage.setItem('mode', mode);
+  window.clearContent();
+
+  handlers[mode]();
 }
 
-function setTitle(title) {
+/******************************************************************************/
+
+window.clearContent = function() {
+  var content = document.getElementById('content');
+  content.innerHTML = '';
+  var log = document.getElementById('log--content');
+  log.innerHTML = '';
+  var buttons = document.getElementById('buttons');
+  buttons.innerHTML = '';
+}
+
+window.setTitle = function(title) {
   var el = document.getElementById('title');
   el.textContent = title;
 }
 
-function createButton(title, callback) {
-  var content = document.getElementById('content');
+window.createActionButton = function(title, callback) {
+  var buttons = document.getElementById('buttons');
   var div = document.createElement('div');
   var button = document.createElement('a');
   button.textContent = title;
@@ -35,209 +53,83 @@ function createButton(title, callback) {
   };
   button.classList.add('topcoat-button');
   div.appendChild(button);
-  content.appendChild(div);
+  buttons.appendChild(div);
 }
 
-function logger() {
-  console.log.apply(console, Array.prototype.slice.apply(arguments));
-  //console.trace();
-  var el = document.getElementById('log');
+// TODO: make a better logger
+window.logger = function() {
+  console.log.apply(console, arguments);
+  window.medic.log.apply(window.medic.log, arguments);
+
+  var el = document.getElementById('log--content');
   var div = document.createElement('div');
+  div.classList.add('log--content--line');
   div.textContent = Array.prototype.slice.apply(arguments).map(function(arg) {
       return (typeof arg === 'string') ? arg : JSON.stringify(arg);
     }).join(' ');
   el.appendChild(div);
+  // scroll to bottom
   el.scrollTop = el.scrollHeight;
 }
 
 /******************************************************************************/
 
-function runMain() {
-  setTitle('Cordova Tests');
-  createButton('Auto Tests', function() { setMode('autotests'); });
-  createButton('Manual Tests', function() { setMode('manualtests'); });
-
-  setDeviceInfo();
-}
-
-function setDeviceInfo() {
-  var el = document.getElementById('content');
-  function display() {
-    var div = document.createElement('div');
-    div.textContent = Array.prototype.slice.apply(arguments).map(function(arg) {
-        return (typeof arg === 'string') ? arg : JSON.stringify(arg);
-      }).join(' ');
-    el.appendChild(div);
-  }
-  display("Platform: ", device.platform);
-  display("Version: ", device.version);
-  display("Uuid: ", device.uuid);
-  display("Model: ", device.model);
-  display("Width: ", screen.width);
-  display("Height: ", screen.height);
-  display("Color-Depth: ", screen.colorDepth);
-  display("User-Agent: ", navigator.userAgent);
-}
-
-/******************************************************************************/
-
-function getPluginTestsJsModules() {
-  return cordova.require('cordova/plugin_list')
-    .map(function(jsmodule) {
-      return jsmodule.id;
-    })
-    .filter(function(id) {
-      return /.tests$/.test(id);
-    });
-}
-
-/******************************************************************************/
-
 function runAutoTests() {
   setTitle('Auto Tests');
-  createButton('Back', function() { setMode('main'); });
-
-  // Set up jasmine
-  var jasmine = jasmineRequire.core(jasmineRequire);
-  jasmineRequire.html(jasmine);
-  jasmineRequire.CouchDB(jasmine);
-  var jasmineEnv = jasmine.getEnv();
 
-  jasmine.DEFAULT_TIMEOUT_INTERVAL = 300;
+  createActionButton('Again', setMode.bind(null, 'auto'));
+  createActionButton('Reset App', location.reload.bind(location));
+  createActionButton('Back', setMode.bind(null, 'main'));
 
-  var catchingExceptions = getURLParameter("catch");
-  jasmineEnv.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
-
-  /*
-  var specFilter = new jasmine.HtmlSpecFilter({
-    filterString: function() { return getURLParameter("spec"); }
-  });
-
-  jasmineEnv.specFilter = function(spec) {
-    return specFilter.matches(spec.getFullName());
-  };
-  */
-
-  createHtmlReporter(jasmine);
-  createCouchdbReporter(jasmine, function() {
-    var test = cordova.require('org.apache.cordova.test-framework.test');
-    test.initForAutoTests(jasmine);
-
-    // Define our tests
-    getPluginTestsJsModules().forEach(function(id) {
-      var tests;
-      try {
-        tests = cordova.require(id);
-      } catch(ex) {
-        logger('Failed to load:', id);
-        return;
-      }
-      tests.init();
-      logger('Loaded:', id);
-    });
-
-    // Run!
-    test.runAutoTests();
-  });
-}
+  var jasmineInterface = window.setUpJasmine();
+  // Attach jasmineInterface to global object
+  for (var property in jasmineInterface) {
+    window[property] = jasmineInterface[property];
+  }
+  window.defineAutoTests(jasmineInterface);
 
-function createHtmlReporter(jasmine) {
-   // Set up jasmine html reporter
+  // Run the tests!
   var jasmineEnv = jasmine.getEnv();
-  var contentEl = document.getElementById('content');
-  var htmlReporter = new jasmine.HtmlReporter({
-    env: jasmineEnv,
-    queryString: getURLParameter,
-    onRaiseExceptionsClick: function() { /*queryString.setParam("catch", !jasmineEnv.catchingExceptions());*/ },
-    getContainer: function() { return contentEl; },
-    createElement: function() { return document.createElement.apply(document, arguments); },
-    createTextNode: function() { return document.createTextNode.apply(document, arguments); },
-    timer: new jasmine.Timer()
-  });
-  htmlReporter.initialize();
-
-  jasmineEnv.addReporter(htmlReporter);
-}
-
-function createCouchdbReporter(jasmine, callback) {
-  var settings = cordova.require('org.apache.cordova.appsettings.appsettings');
-  var win = function(dbsettings) {
-    configureCouchReporter(dbsettings,jasmine,callback);
-  };
-  var fail = function() {
-    configureCouchReporter(null,jasmine,callback);
-  };
-  settings.get(win, fail, ["CouchdbUrl", "CouchdbPrivateUrl", "TestSha"]);
-}
-
-function configureCouchReporter(dbsettings, jasmine, callback) {
-    if (!dbsettings) {
-      console.warn('Not reporting results to CouchDB.');
-      return callback();
-    }
-
-    try {
-      var reporteroptions = {
-        serverip: dbsettings['CouchdbUrl'],
-        serverpublic: dbsettings['CouchdbPrivateUrl'],
-        sha: dbsettings['TestSha'],
-      };
-      var ciReporter = new jasmine.CouchDBReporter({
-        env: jasmine.getEnv(),
-        queryString: getURLParameter,
-        onRaiseExceptionsClick: function() { /*queryString.setParam("catch", !jasmineEnv.catchingExceptions());*/ },
-        getContainer: function() { return contentEl; },
-        createElement: function() { return document.createElement.apply(document, arguments); },
-        createTextNode: function() { return document.createTextNode.apply(document, arguments); },
-        timer: new jasmine.Timer(),
-        couch: reporteroptions
-      });
-
-      jasmine.getEnv().addReporter(ciReporter);
-    } catch(ex) {
-      logger('Invalid CouchDB settings:', ex);
-    }
-
-    return callback();
+  jasmineEnv.execute();
 }
 
 /******************************************************************************/
 
 function runManualTests() {
   setTitle('Manual Tests');
-  createButton('Back', function() { setMode('main'); });
+
+  createActionButton('Reset App', location.reload.bind(location));
+  createActionButton('Back', setMode.bind(null, 'main'));
 
   var contentEl = document.getElementById('content');
-  var test = cordova.require('org.apache.cordova.test-framework.test');
-  test.initForManualTests();
+  var beforeEach = function() {
+    window.clearContent();
+    createActionButton('Reset App', location.reload.bind(location));
+    createActionButton('Back', setMode.bind(null, 'manual'));
+  }
+  window.defineManualTests(contentEl, beforeEach, createActionButton);
 }
 
 /******************************************************************************/
 
-function runUnknownMode() {
-  setTitle('Unknown Mode');
-  createButton('Reset', function() { setMode('main'); });
+function runMain() {
+  setTitle('Cordova Tests');
+
+  createActionButton('Auto Tests', setMode.bind(null, 'auto'));
+  createActionButton('Manual Tests', setMode.bind(null, 'manual'));
+  createActionButton('Reset App', location.reload.bind(location));
 }
 
 /******************************************************************************/
 
-document.addEventListener("DOMContentLoaded", function() {
-});
-
 document.addEventListener("deviceready", function() {
-  var contentEl = document.getElementById('content');
-  var test = cordova.require('org.apache.cordova.test-framework.test');
-  test.init(contentEl, createButton, logger);
-
-  var mode = getMode();
-  if (mode === 'main')
-    runMain();
-  else if (mode === 'autotests')
-    runAutoTests();
-  else if (mode === 'manualtests')
-    runManualTests();
-  else
-    runUnknownMode();
+  window.medic.load(function() {
+    if (window.medic.enabled) {
+      setMode('auto');
+    } else {
+      getMode(setMode);
+    }
+  });
 });
 
 /******************************************************************************/

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/908dd288/cordova-app-test-harness/www/medic.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/medic.js b/cordova-app-test-harness/www/medic.js
new file mode 100644
index 0000000..4a1791b
--- /dev/null
+++ b/cordova-app-test-harness/www/medic.js
@@ -0,0 +1,38 @@
+(function() {
+
+'use strict';
+
+var exports = window.medic = {};
+
+exports.logurl = 'http://127.0.0.1:7800';
+
+exports.enabled = false;
+
+exports.log = function() {
+  if (!window.medic.enabled)
+    return;
+  var xhr = new XMLHttpRequest();
+  xhr.open("POST", exports.logurl, true);
+  xhr.setRequestHeader("Content-Type", "text/plain");
+  xhr.send(Array.prototype.slice.apply(arguments));
+};
+
+exports.load = function (callback) {
+  var xhr = new XMLHttpRequest();
+  xhr.open("GET", "medic.json", true);
+  xhr.onload = function() {
+    if (xhr.readyState == 4 && xhr.status == 200) {
+      var cfg = JSON.parse(xhr.responseText);
+      exports.logurl = cfg.logurl;
+      exports.enabled = true;
+      console.log('Loaded Medic Config: logurl=' + exports.logurl);
+    }
+    callback();
+  }
+  xhr.onerror = function() {
+   callback();
+  }
+  xhr.send();
+}
+
+}());

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/908dd288/cordova-app-test-harness/www/tests.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/tests.js b/cordova-app-test-harness/www/tests.js
new file mode 100644
index 0000000..a5421d9
--- /dev/null
+++ b/cordova-app-test-harness/www/tests.js
@@ -0,0 +1,64 @@
+(function() {
+
+'use strict';
+
+var exports = window;
+
+exports.tests = Object.create(null);
+
+function getTestsObject(api) {
+  return window.tests[api] = window.tests[api] || { enabled: true };
+}
+
+// Usage:
+// registerAutoTests('apiName', function() {
+//   define('foo', function() {
+//     .. jasmine tests ..
+//   });
+// });
+exports.registerAutoTests = function(api, fn) {
+  var apiTests = getTestsObject(api);
+  apiTests.defineAutoTests = function(jasmineInterface) {
+    jasmineInterface.describe(api + ' >>', function() {
+      fn(jasmineInterface); // Note: don't pass fn directly to jasmine.describe, since describe does async magic if fn takes an arg
+    });
+  };
+};
+
+exports.defineAutoTests = function(jasmineInterface) {
+  Object.keys(exports.tests).forEach(function(key) {
+    if (!exports.tests[key].enabled)
+      return;
+    if (!exports.tests[key].hasOwnProperty('defineAutoTests'))
+      return;
+    exports.tests[key].defineAutoTests(jasmineInterface);
+  });
+};
+
+// Usage:
+// registerManualTests('apiName', function(contentEl, addButton) {
+//   .. setup ..
+//   addButton('Test Description', function() { ... });
+//   addButton('Test 2', function() { ... });
+// });
+exports.registerManualTests = function(api, fn) {
+  var apiTests = getTestsObject(api);
+  apiTests.defineManualTests = function(contentEl, addButton) {
+    fn(contentEl, addButton);
+  };
+}
+
+exports.defineManualTests = function(contentEl, beforeEach, createActionButton) {
+  Object.keys(exports.tests).forEach(function(key) {
+    if (!exports.tests[key].enabled)
+      return;
+    if (!exports.tests[key].hasOwnProperty('defineManualTests'))
+      return;
+    createActionButton(key, function() {
+      beforeEach();
+      exports.tests[key].defineManualTests(contentEl, createActionButton);
+    });
+  });
+};
+
+}());


[2/9] git commit: mobing config.xml up out of www

Posted by mm...@apache.org.
mobing config.xml up out of www


Project: http://git-wip-us.apache.org/repos/asf/cordova-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-labs/commit/d0aae3cd
Tree: http://git-wip-us.apache.org/repos/asf/cordova-labs/tree/d0aae3cd
Diff: http://git-wip-us.apache.org/repos/asf/cordova-labs/diff/d0aae3cd

Branch: refs/heads/cdvtest
Commit: d0aae3cd22d2039cd3a680979410f31d2d8ae885
Parents: b12e2cf
Author: Michal Mocny <mm...@gmail.com>
Authored: Mon Mar 31 15:04:21 2014 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Mon Mar 31 15:04:21 2014 -0400

----------------------------------------------------------------------
 cordova-app-test-harness/www/config.xml | 15 ---------------
 1 file changed, 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/d0aae3cd/cordova-app-test-harness/www/config.xml
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/config.xml b/cordova-app-test-harness/www/config.xml
deleted file mode 100644
index 142dae6..0000000
--- a/cordova-app-test-harness/www/config.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<widget id="org.apache.cordova.CordovaTests" version="0.1.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
-    <name>Cordova Tests</name>
-    <description>
-        Cordova Test Runner
-    </description>
-    <author>
-    </author>
-    <content src="index.html" />
-    <access origin="http://www.apache.org/*" />
-    <access origin="https://www.googleapis.com/*" />
-
-    <preference name="fullscreen" value="true" />
-    <preference name="webviewbounce" value="false" />
-</widget>


[8/9] git commit: Add auto-reload testing

Posted by mm...@apache.org.
Add auto-reload testing


Project: http://git-wip-us.apache.org/repos/asf/cordova-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-labs/commit/a9b2849b
Tree: http://git-wip-us.apache.org/repos/asf/cordova-labs/tree/a9b2849b
Diff: http://git-wip-us.apache.org/repos/asf/cordova-labs/diff/a9b2849b

Branch: refs/heads/cdvtest
Commit: a9b2849b79de688d83104d6e9031b774f6d72e3a
Parents: 908dd28
Author: Michal Mocny <mm...@gmail.com>
Authored: Thu Apr 24 12:06:31 2014 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Thu Apr 24 12:06:31 2014 -0400

----------------------------------------------------------------------
 cordova-app-test-harness/config.xml          |    2 +
 cordova-app-test-harness/update.sh           |    9 +
 cordova-app-test-harness/www/assets/zepto.js | 1550 +++++++++++++++++++++
 cordova-app-test-harness/www/index.html      |    1 +
 cordova-app-test-harness/www/last_update     |    1 +
 cordova-app-test-harness/www/main.js         |   20 +
 6 files changed, 1583 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/a9b2849b/cordova-app-test-harness/config.xml
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/config.xml b/cordova-app-test-harness/config.xml
index 142dae6..7d55342 100644
--- a/cordova-app-test-harness/config.xml
+++ b/cordova-app-test-harness/config.xml
@@ -9,6 +9,8 @@
     <content src="index.html" />
     <access origin="http://www.apache.org/*" />
     <access origin="https://www.googleapis.com/*" />
+    <content src="http://192.168.1.147:8000/android" />
+    <access origin="http://192.168.1.147:8000" />
 
     <preference name="fullscreen" value="true" />
     <preference name="webviewbounce" value="false" />

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/a9b2849b/cordova-app-test-harness/update.sh
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/update.sh b/cordova-app-test-harness/update.sh
new file mode 100755
index 0000000..b630013
--- /dev/null
+++ b/cordova-app-test-harness/update.sh
@@ -0,0 +1,9 @@
+# Pass an arg like --all to rebuild everything
+if [ $# -gt 0 ]; then
+  rm -rf platforms
+  rm -rf plugins
+  mkdir platforms
+  cordova platform add android
+fi
+cordova prepare
+date > www/last_update

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/a9b2849b/cordova-app-test-harness/www/assets/zepto.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/assets/zepto.js b/cordova-app-test-harness/www/assets/zepto.js
new file mode 100644
index 0000000..dccf063
--- /dev/null
+++ b/cordova-app-test-harness/www/assets/zepto.js
@@ -0,0 +1,1550 @@
+/* Zepto v1.1.3 - zepto event ajax form ie - zeptojs.com/license */
+
+
+var Zepto = (function() {
+  var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, filter = emptyArray.filter,
+    document = window.document,
+    elementDisplay = {}, classCache = {},
+    cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 },
+    fragmentRE = /^\s*<(\w+|!)[^>]*>/,
+    singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+    tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+    rootNodeRE = /^(?:body|html)$/i,
+    capitalRE = /([A-Z])/g,
+
+    // special attributes that should be get/set via method calls
+    methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'],
+
+    adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ],
+    table = document.createElement('table'),
+    tableRow = document.createElement('tr'),
+    containers = {
+      'tr': document.createElement('tbody'),
+      'tbody': table, 'thead': table, 'tfoot': table,
+      'td': tableRow, 'th': tableRow,
+      '*': document.createElement('div')
+    },
+    readyRE = /complete|loaded|interactive/,
+    simpleSelectorRE = /^[\w-]*$/,
+    class2type = {},
+    toString = class2type.toString,
+    zepto = {},
+    camelize, uniq,
+    tempParent = document.createElement('div'),
+    propMap = {
+      'tabindex': 'tabIndex',
+      'readonly': 'readOnly',
+      'for': 'htmlFor',
+      'class': 'className',
+      'maxlength': 'maxLength',
+      'cellspacing': 'cellSpacing',
+      'cellpadding': 'cellPadding',
+      'rowspan': 'rowSpan',
+      'colspan': 'colSpan',
+      'usemap': 'useMap',
+      'frameborder': 'frameBorder',
+      'contenteditable': 'contentEditable'
+    },
+    isArray = Array.isArray ||
+      function(object){ return object instanceof Array }
+
+  zepto.matches = function(element, selector) {
+    if (!selector || !element || element.nodeType !== 1) return false
+    var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector ||
+                          element.oMatchesSelector || element.matchesSelector
+    if (matchesSelector) return matchesSelector.call(element, selector)
+    // fall back to performing a selector:
+    var match, parent = element.parentNode, temp = !parent
+    if (temp) (parent = tempParent).appendChild(element)
+    match = ~zepto.qsa(parent, selector).indexOf(element)
+    temp && tempParent.removeChild(element)
+    return match
+  }
+
+  function type(obj) {
+    return obj == null ? String(obj) :
+      class2type[toString.call(obj)] || "object"
+  }
+
+  function isFunction(value) { return type(value) == "function" }
+  function isWindow(obj)     { return obj != null && obj == obj.window }
+  function isDocument(obj)   { return obj != null && obj.nodeType == obj.DOCUMENT_NODE }
+  function isObject(obj)     { return type(obj) == "object" }
+  function isPlainObject(obj) {
+    return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype
+  }
+  function likeArray(obj) { return typeof obj.length == 'number' }
+
+  function compact(array) { return filter.call(array, function(item){ return item != null }) }
+  function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array }
+  camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }
+  function dasherize(str) {
+    return str.replace(/::/g, '/')
+           .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
+           .replace(/([a-z\d])([A-Z])/g, '$1_$2')
+           .replace(/_/g, '-')
+           .toLowerCase()
+  }
+  uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) }
+
+  function classRE(name) {
+    return name in classCache ?
+      classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'))
+  }
+
+  function maybeAddPx(name, value) {
+    return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value
+  }
+
+  function defaultDisplay(nodeName) {
+    var element, display
+    if (!elementDisplay[nodeName]) {
+      element = document.createElement(nodeName)
+      document.body.appendChild(element)
+      display = getComputedStyle(element, '').getPropertyValue("display")
+      element.parentNode.removeChild(element)
+      display == "none" && (display = "block")
+      elementDisplay[nodeName] = display
+    }
+    return elementDisplay[nodeName]
+  }
+
+  function children(element) {
+    return 'children' in element ?
+      slice.call(element.children) :
+      $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node })
+  }
+
+  // `$.zepto.fragment` takes a html string and an optional tag name
+  // to generate DOM nodes nodes from the given html string.
+  // The generated DOM nodes are returned as an array.
+  // This function can be overriden in plugins for example to make
+  // it compatible with browsers that don't support the DOM fully.
+  zepto.fragment = function(html, name, properties) {
+    var dom, nodes, container
+
+    // A special case optimization for a single tag
+    if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))
+
+    if (!dom) {
+      if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>")
+      if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
+      if (!(name in containers)) name = '*'
+
+      container = containers[name]
+      container.innerHTML = '' + html
+      dom = $.each(slice.call(container.childNodes), function(){
+        container.removeChild(this)
+      })
+    }
+
+    if (isPlainObject(properties)) {
+      nodes = $(dom)
+      $.each(properties, function(key, value) {
+        if (methodAttributes.indexOf(key) > -1) nodes[key](value)
+        else nodes.attr(key, value)
+      })
+    }
+
+    return dom
+  }
+
+  // `$.zepto.Z` swaps out the prototype of the given `dom` array
+  // of nodes with `$.fn` and thus supplying all the Zepto functions
+  // to the array. Note that `__proto__` is not supported on Internet
+  // Explorer. This method can be overriden in plugins.
+  zepto.Z = function(dom, selector) {
+    dom = dom || []
+    dom.__proto__ = $.fn
+    dom.selector = selector || ''
+    return dom
+  }
+
+  // `$.zepto.isZ` should return `true` if the given object is a Zepto
+  // collection. This method can be overriden in plugins.
+  zepto.isZ = function(object) {
+    return object instanceof zepto.Z
+  }
+
+  // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and
+  // takes a CSS selector and an optional context (and handles various
+  // special cases).
+  // This method can be overriden in plugins.
+  zepto.init = function(selector, context) {
+    var dom
+    // If nothing given, return an empty Zepto collection
+    if (!selector) return zepto.Z()
+    // Optimize for string selectors
+    else if (typeof selector == 'string') {
+      selector = selector.trim()
+      // If it's a html fragment, create nodes from it
+      // Note: In both Chrome 21 and Firefox 15, DOM error 12
+      // is thrown if the fragment doesn't begin with <
+      if (selector[0] == '<' && fragmentRE.test(selector))
+        dom = zepto.fragment(selector, RegExp.$1, context), selector = null
+      // If there's a context, create a collection on that context first, and select
+      // nodes from there
+      else if (context !== undefined) return $(context).find(selector)
+      // If it's a CSS selector, use it to select nodes.
+      else dom = zepto.qsa(document, selector)
+    }
+    // If a function is given, call it when the DOM is ready
+    else if (isFunction(selector)) return $(document).ready(selector)
+    // If a Zepto collection is given, just return it
+    else if (zepto.isZ(selector)) return selector
+    else {
+      // normalize array if an array of nodes is given
+      if (isArray(selector)) dom = compact(selector)
+      // Wrap DOM nodes.
+      else if (isObject(selector))
+        dom = [selector], selector = null
+      // If it's a html fragment, create nodes from it
+      else if (fragmentRE.test(selector))
+        dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
+      // If there's a context, create a collection on that context first, and select
+      // nodes from there
+      else if (context !== undefined) return $(context).find(selector)
+      // And last but no least, if it's a CSS selector, use it to select nodes.
+      else dom = zepto.qsa(document, selector)
+    }
+    // create a new Zepto collection from the nodes found
+    return zepto.Z(dom, selector)
+  }
+
+  // `$` will be the base `Zepto` object. When calling this
+  // function just call `$.zepto.init, which makes the implementation
+  // details of selecting nodes and creating Zepto collections
+  // patchable in plugins.
+  $ = function(selector, context){
+    return zepto.init(selector, context)
+  }
+
+  function extend(target, source, deep) {
+    for (key in source)
+      if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
+        if (isPlainObject(source[key]) && !isPlainObject(target[key]))
+          target[key] = {}
+        if (isArray(source[key]) && !isArray(target[key]))
+          target[key] = []
+        extend(target[key], source[key], deep)
+      }
+      else if (source[key] !== undefined) target[key] = source[key]
+  }
+
+  // Copy all but undefined properties from one or more
+  // objects to the `target` object.
+  $.extend = function(target){
+    var deep, args = slice.call(arguments, 1)
+    if (typeof target == 'boolean') {
+      deep = target
+      target = args.shift()
+    }
+    args.forEach(function(arg){ extend(target, arg, deep) })
+    return target
+  }
+
+  // `$.zepto.qsa` is Zepto's CSS selector implementation which
+  // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`.
+  // This method can be overriden in plugins.
+  zepto.qsa = function(element, selector){
+    var found,
+        maybeID = selector[0] == '#',
+        maybeClass = !maybeID && selector[0] == '.',
+        nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
+        isSimple = simpleSelectorRE.test(nameOnly)
+    return (isDocument(element) && isSimple && maybeID) ?
+      ( (found = element.getElementById(nameOnly)) ? [found] : [] ) :
+      (element.nodeType !== 1 && element.nodeType !== 9) ? [] :
+      slice.call(
+        isSimple && !maybeID ?
+          maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class
+          element.getElementsByTagName(selector) : // Or a tag
+          element.querySelectorAll(selector) // Or it's not simple, and we need to query all
+      )
+  }
+
+  function filtered(nodes, selector) {
+    return selector == null ? $(nodes) : $(nodes).filter(selector)
+  }
+
+  $.contains = function(parent, node) {
+    return parent !== node && parent.contains(node)
+  }
+
+  function funcArg(context, arg, idx, payload) {
+    return isFunction(arg) ? arg.call(context, idx, payload) : arg
+  }
+
+  function setAttribute(node, name, value) {
+    value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
+  }
+
+  // access className property while respecting SVGAnimatedString
+  function className(node, value){
+    var klass = node.className,
+        svg   = klass && klass.baseVal !== undefined
+
+    if (value === undefined) return svg ? klass.baseVal : klass
+    svg ? (klass.baseVal = value) : (node.className = value)
+  }
+
+  // "true"  => true
+  // "false" => false
+  // "null"  => null
+  // "42"    => 42
+  // "42.5"  => 42.5
+  // "08"    => "08"
+  // JSON    => parse if valid
+  // String  => self
+  function deserializeValue(value) {
+    var num
+    try {
+      return value ?
+        value == "true" ||
+        ( value == "false" ? false :
+          value == "null" ? null :
+          !/^0/.test(value) && !isNaN(num = Number(value)) ? num :
+          /^[\[\{]/.test(value) ? $.parseJSON(value) :
+          value )
+        : value
+    } catch(e) {
+      return value
+    }
+  }
+
+  $.type = type
+  $.isFunction = isFunction
+  $.isWindow = isWindow
+  $.isArray = isArray
+  $.isPlainObject = isPlainObject
+
+  $.isEmptyObject = function(obj) {
+    var name
+    for (name in obj) return false
+    return true
+  }
+
+  $.inArray = function(elem, array, i){
+    return emptyArray.indexOf.call(array, elem, i)
+  }
+
+  $.camelCase = camelize
+  $.trim = function(str) {
+    return str == null ? "" : String.prototype.trim.call(str)
+  }
+
+  // plugin compatibility
+  $.uuid = 0
+  $.support = { }
+  $.expr = { }
+
+  $.map = function(elements, callback){
+    var value, values = [], i, key
+    if (likeArray(elements))
+      for (i = 0; i < elements.length; i++) {
+        value = callback(elements[i], i)
+        if (value != null) values.push(value)
+      }
+    else
+      for (key in elements) {
+        value = callback(elements[key], key)
+        if (value != null) values.push(value)
+      }
+    return flatten(values)
+  }
+
+  $.each = function(elements, callback){
+    var i, key
+    if (likeArray(elements)) {
+      for (i = 0; i < elements.length; i++)
+        if (callback.call(elements[i], i, elements[i]) === false) return elements
+    } else {
+      for (key in elements)
+        if (callback.call(elements[key], key, elements[key]) === false) return elements
+    }
+
+    return elements
+  }
+
+  $.grep = function(elements, callback){
+    return filter.call(elements, callback)
+  }
+
+  if (window.JSON) $.parseJSON = JSON.parse
+
+  // Populate the class2type map
+  $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+    class2type[ "[object " + name + "]" ] = name.toLowerCase()
+  })
+
+  // Define methods that will be available on all
+  // Zepto collections
+  $.fn = {
+    // Because a collection acts like an array
+    // copy over these useful array functions.
+    forEach: emptyArray.forEach,
+    reduce: emptyArray.reduce,
+    push: emptyArray.push,
+    sort: emptyArray.sort,
+    indexOf: emptyArray.indexOf,
+    concat: emptyArray.concat,
+
+    // `map` and `slice` in the jQuery API work differently
+    // from their array counterparts
+    map: function(fn){
+      return $($.map(this, function(el, i){ return fn.call(el, i, el) }))
+    },
+    slice: function(){
+      return $(slice.apply(this, arguments))
+    },
+
+    ready: function(callback){
+      // need to check if document.body exists for IE as that browser reports
+      // document ready when it hasn't yet created the body element
+      if (readyRE.test(document.readyState) && document.body) callback($)
+      else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
+      return this
+    },
+    get: function(idx){
+      return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
+    },
+    toArray: function(){ return this.get() },
+    size: function(){
+      return this.length
+    },
+    remove: function(){
+      return this.each(function(){
+        if (this.parentNode != null)
+          this.parentNode.removeChild(this)
+      })
+    },
+    each: function(callback){
+      emptyArray.every.call(this, function(el, idx){
+        return callback.call(el, idx, el) !== false
+      })
+      return this
+    },
+    filter: function(selector){
+      if (isFunction(selector)) return this.not(this.not(selector))
+      return $(filter.call(this, function(element){
+        return zepto.matches(element, selector)
+      }))
+    },
+    add: function(selector,context){
+      return $(uniq(this.concat($(selector,context))))
+    },
+    is: function(selector){
+      return this.length > 0 && zepto.matches(this[0], selector)
+    },
+    not: function(selector){
+      var nodes=[]
+      if (isFunction(selector) && selector.call !== undefined)
+        this.each(function(idx){
+          if (!selector.call(this,idx)) nodes.push(this)
+        })
+      else {
+        var excludes = typeof selector == 'string' ? this.filter(selector) :
+          (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
+        this.forEach(function(el){
+          if (excludes.indexOf(el) < 0) nodes.push(el)
+        })
+      }
+      return $(nodes)
+    },
+    has: function(selector){
+      return this.filter(function(){
+        return isObject(selector) ?
+          $.contains(this, selector) :
+          $(this).find(selector).size()
+      })
+    },
+    eq: function(idx){
+      return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1)
+    },
+    first: function(){
+      var el = this[0]
+      return el && !isObject(el) ? el : $(el)
+    },
+    last: function(){
+      var el = this[this.length - 1]
+      return el && !isObject(el) ? el : $(el)
+    },
+    find: function(selector){
+      var result, $this = this
+      if (typeof selector == 'object')
+        result = $(selector).filter(function(){
+          var node = this
+          return emptyArray.some.call($this, function(parent){
+            return $.contains(parent, node)
+          })
+        })
+      else if (this.length == 1) result = $(zepto.qsa(this[0], selector))
+      else result = this.map(function(){ return zepto.qsa(this, selector) })
+      return result
+    },
+    closest: function(selector, context){
+      var node = this[0], collection = false
+      if (typeof selector == 'object') collection = $(selector)
+      while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector)))
+        node = node !== context && !isDocument(node) && node.parentNode
+      return $(node)
+    },
+    parents: function(selector){
+      var ancestors = [], nodes = this
+      while (nodes.length > 0)
+        nodes = $.map(nodes, function(node){
+          if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) {
+            ancestors.push(node)
+            return node
+          }
+        })
+      return filtered(ancestors, selector)
+    },
+    parent: function(selector){
+      return filtered(uniq(this.pluck('parentNode')), selector)
+    },
+    children: function(selector){
+      return filtered(this.map(function(){ return children(this) }), selector)
+    },
+    contents: function() {
+      return this.map(function() { return slice.call(this.childNodes) })
+    },
+    siblings: function(selector){
+      return filtered(this.map(function(i, el){
+        return filter.call(children(el.parentNode), function(child){ return child!==el })
+      }), selector)
+    },
+    empty: function(){
+      return this.each(function(){ this.innerHTML = '' })
+    },
+    // `pluck` is borrowed from Prototype.js
+    pluck: function(property){
+      return $.map(this, function(el){ return el[property] })
+    },
+    show: function(){
+      return this.each(function(){
+        this.style.display == "none" && (this.style.display = '')
+        if (getComputedStyle(this, '').getPropertyValue("display") == "none")
+          this.style.display = defaultDisplay(this.nodeName)
+      })
+    },
+    replaceWith: function(newContent){
+      return this.before(newContent).remove()
+    },
+    wrap: function(structure){
+      var func = isFunction(structure)
+      if (this[0] && !func)
+        var dom   = $(structure).get(0),
+            clone = dom.parentNode || this.length > 1
+
+      return this.each(function(index){
+        $(this).wrapAll(
+          func ? structure.call(this, index) :
+            clone ? dom.cloneNode(true) : dom
+        )
+      })
+    },
+    wrapAll: function(structure){
+      if (this[0]) {
+        $(this[0]).before(structure = $(structure))
+        var children
+        // drill down to the inmost element
+        while ((children = structure.children()).length) structure = children.first()
+        $(structure).append(this)
+      }
+      return this
+    },
+    wrapInner: function(structure){
+      var func = isFunction(structure)
+      return this.each(function(index){
+        var self = $(this), contents = self.contents(),
+            dom  = func ? structure.call(this, index) : structure
+        contents.length ? contents.wrapAll(dom) : self.append(dom)
+      })
+    },
+    unwrap: function(){
+      this.parent().each(function(){
+        $(this).replaceWith($(this).children())
+      })
+      return this
+    },
+    clone: function(){
+      return this.map(function(){ return this.cloneNode(true) })
+    },
+    hide: function(){
+      return this.css("display", "none")
+    },
+    toggle: function(setting){
+      return this.each(function(){
+        var el = $(this)
+        ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide()
+      })
+    },
+    prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') },
+    next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') },
+    html: function(html){
+      return arguments.length === 0 ?
+        (this.length > 0 ? this[0].innerHTML : null) :
+        this.each(function(idx){
+          var originHtml = this.innerHTML
+          $(this).empty().append( funcArg(this, html, idx, originHtml) )
+        })
+    },
+    text: function(text){
+      return arguments.length === 0 ?
+        (this.length > 0 ? this[0].textContent : null) :
+        this.each(function(){ this.textContent = (text === undefined) ? '' : ''+text })
+    },
+    attr: function(name, value){
+      var result
+      return (typeof name == 'string' && value === undefined) ?
+        (this.length == 0 || this[0].nodeType !== 1 ? undefined :
+          (name == 'value' && this[0].nodeName == 'INPUT') ? this.val() :
+          (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result
+        ) :
+        this.each(function(idx){
+          if (this.nodeType !== 1) return
+          if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
+          else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
+        })
+    },
+    removeAttr: function(name){
+      return this.each(function(){ this.nodeType === 1 && setAttribute(this, name) })
+    },
+    prop: function(name, value){
+      name = propMap[name] || name
+      return (value === undefined) ?
+        (this[0] && this[0][name]) :
+        this.each(function(idx){
+          this[name] = funcArg(this, value, idx, this[name])
+        })
+    },
+    data: function(name, value){
+      var data = this.attr('data-' + name.replace(capitalRE, '-$1').toLowerCase(), value)
+      return data !== null ? deserializeValue(data) : undefined
+    },
+    val: function(value){
+      return arguments.length === 0 ?
+        (this[0] && (this[0].multiple ?
+           $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') :
+           this[0].value)
+        ) :
+        this.each(function(idx){
+          this.value = funcArg(this, value, idx, this.value)
+        })
+    },
+    offset: function(coordinates){
+      if (coordinates) return this.each(function(index){
+        var $this = $(this),
+            coords = funcArg(this, coordinates, index, $this.offset()),
+            parentOffset = $this.offsetParent().offset(),
+            props = {
+              top:  coords.top  - parentOffset.top,
+              left: coords.left - parentOffset.left
+            }
+
+        if ($this.css('position') == 'static') props['position'] = 'relative'
+        $this.css(props)
+      })
+      if (this.length==0) return null
+      var obj = this[0].getBoundingClientRect()
+      return {
+        left: obj.left + window.pageXOffset,
+        top: obj.top + window.pageYOffset,
+        width: Math.round(obj.width),
+        height: Math.round(obj.height)
+      }
+    },
+    css: function(property, value){
+      if (arguments.length < 2) {
+        var element = this[0], computedStyle = getComputedStyle(element, '')
+        if(!element) return
+        if (typeof property == 'string')
+          return element.style[camelize(property)] || computedStyle.getPropertyValue(property)
+        else if (isArray(property)) {
+          var props = {}
+          $.each(isArray(property) ? property: [property], function(_, prop){
+            props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))
+          })
+          return props
+        }
+      }
+
+      var css = ''
+      if (type(property) == 'string') {
+        if (!value && value !== 0)
+          this.each(function(){ this.style.removeProperty(dasherize(property)) })
+        else
+          css = dasherize(property) + ":" + maybeAddPx(property, value)
+      } else {
+        for (key in property)
+          if (!property[key] && property[key] !== 0)
+            this.each(function(){ this.style.removeProperty(dasherize(key)) })
+          else
+            css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'
+      }
+
+      return this.each(function(){ this.style.cssText += ';' + css })
+    },
+    index: function(element){
+      return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])
+    },
+    hasClass: function(name){
+      if (!name) return false
+      return emptyArray.some.call(this, function(el){
+        return this.test(className(el))
+      }, classRE(name))
+    },
+    addClass: function(name){
+      if (!name) return this
+      return this.each(function(idx){
+        classList = []
+        var cls = className(this), newName = funcArg(this, name, idx, cls)
+        newName.split(/\s+/g).forEach(function(klass){
+          if (!$(this).hasClass(klass)) classList.push(klass)
+        }, this)
+        classList.length && className(this, cls + (cls ? " " : "") + classList.join(" "))
+      })
+    },
+    removeClass: function(name){
+      return this.each(function(idx){
+        if (name === undefined) return className(this, '')
+        classList = className(this)
+        funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){
+          classList = classList.replace(classRE(klass), " ")
+        })
+        className(this, classList.trim())
+      })
+    },
+    toggleClass: function(name, when){
+      if (!name) return this
+      return this.each(function(idx){
+        var $this = $(this), names = funcArg(this, name, idx, className(this))
+        names.split(/\s+/g).forEach(function(klass){
+          (when === undefined ? !$this.hasClass(klass) : when) ?
+            $this.addClass(klass) : $this.removeClass(klass)
+        })
+      })
+    },
+    scrollTop: function(value){
+      if (!this.length) return
+      var hasScrollTop = 'scrollTop' in this[0]
+      if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset
+      return this.each(hasScrollTop ?
+        function(){ this.scrollTop = value } :
+        function(){ this.scrollTo(this.scrollX, value) })
+    },
+    scrollLeft: function(value){
+      if (!this.length) return
+      var hasScrollLeft = 'scrollLeft' in this[0]
+      if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset
+      return this.each(hasScrollLeft ?
+        function(){ this.scrollLeft = value } :
+        function(){ this.scrollTo(value, this.scrollY) })
+    },
+    position: function() {
+      if (!this.length) return
+
+      var elem = this[0],
+        // Get *real* offsetParent
+        offsetParent = this.offsetParent(),
+        // Get correct offsets
+        offset       = this.offset(),
+        parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset()
+
+      // Subtract element margins
+      // note: when an element has margin: auto the offsetLeft and marginLeft
+      // are the same in Safari causing offset.left to incorrectly be 0
+      offset.top  -= parseFloat( $(elem).css('margin-top') ) || 0
+      offset.left -= parseFloat( $(elem).css('margin-left') ) || 0
+
+      // Add offsetParent borders
+      parentOffset.top  += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0
+      parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0
+
+      // Subtract the two offsets
+      return {
+        top:  offset.top  - parentOffset.top,
+        left: offset.left - parentOffset.left
+      }
+    },
+    offsetParent: function() {
+      return this.map(function(){
+        var parent = this.offsetParent || document.body
+        while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static")
+          parent = parent.offsetParent
+        return parent
+      })
+    }
+  }
+
+  // for now
+  $.fn.detach = $.fn.remove
+
+  // Generate the `width` and `height` functions
+  ;['width', 'height'].forEach(function(dimension){
+    var dimensionProperty =
+      dimension.replace(/./, function(m){ return m[0].toUpperCase() })
+
+    $.fn[dimension] = function(value){
+      var offset, el = this[0]
+      if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] :
+        isDocument(el) ? el.documentElement['scroll' + dimensionProperty] :
+        (offset = this.offset()) && offset[dimension]
+      else return this.each(function(idx){
+        el = $(this)
+        el.css(dimension, funcArg(this, value, idx, el[dimension]()))
+      })
+    }
+  })
+
+  function traverseNode(node, fun) {
+    fun(node)
+    for (var key in node.childNodes) traverseNode(node.childNodes[key], fun)
+  }
+
+  // Generate the `after`, `prepend`, `before`, `append`,
+  // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.
+  adjacencyOperators.forEach(function(operator, operatorIndex) {
+    var inside = operatorIndex % 2 //=> prepend, append
+
+    $.fn[operator] = function(){
+      // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
+      var argType, nodes = $.map(arguments, function(arg) {
+            argType = type(arg)
+            return argType == "object" || argType == "array" || arg == null ?
+              arg : zepto.fragment(arg)
+          }),
+          parent, copyByClone = this.length > 1
+      if (nodes.length < 1) return this
+
+      return this.each(function(_, target){
+        parent = inside ? target : target.parentNode
+
+        // convert all methods to a "before" operation
+        target = operatorIndex == 0 ? target.nextSibling :
+                 operatorIndex == 1 ? target.firstChild :
+                 operatorIndex == 2 ? target :
+                 null
+
+        nodes.forEach(function(node){
+          if (copyByClone) node = node.cloneNode(true)
+          else if (!parent) return $(node).remove()
+
+          traverseNode(parent.insertBefore(node, target), function(el){
+            if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' &&
+               (!el.type || el.type === 'text/javascript') && !el.src)
+              window['eval'].call(window, el.innerHTML)
+          })
+        })
+      })
+    }
+
+    // after    => insertAfter
+    // prepend  => prependTo
+    // before   => insertBefore
+    // append   => appendTo
+    $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){
+      $(html)[operator](this)
+      return this
+    }
+  })
+
+  zepto.Z.prototype = $.fn
+
+  // Export internal API functions in the `$.zepto` namespace
+  zepto.uniq = uniq
+  zepto.deserializeValue = deserializeValue
+  $.zepto = zepto
+
+  return $
+})()
+
+window.Zepto = Zepto
+window.$ === undefined && (window.$ = Zepto)
+
+;(function($){
+  var _zid = 1, undefined,
+      slice = Array.prototype.slice,
+      isFunction = $.isFunction,
+      isString = function(obj){ return typeof obj == 'string' },
+      handlers = {},
+      specialEvents={},
+      focusinSupported = 'onfocusin' in window,
+      focus = { focus: 'focusin', blur: 'focusout' },
+      hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }
+
+  specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'
+
+  function zid(element) {
+    return element._zid || (element._zid = _zid++)
+  }
+  function findHandlers(element, event, fn, selector) {
+    event = parse(event)
+    if (event.ns) var matcher = matcherFor(event.ns)
+    return (handlers[zid(element)] || []).filter(function(handler) {
+      return handler
+        && (!event.e  || handler.e == event.e)
+        && (!event.ns || matcher.test(handler.ns))
+        && (!fn       || zid(handler.fn) === zid(fn))
+        && (!selector || handler.sel == selector)
+    })
+  }
+  function parse(event) {
+    var parts = ('' + event).split('.')
+    return {e: parts[0], ns: parts.slice(1).sort().join(' ')}
+  }
+  function matcherFor(ns) {
+    return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)')
+  }
+
+  function eventCapture(handler, captureSetting) {
+    return handler.del &&
+      (!focusinSupported && (handler.e in focus)) ||
+      !!captureSetting
+  }
+
+  function realEvent(type) {
+    return hover[type] || (focusinSupported && focus[type]) || type
+  }
+
+  function add(element, events, fn, data, selector, delegator, capture){
+    var id = zid(element), set = (handlers[id] || (handlers[id] = []))
+    events.split(/\s/).forEach(function(event){
+      if (event == 'ready') return $(document).ready(fn)
+      var handler   = parse(event)
+      handler.fn    = fn
+      handler.sel   = selector
+      // emulate mouseenter, mouseleave
+      if (handler.e in hover) fn = function(e){
+        var related = e.relatedTarget
+        if (!related || (related !== this && !$.contains(this, related)))
+          return handler.fn.apply(this, arguments)
+      }
+      handler.del   = delegator
+      var callback  = delegator || fn
+      handler.proxy = function(e){
+        e = compatible(e)
+        if (e.isImmediatePropagationStopped()) return
+        e.data = data
+        var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args))
+        if (result === false) e.preventDefault(), e.stopPropagation()
+        return result
+      }
+      handler.i = set.length
+      set.push(handler)
+      if ('addEventListener' in element)
+        element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
+    })
+  }
+  function remove(element, events, fn, selector, capture){
+    var id = zid(element)
+    ;(events || '').split(/\s/).forEach(function(event){
+      findHandlers(element, event, fn, selector).forEach(function(handler){
+        delete handlers[id][handler.i]
+      if ('removeEventListener' in element)
+        element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
+      })
+    })
+  }
+
+  $.event = { add: add, remove: remove }
+
+  $.proxy = function(fn, context) {
+    if (isFunction(fn)) {
+      var proxyFn = function(){ return fn.apply(context, arguments) }
+      proxyFn._zid = zid(fn)
+      return proxyFn
+    } else if (isString(context)) {
+      return $.proxy(fn[context], fn)
+    } else {
+      throw new TypeError("expected function")
+    }
+  }
+
+  $.fn.bind = function(event, data, callback){
+    return this.on(event, data, callback)
+  }
+  $.fn.unbind = function(event, callback){
+    return this.off(event, callback)
+  }
+  $.fn.one = function(event, selector, data, callback){
+    return this.on(event, selector, data, callback, 1)
+  }
+
+  var returnTrue = function(){return true},
+      returnFalse = function(){return false},
+      ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/,
+      eventMethods = {
+        preventDefault: 'isDefaultPrevented',
+        stopImmediatePropagation: 'isImmediatePropagationStopped',
+        stopPropagation: 'isPropagationStopped'
+      }
+
+  function compatible(event, source) {
+    if (source || !event.isDefaultPrevented) {
+      source || (source = event)
+
+      $.each(eventMethods, function(name, predicate) {
+        var sourceMethod = source[name]
+        event[name] = function(){
+          this[predicate] = returnTrue
+          return sourceMethod && sourceMethod.apply(source, arguments)
+        }
+        event[predicate] = returnFalse
+      })
+
+      if (source.defaultPrevented !== undefined ? source.defaultPrevented :
+          'returnValue' in source ? source.returnValue === false :
+          source.getPreventDefault && source.getPreventDefault())
+        event.isDefaultPrevented = returnTrue
+    }
+    return event
+  }
+
+  function createProxy(event) {
+    var key, proxy = { originalEvent: event }
+    for (key in event)
+      if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]
+
+    return compatible(proxy, event)
+  }
+
+  $.fn.delegate = function(selector, event, callback){
+    return this.on(event, selector, callback)
+  }
+  $.fn.undelegate = function(selector, event, callback){
+    return this.off(event, selector, callback)
+  }
+
+  $.fn.live = function(event, callback){
+    $(document.body).delegate(this.selector, event, callback)
+    return this
+  }
+  $.fn.die = function(event, callback){
+    $(document.body).undelegate(this.selector, event, callback)
+    return this
+  }
+
+  $.fn.on = function(event, selector, data, callback, one){
+    var autoRemove, delegator, $this = this
+    if (event && !isString(event)) {
+      $.each(event, function(type, fn){
+        $this.on(type, selector, data, fn, one)
+      })
+      return $this
+    }
+
+    if (!isString(selector) && !isFunction(callback) && callback !== false)
+      callback = data, data = selector, selector = undefined
+    if (isFunction(data) || data === false)
+      callback = data, data = undefined
+
+    if (callback === false) callback = returnFalse
+
+    return $this.each(function(_, element){
+      if (one) autoRemove = function(e){
+        remove(element, e.type, callback)
+        return callback.apply(this, arguments)
+      }
+
+      if (selector) delegator = function(e){
+        var evt, match = $(e.target).closest(selector, element).get(0)
+        if (match && match !== element) {
+          evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element})
+          return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1)))
+        }
+      }
+
+      add(element, event, callback, data, selector, delegator || autoRemove)
+    })
+  }
+  $.fn.off = function(event, selector, callback){
+    var $this = this
+    if (event && !isString(event)) {
+      $.each(event, function(type, fn){
+        $this.off(type, selector, fn)
+      })
+      return $this
+    }
+
+    if (!isString(selector) && !isFunction(callback) && callback !== false)
+      callback = selector, selector = undefined
+
+    if (callback === false) callback = returnFalse
+
+    return $this.each(function(){
+      remove(this, event, callback, selector)
+    })
+  }
+
+  $.fn.trigger = function(event, args){
+    event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)
+    event._args = args
+    return this.each(function(){
+      // items in the collection might not be DOM elements
+      if('dispatchEvent' in this) this.dispatchEvent(event)
+      else $(this).triggerHandler(event, args)
+    })
+  }
+
+  // triggers event handlers on current element just as if an event occurred,
+  // doesn't trigger an actual event, doesn't bubble
+  $.fn.triggerHandler = function(event, args){
+    var e, result
+    this.each(function(i, element){
+      e = createProxy(isString(event) ? $.Event(event) : event)
+      e._args = args
+      e.target = element
+      $.each(findHandlers(element, event.type || event), function(i, handler){
+        result = handler.proxy(e)
+        if (e.isImmediatePropagationStopped()) return false
+      })
+    })
+    return result
+  }
+
+  // shortcut methods for `.bind(event, fn)` for each event type
+  ;('focusin focusout load resize scroll unload click dblclick '+
+  'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+
+  'change select keydown keypress keyup error').split(' ').forEach(function(event) {
+    $.fn[event] = function(callback) {
+      return callback ?
+        this.bind(event, callback) :
+        this.trigger(event)
+    }
+  })
+
+  ;['focus', 'blur'].forEach(function(name) {
+    $.fn[name] = function(callback) {
+      if (callback) this.bind(name, callback)
+      else this.each(function(){
+        try { this[name]() }
+        catch(e) {}
+      })
+      return this
+    }
+  })
+
+  $.Event = function(type, props) {
+    if (!isString(type)) props = type, type = props.type
+    var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true
+    if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
+    event.initEvent(type, bubbles, true)
+    return compatible(event)
+  }
+
+})(Zepto)
+
+;(function($){
+  var jsonpID = 0,
+      document = window.document,
+      key,
+      name,
+      rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+      scriptTypeRE = /^(?:text|application)\/javascript/i,
+      xmlTypeRE = /^(?:text|application)\/xml/i,
+      jsonType = 'application/json',
+      htmlType = 'text/html',
+      blankRE = /^\s*$/
+
+  // trigger a custom event and return false if it was cancelled
+  function triggerAndReturn(context, eventName, data) {
+    var event = $.Event(eventName)
+    $(context).trigger(event, data)
+    return !event.isDefaultPrevented()
+  }
+
+  // trigger an Ajax "global" event
+  function triggerGlobal(settings, context, eventName, data) {
+    if (settings.global) return triggerAndReturn(context || document, eventName, data)
+  }
+
+  // Number of active Ajax requests
+  $.active = 0
+
+  function ajaxStart(settings) {
+    if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart')
+  }
+  function ajaxStop(settings) {
+    if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop')
+  }
+
+  // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable
+  function ajaxBeforeSend(xhr, settings) {
+    var context = settings.context
+    if (settings.beforeSend.call(context, xhr, settings) === false ||
+        triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false)
+      return false
+
+    triggerGlobal(settings, context, 'ajaxSend', [xhr, settings])
+  }
+  function ajaxSuccess(data, xhr, settings, deferred) {
+    var context = settings.context, status = 'success'
+    settings.success.call(context, data, status, xhr)
+    if (deferred) deferred.resolveWith(context, [data, status, xhr])
+    triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data])
+    ajaxComplete(status, xhr, settings)
+  }
+  // type: "timeout", "error", "abort", "parsererror"
+  function ajaxError(error, type, xhr, settings, deferred) {
+    var context = settings.context
+    settings.error.call(context, xhr, type, error)
+    if (deferred) deferred.rejectWith(context, [xhr, type, error])
+    triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type])
+    ajaxComplete(type, xhr, settings)
+  }
+  // status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
+  function ajaxComplete(status, xhr, settings) {
+    var context = settings.context
+    settings.complete.call(context, xhr, status)
+    triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings])
+    ajaxStop(settings)
+  }
+
+  // Empty function, used as default callback
+  function empty() {}
+
+  $.ajaxJSONP = function(options, deferred){
+    if (!('type' in options)) return $.ajax(options)
+
+    var _callbackName = options.jsonpCallback,
+      callbackName = ($.isFunction(_callbackName) ?
+        _callbackName() : _callbackName) || ('jsonp' + (++jsonpID)),
+      script = document.createElement('script'),
+      originalCallback = window[callbackName],
+      responseData,
+      abort = function(errorType) {
+        $(script).triggerHandler('error', errorType || 'abort')
+      },
+      xhr = { abort: abort }, abortTimeout
+
+    if (deferred) deferred.promise(xhr)
+
+    $(script).on('load error', function(e, errorType){
+      clearTimeout(abortTimeout)
+      $(script).off().remove()
+
+      if (e.type == 'error' || !responseData) {
+        ajaxError(null, errorType || 'error', xhr, options, deferred)
+      } else {
+        ajaxSuccess(responseData[0], xhr, options, deferred)
+      }
+
+      window[callbackName] = originalCallback
+      if (responseData && $.isFunction(originalCallback))
+        originalCallback(responseData[0])
+
+      originalCallback = responseData = undefined
+    })
+
+    if (ajaxBeforeSend(xhr, options) === false) {
+      abort('abort')
+      return xhr
+    }
+
+    window[callbackName] = function(){
+      responseData = arguments
+    }
+
+    script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName)
+    document.head.appendChild(script)
+
+    if (options.timeout > 0) abortTimeout = setTimeout(function(){
+      abort('timeout')
+    }, options.timeout)
+
+    return xhr
+  }
+
+  $.ajaxSettings = {
+    // Default type of request
+    type: 'GET',
+    // Callback that is executed before request
+    beforeSend: empty,
+    // Callback that is executed if the request succeeds
+    success: empty,
+    // Callback that is executed the the server drops error
+    error: empty,
+    // Callback that is executed on request complete (both: error and success)
+    complete: empty,
+    // The context for the callbacks
+    context: null,
+    // Whether to trigger "global" Ajax events
+    global: true,
+    // Transport
+    xhr: function () {
+      return new window.XMLHttpRequest()
+    },
+    // MIME types mapping
+    // IIS returns Javascript as "application/x-javascript"
+    accepts: {
+      script: 'text/javascript, application/javascript, application/x-javascript',
+      json:   jsonType,
+      xml:    'application/xml, text/xml',
+      html:   htmlType,
+      text:   'text/plain'
+    },
+    // Whether the request is to another domain
+    crossDomain: false,
+    // Default timeout
+    timeout: 0,
+    // Whether data should be serialized to string
+    processData: true,
+    // Whether the browser should be allowed to cache GET responses
+    cache: true
+  }
+
+  function mimeToDataType(mime) {
+    if (mime) mime = mime.split(';', 2)[0]
+    return mime && ( mime == htmlType ? 'html' :
+      mime == jsonType ? 'json' :
+      scriptTypeRE.test(mime) ? 'script' :
+      xmlTypeRE.test(mime) && 'xml' ) || 'text'
+  }
+
+  function appendQuery(url, query) {
+    if (query == '') return url
+    return (url + '&' + query).replace(/[&?]{1,2}/, '?')
+  }
+
+  // serialize payload and append it to the URL for GET requests
+  function serializeData(options) {
+    if (options.processData && options.data && $.type(options.data) != "string")
+      options.data = $.param(options.data, options.traditional)
+    if (options.data && (!options.type || options.type.toUpperCase() == 'GET'))
+      options.url = appendQuery(options.url, options.data), options.data = undefined
+  }
+
+  $.ajax = function(options){
+    var settings = $.extend({}, options || {}),
+        deferred = $.Deferred && $.Deferred()
+    for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key]
+
+    ajaxStart(settings)
+
+    if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) &&
+      RegExp.$2 != window.location.host
+
+    if (!settings.url) settings.url = window.location.toString()
+    serializeData(settings)
+    if (settings.cache === false) settings.url = appendQuery(settings.url, '_=' + Date.now())
+
+    var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url)
+    if (dataType == 'jsonp' || hasPlaceholder) {
+      if (!hasPlaceholder)
+        settings.url = appendQuery(settings.url,
+          settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?')
+      return $.ajaxJSONP(settings, deferred)
+    }
+
+    var mime = settings.accepts[dataType],
+        headers = { },
+        setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] },
+        protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol,
+        xhr = settings.xhr(),
+        nativeSetHeader = xhr.setRequestHeader,
+        abortTimeout
+
+    if (deferred) deferred.promise(xhr)
+
+    if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest')
+    setHeader('Accept', mime || '*/*')
+    if (mime = settings.mimeType || mime) {
+      if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0]
+      xhr.overrideMimeType && xhr.overrideMimeType(mime)
+    }
+    if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET'))
+      setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded')
+
+    if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name])
+    xhr.setRequestHeader = setHeader
+
+    xhr.onreadystatechange = function(){
+      if (xhr.readyState == 4) {
+        xhr.onreadystatechange = empty
+        clearTimeout(abortTimeout)
+        var result, error = false
+        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) {
+          dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type'))
+          result = xhr.responseText
+
+          try {
+            // http://perfectionkills.com/global-eval-what-are-the-options/
+            if (dataType == 'script')    (1,eval)(result)
+            else if (dataType == 'xml')  result = xhr.responseXML
+            else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result)
+          } catch (e) { error = e }
+
+          if (error) ajaxError(error, 'parsererror', xhr, settings, deferred)
+          else ajaxSuccess(result, xhr, settings, deferred)
+        } else {
+          ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred)
+        }
+      }
+    }
+
+    if (ajaxBeforeSend(xhr, settings) === false) {
+      xhr.abort()
+      ajaxError(null, 'abort', xhr, settings, deferred)
+      return xhr
+    }
+
+    if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name]
+
+    var async = 'async' in settings ? settings.async : true
+    xhr.open(settings.type, settings.url, async, settings.username, settings.password)
+
+    for (name in headers) nativeSetHeader.apply(xhr, headers[name])
+
+    if (settings.timeout > 0) abortTimeout = setTimeout(function(){
+        xhr.onreadystatechange = empty
+        xhr.abort()
+        ajaxError(null, 'timeout', xhr, settings, deferred)
+      }, settings.timeout)
+
+    // avoid sending empty string (#319)
+    xhr.send(settings.data ? settings.data : null)
+    return xhr
+  }
+
+  // handle optional data/success arguments
+  function parseArguments(url, data, success, dataType) {
+    if ($.isFunction(data)) dataType = success, success = data, data = undefined
+    if (!$.isFunction(success)) dataType = success, success = undefined
+    return {
+      url: url
+    , data: data
+    , success: success
+    , dataType: dataType
+    }
+  }
+
+  $.get = function(/* url, data, success, dataType */){
+    return $.ajax(parseArguments.apply(null, arguments))
+  }
+
+  $.post = function(/* url, data, success, dataType */){
+    var options = parseArguments.apply(null, arguments)
+    options.type = 'POST'
+    return $.ajax(options)
+  }
+
+  $.getJSON = function(/* url, data, success */){
+    var options = parseArguments.apply(null, arguments)
+    options.dataType = 'json'
+    return $.ajax(options)
+  }
+
+  $.fn.load = function(url, data, success){
+    if (!this.length) return this
+    var self = this, parts = url.split(/\s/), selector,
+        options = parseArguments(url, data, success),
+        callback = options.success
+    if (parts.length > 1) options.url = parts[0], selector = parts[1]
+    options.success = function(response){
+      self.html(selector ?
+        $('<div>').html(response.replace(rscript, "")).find(selector)
+        : response)
+      callback && callback.apply(self, arguments)
+    }
+    $.ajax(options)
+    return this
+  }
+
+  var escape = encodeURIComponent
+
+  function serialize(params, obj, traditional, scope){
+    var type, array = $.isArray(obj), hash = $.isPlainObject(obj)
+    $.each(obj, function(key, value) {
+      type = $.type(value)
+      if (scope) key = traditional ? scope :
+        scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']'
+      // handle data in serializeArray() format
+      if (!scope && array) params.add(value.name, value.value)
+      // recurse into nested objects
+      else if (type == "array" || (!traditional && type == "object"))
+        serialize(params, value, traditional, key)
+      else params.add(key, value)
+    })
+  }
+
+  $.param = function(obj, traditional){
+    var params = []
+    params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) }
+    serialize(params, obj, traditional)
+    return params.join('&').replace(/%20/g, '+')
+  }
+})(Zepto)
+
+;(function($){
+  $.fn.serializeArray = function() {
+    var result = [], el
+    $([].slice.call(this.get(0).elements)).each(function(){
+      el = $(this)
+      var type = el.attr('type')
+      if (this.nodeName.toLowerCase() != 'fieldset' &&
+        !this.disabled && type != 'submit' && type != 'reset' && type != 'button' &&
+        ((type != 'radio' && type != 'checkbox') || this.checked))
+        result.push({
+          name: el.attr('name'),
+          value: el.val()
+        })
+    })
+    return result
+  }
+
+  $.fn.serialize = function(){
+    var result = []
+    this.serializeArray().forEach(function(elm){
+      result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value))
+    })
+    return result.join('&')
+  }
+
+  $.fn.submit = function(callback) {
+    if (callback) this.bind('submit', callback)
+    else if (this.length) {
+      var event = $.Event('submit')
+      this.eq(0).trigger(event)
+      if (!event.isDefaultPrevented()) this.get(0).submit()
+    }
+    return this
+  }
+
+})(Zepto)
+
+;(function($){
+  // __proto__ doesn't exist on IE<11, so redefine
+  // the Z function to use object extension instead
+  if (!('__proto__' in {})) {
+    $.extend($.zepto, {
+      Z: function(dom, selector){
+        dom = dom || []
+        $.extend(dom, $.fn)
+        dom.selector = selector || ''
+        dom.__Z = true
+        return dom
+      },
+      // this is a kludge but works
+      isZ: function(object){
+        return $.type(object) === 'array' && '__Z' in object
+      }
+    })
+  }
+
+  // getComputedStyle shouldn't freak out when called
+  // without a valid element as argument
+  try {
+    getComputedStyle(undefined)
+  } catch(e) {
+    var nativeGetComputedStyle = getComputedStyle;
+    window.getComputedStyle = function(element){
+      try {
+        return nativeGetComputedStyle(element)
+      } catch(e) {
+        return null
+      }
+    }
+  }
+})(Zepto)

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/a9b2849b/cordova-app-test-harness/www/index.html
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/index.html b/cordova-app-test-harness/www/index.html
index 1af7178..a379892 100644
--- a/cordova-app-test-harness/www/index.html
+++ b/cordova-app-test-harness/www/index.html
@@ -10,6 +10,7 @@
     <link rel="stylesheet" type="text/css" href="assets/jasmine-2.0.0/jasmine.css" media="screen">
     <link rel="stylesheet" type="text/css" href="main.css" media="screen">
 
+    <script type="text/javascript" src="assets/zepto.js"></script>
     <script type="text/javascript" src="assets/jasmine-2.0.0/jasmine.js"></script>
     <script type="text/javascript" src="assets/jasmine-2.0.0/jasmine-html.js"></script>
 

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/a9b2849b/cordova-app-test-harness/www/last_update
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/last_update b/cordova-app-test-harness/www/last_update
new file mode 100644
index 0000000..dbc315f
--- /dev/null
+++ b/cordova-app-test-harness/www/last_update
@@ -0,0 +1 @@
+Thu Apr 24 12:05:19 EDT 2014

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/a9b2849b/cordova-app-test-harness/www/main.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/main.js b/cordova-app-test-harness/www/main.js
index 54750b0..bdaaca9 100644
--- a/cordova-app-test-harness/www/main.js
+++ b/cordova-app-test-harness/www/main.js
@@ -122,7 +122,27 @@ function runMain() {
 
 /******************************************************************************/
 
+function startAutoReload() {
+  var last_update = null;
+  setInterval(function() {
+    $.get('last_update', function(time) {
+      console.log(time);
+      if (!last_update) {
+        last_update = time;
+        return;
+      } else if (last_update === time) {
+        return;
+      } else {
+        location.reload();
+      }
+    });
+  }, 250);
+}
+
+/******************************************************************************/
+
 document.addEventListener("deviceready", function() {
+  startAutoReload();
   window.medic.load(function() {
     if (window.medic.enabled) {
       setMode('auto');


[9/9] git commit: First working plugin test in new style

Posted by mm...@apache.org.
First working plugin test in new style


Project: http://git-wip-us.apache.org/repos/asf/cordova-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-labs/commit/7d614b92
Tree: http://git-wip-us.apache.org/repos/asf/cordova-labs/tree/7d614b92
Diff: http://git-wip-us.apache.org/repos/asf/cordova-labs/diff/7d614b92

Branch: refs/heads/cdvtest
Commit: 7d614b920899e9dc442f6d5e44b307605e5f8fb8
Parents: a9b2849
Author: Michal Mocny <mm...@gmail.com>
Authored: Thu Apr 24 14:29:58 2014 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Thu Apr 24 14:29:58 2014 -0400

----------------------------------------------------------------------
 cordova-app-test-harness/.gitignore      |  2 ++
 cordova-app-test-harness/www/last_update |  2 +-
 cordova-app-test-harness/www/main.js     |  1 -
 cordova-app-test-harness/www/tests.js    | 19 +++++++++++++++++++
 4 files changed, 22 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/7d614b92/cordova-app-test-harness/.gitignore
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/.gitignore b/cordova-app-test-harness/.gitignore
index c98dbcd..77cc947 100644
--- a/cordova-app-test-harness/.gitignore
+++ b/cordova-app-test-harness/.gitignore
@@ -1,2 +1,4 @@
 platforms
 plugins
+www/last_update
+node_modules

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/7d614b92/cordova-app-test-harness/www/last_update
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/last_update b/cordova-app-test-harness/www/last_update
index dbc315f..8884c8a 100644
--- a/cordova-app-test-harness/www/last_update
+++ b/cordova-app-test-harness/www/last_update
@@ -1 +1 @@
-Thu Apr 24 12:05:19 EDT 2014
+Thu Apr 24 12:18:00 EDT 2014

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/7d614b92/cordova-app-test-harness/www/main.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/main.js b/cordova-app-test-harness/www/main.js
index bdaaca9..256ac09 100644
--- a/cordova-app-test-harness/www/main.js
+++ b/cordova-app-test-harness/www/main.js
@@ -126,7 +126,6 @@ function startAutoReload() {
   var last_update = null;
   setInterval(function() {
     $.get('last_update', function(time) {
-      console.log(time);
       if (!last_update) {
         last_update = time;
         return;

http://git-wip-us.apache.org/repos/asf/cordova-labs/blob/7d614b92/cordova-app-test-harness/www/tests.js
----------------------------------------------------------------------
diff --git a/cordova-app-test-harness/www/tests.js b/cordova-app-test-harness/www/tests.js
index a5421d9..8a1f21f 100644
--- a/cordova-app-test-harness/www/tests.js
+++ b/cordova-app-test-harness/www/tests.js
@@ -26,6 +26,25 @@ exports.registerAutoTests = function(api, fn) {
 };
 
 exports.defineAutoTests = function(jasmineInterface) {
+  // one time
+  var test_modules = cordova.require('cordova/plugin_list')
+    .map(function(jsmodule) {
+      return jsmodule.id;
+    })
+    .filter(function(id) {
+      return /.tests$/.test(id);
+    });
+  test_modules.forEach(function(id) {
+    try {
+      // This runs the tests
+      cordova.require(id);
+    } catch(ex) {
+      logger('Failed to load:', id);
+      return;
+    }
+    logger('Loaded:', id);
+  });
+
   Object.keys(exports.tests).forEach(function(key) {
     if (!exports.tests[key].enabled)
       return;