You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by er...@apache.org on 2020/08/06 11:12:17 UTC

[cordova-plugin-test-framework] 02/04: FR-44 : Update Jasmine version

This is an automated email from the ASF dual-hosted git repository.

erisu pushed a commit to branch feat/jasmine-upgrade
in repository https://gitbox.apache.org/repos/asf/cordova-plugin-test-framework.git

commit 67f08265dcde9099150f17e6b9ca572876f1808d
Author: Sven Emtell <sv...@doremir.com>
AuthorDate: Thu Oct 10 11:00:58 2019 +0200

    FR-44 : Update Jasmine version
---
 .eslintignore                                      |    2 +-
 .ratignore                                         |    2 +-
 www/assets/index.html                              |    6 +-
 www/assets/jasmine-2.4.1/jasmine.js                | 3454 ------------
 .../{jasmine-2.4.1 => jasmine-2.99.0}/boot.js      |    5 +-
 .../{jasmine-2.4.1 => jasmine-2.99.0}/console.js   |    2 +-
 .../jasmine-html.js                                |  144 +-
 .../{jasmine-2.4.1 => jasmine-2.99.0}/jasmine.css  |    1 +
 www/assets/jasmine-2.99.0/jasmine.js               | 5584 ++++++++++++++++++++
 .../jasmine_favicon.png                            |  Bin
 10 files changed, 5703 insertions(+), 3497 deletions(-)

diff --git a/.eslintignore b/.eslintignore
index 85182f7..a5bb78f 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,2 +1,2 @@
-www/assets/jasmine-2.4.1
+www/assets/jasmine-2.99.0
 www/assets/topcoat-0.7.5
\ No newline at end of file
diff --git a/.ratignore b/.ratignore
index ea255bf..11cc15e 100644
--- a/.ratignore
+++ b/.ratignore
@@ -1 +1 @@
-jasmine-2.4.1
+jasmine-2.99.0
diff --git a/www/assets/index.html b/www/assets/index.html
index 8cd498d..5c42d9a 100644
--- a/www/assets/index.html
+++ b/www/assets/index.html
@@ -36,11 +36,11 @@
     <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="topcoat-0.7.5/css/topcoat-mobile-light.min.css">
-    <link rel="stylesheet" type="text/css" href="jasmine-2.4.1/jasmine.css" media="screen">
+    <link rel="stylesheet" type="text/css" href="jasmine-2.99.0/jasmine.css" media="screen">
     <link rel="stylesheet" type="text/css" href="main.css" media="screen">
 
-    <script type="text/javascript" src="jasmine-2.4.1/jasmine.js"></script>
-    <script type="text/javascript" src="jasmine-2.4.1/jasmine-html.js"></script>
+    <script type="text/javascript" src="jasmine-2.99.0/jasmine.js"></script>
+    <script type="text/javascript" src="jasmine-2.99.0/jasmine-html.js"></script>
     <script type="text/javascript" src="jasmine-medic.js"></script>
 
     <script type="text/javascript" src="../cordova.js"></script>
diff --git a/www/assets/jasmine-2.4.1/jasmine.js b/www/assets/jasmine-2.4.1/jasmine.js
deleted file mode 100755
index bea469d..0000000
--- a/www/assets/jasmine-2.4.1/jasmine.js
+++ /dev/null
@@ -1,3454 +0,0 @@
-/*
-Copyright (c) 2008-2015 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.
-*/
-var getJasmineRequireObj = (function (jasmineGlobal) {
-  var jasmineRequire;
-
-  if (typeof module !== 'undefined' && module.exports) {
-    if (typeof global !== 'undefined') {
-      jasmineGlobal = global;
-    } else {
-      jasmineGlobal = {};
-    }
-    jasmineRequire = exports;
-  } else {
-    if (typeof window !== 'undefined' && typeof window.toString === 'function' && window.toString() === '[object GjsGlobal]') {
-      jasmineGlobal = window;
-    }
-    jasmineRequire = jasmineGlobal.jasmineRequire = jasmineGlobal.jasmineRequire || {};
-  }
-
-  function getJasmineRequire() {
-    return jasmineRequire;
-  }
-
-  getJasmineRequire().core = function(jRequire) {
-    var j$ = {};
-
-    jRequire.base(j$, jasmineGlobal);
-    j$.util = jRequire.util();
-    j$.errors = jRequire.errors();
-    j$.Any = jRequire.Any(j$);
-    j$.Anything = jRequire.Anything(j$);
-    j$.CallTracker = jRequire.CallTracker();
-    j$.MockDate = jRequire.MockDate();
-    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$.ArrayContaining = jRequire.ArrayContaining(j$);
-    j$.pp = jRequire.pp(j$);
-    j$.QueueRunner = jRequire.QueueRunner(j$);
-    j$.ReportDispatcher = jRequire.ReportDispatcher();
-    j$.Spec = jRequire.Spec(j$);
-    j$.SpyRegistry = jRequire.SpyRegistry(j$);
-    j$.SpyStrategy = jRequire.SpyStrategy();
-    j$.StringMatching = jRequire.StringMatching(j$);
-    j$.Suite = jRequire.Suite(j$);
-    j$.Timer = jRequire.Timer();
-    j$.TreeProcessor = jRequire.TreeProcessor();
-    j$.version = jRequire.version();
-    j$.Order = jRequire.Order();
-
-    j$.matchers = jRequire.requireMatchers(jRequire, j$);
-
-    return j$;
-  };
-
-  return getJasmineRequire;
-})(this);
-
-getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
-  var availableMatchers = [
-      'toBe',
-      'toBeCloseTo',
-      'toBeDefined',
-      'toBeFalsy',
-      'toBeGreaterThan',
-      'toBeLessThan',
-      'toBeNaN',
-      'toBeNull',
-      'toBeTruthy',
-      'toBeUndefined',
-      'toContain',
-      'toEqual',
-      'toHaveBeenCalled',
-      'toHaveBeenCalledWith',
-      'toHaveBeenCalledTimes',
-      '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$, jasmineGlobal) {
-  j$.unimplementedMethod_ = function() {
-    throw new Error('unimplemented method');
-  };
-
-  j$.MAX_PRETTY_PRINT_DEPTH = 40;
-  j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 100;
-  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$.fnNameFor = function(func) {
-    return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
-  };
-
-  j$.any = function(clazz) {
-    return new j$.Any(clazz);
-  };
-
-  j$.anything = function() {
-    return new j$.Anything();
-  };
-
-  j$.objectContaining = function(sample) {
-    return new j$.ObjectContaining(sample);
-  };
-
-  j$.stringMatching = function(expected) {
-    return new j$.StringMatching(expected);
-  };
-
-  j$.arrayContaining = function(sample) {
-    return new j$.ArrayContaining(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() {
-        var callData = {
-          object: this,
-          args: Array.prototype.slice.apply(arguments)
-        };
-
-        callTracker.track(callData);
-        var returnValue = spyStrategy.exec.apply(this, arguments);
-        callData.returnValue = returnValue;
-
-        return returnValue;
-      };
-
-    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_(baseName) && j$.util.isUndefined(methodNames)) {
-      methodNames = baseName;
-      baseName = 'unknown';
-    }
-
-    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;
-  };
-
-  util.arrayContains = function(array, search) {
-    var i = array.length;
-    while (i--) {
-      if (array[i] === search) {
-        return true;
-      }
-    }
-    return false;
-  };
-
-  util.clone = function(obj) {
-    if (Object.prototype.toString.apply(obj) === '[object Array]') {
-      return obj.slice();
-    }
-
-    var cloned = {};
-    for (var prop in obj) {
-      if (obj.hasOwnProperty(prop)) {
-        cloned[prop] = obj[prop];
-      }
-    }
-
-    return cloned;
-  };
-
-  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.queueableFn = attrs.queueableFn;
-    this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return {befores: [], afters: []}; };
-    this.userContext = attrs.userContext || function() { return {}; };
-    this.onStart = attrs.onStart || 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.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
-
-    if (!this.queueableFn.fn) {
-      this.pend();
-    }
-
-    this.result = {
-      id: this.id,
-      description: this.description,
-      fullName: this.getFullName(),
-      failedExpectations: [],
-      passedExpectations: [],
-      pendingReason: ''
-    };
-  }
-
-  Spec.prototype.addExpectationResult = function(passed, data, isError) {
-    var expectationResult = this.expectationResultFactory(data);
-    if (passed) {
-      this.result.passedExpectations.push(expectationResult);
-    } else {
-      this.result.failedExpectations.push(expectationResult);
-
-      if (this.throwOnExpectationFailure && !isError) {
-        throw new j$.errors.ExpectationFailed();
-      }
-    }
-  };
-
-  Spec.prototype.expect = function(actual) {
-    return this.expectationFactory(actual, this);
-  };
-
-  Spec.prototype.execute = function(onComplete, enabled) {
-    var self = this;
-
-    this.onStart(this);
-
-    if (!this.isExecutable() || this.markedPending || enabled === false) {
-      complete(enabled);
-      return;
-    }
-
-    var fns = this.beforeAndAfterFns();
-    var allFns = fns.befores.concat(this.queueableFn).concat(fns.afters);
-
-    this.queueRunnerFactory({
-      queueableFns: allFns,
-      onException: function() { self.onException.apply(self, arguments); },
-      onComplete: complete,
-      userContext: this.userContext()
-    });
-
-    function complete(enabledAgain) {
-      self.result.status = self.status(enabledAgain);
-      self.resultCallback(self.result);
-
-      if (onComplete) {
-        onComplete();
-      }
-    }
-  };
-
-  Spec.prototype.onException = function onException(e) {
-    if (Spec.isPendingSpecException(e)) {
-      this.pend(extractCustomPendingMessage(e));
-      return;
-    }
-
-    if (e instanceof j$.errors.ExpectationFailed) {
-      return;
-    }
-
-    this.addExpectationResult(false, {
-      matcherName: '',
-      passed: false,
-      expected: '',
-      actual: '',
-      error: e
-    }, true);
-  };
-
-  Spec.prototype.disable = function() {
-    this.disabled = true;
-  };
-
-  Spec.prototype.pend = function(message) {
-    this.markedPending = true;
-    if (message) {
-      this.result.pendingReason = message;
-    }
-  };
-
-  Spec.prototype.getResult = function() {
-    this.result.status = this.status();
-    return this.result;
-  };
-
-  Spec.prototype.status = function(enabled) {
-    if (this.disabled || enabled === false) {
-      return 'disabled';
-    }
-
-    if (this.markedPending) {
-      return 'pending';
-    }
-
-    if (this.result.failedExpectations.length > 0) {
-      return 'failed';
-    } else {
-      return 'passed';
-    }
-  };
-
-  Spec.prototype.isExecutable = function() {
-    return !this.disabled;
-  };
-
-  Spec.prototype.getFullName = function() {
-    return this.getSpecName(this);
-  };
-
-  var extractCustomPendingMessage = function(e) {
-    var fullMessage = e.toString(),
-        boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),
-        boilerplateEnd = boilerplateStart + Spec.pendingSpecExceptionMessage.length;
-
-    return fullMessage.substr(boilerplateEnd);
-  };
-
-  Spec.pendingSpecExceptionMessage = '=> marked Pending';
-
-  Spec.isPendingSpecException = function(e) {
-    return !!(e && e.toString && e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1);
-  };
-
-  return Spec;
-};
-
-if (typeof window == void 0 && typeof exports == 'object') {
-  exports.Spec = jasmineRequire.Spec;
-}
-
-/*jshint bitwise: false*/
-
-getJasmineRequireObj().Order = function() {
-  function Order(options) {
-    this.random = 'random' in options ? options.random : true;
-    var seed = this.seed = options.seed || generateSeed();
-    this.sort = this.random ? randomOrder : naturalOrder;
-
-    function naturalOrder(items) {
-      return items;
-    }
-
-    function randomOrder(items) {
-      var copy = items.slice();
-      copy.sort(function(a, b) {
-        return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id);
-      });
-      return copy;
-    }
-
-    function generateSeed() {
-      return String(Math.random()).slice(-5);
-    }
-
-    // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function
-    // used to get a different output when the key changes slighly.
-    // We use your return to sort the children randomly in a consistent way when
-    // used in conjunction with a seed
-
-    function jenkinsHash(key) {
-      var hash, i;
-      for(hash = i = 0; i < key.length; ++i) {
-        hash += key.charCodeAt(i);
-        hash += (hash << 10);
-        hash ^= (hash >> 6);
-      }
-      hash += (hash << 3);
-      hash ^= (hash >> 11);
-      hash += (hash << 15);
-      return hash;
-    }
-
-  }
-
-  return Order;
-};
-
-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, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global));
-
-    var runnableLookupTable = {};
-    var runnableResources = {};
-
-    var currentSpec = null;
-    var currentlyExecutingSuites = [];
-    var currentDeclarationSuite = null;
-    var throwOnExpectationFailure = false;
-    var random = false;
-    var seed = null;
-
-    var currentSuite = function() {
-      return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
-    };
-
-    var currentRunnable = function() {
-      return currentSpec || currentSuite();
-    };
-
-    var reporter = new j$.ReportDispatcher([
-      'jasmineStarted',
-      'jasmineDone',
-      'suiteStarted',
-      'suiteDone',
-      'specStarted',
-      'specDone'
-    ]);
-
-    this.specFilter = function() {
-      return true;
-    };
-
-    this.addCustomEqualityTester = function(tester) {
-      if(!currentRunnable()) {
-        throw new Error('Custom Equalities must be added in a before function or a spec');
-      }
-      runnableResources[currentRunnable().id].customEqualityTesters.push(tester);
-    };
-
-    this.addMatchers = function(matchersToAdd) {
-      if(!currentRunnable()) {
-        throw new Error('Matchers must be added in a before function or a spec');
-      }
-      var customMatchers = runnableResources[currentRunnable().id].customMatchers;
-      for (var matcherName in matchersToAdd) {
-        customMatchers[matcherName] = matchersToAdd[matcherName];
-      }
-    };
-
-    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: runnableResources[spec.id].customEqualityTesters,
-        customMatchers: runnableResources[spec.id].customMatchers,
-        actual: actual,
-        addExpectationResult: addExpectationResult
-      });
-
-      function addExpectationResult(passed, result) {
-        return spec.addExpectationResult(passed, result);
-      }
-    };
-
-    var defaultResourcesForRunnable = function(id, parentRunnableId) {
-      var resources = {spies: [], customEqualityTesters: [], customMatchers: {}};
-
-      if(runnableResources[parentRunnableId]){
-        resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters);
-        resources.customMatchers = j$.util.clone(runnableResources[parentRunnableId].customMatchers);
-      }
-
-      runnableResources[id] = resources;
-    };
-
-    var clearResourcesForRunnable = function(id) {
-        spyRegistry.clearSpies();
-        delete runnableResources[id];
-    };
-
-    var beforeAndAfterFns = function(suite) {
-      return function() {
-        var befores = [],
-          afters = [];
-
-        while(suite) {
-          befores = befores.concat(suite.beforeFns);
-          afters = afters.concat(suite.afterFns);
-
-          suite = suite.parentSuite;
-        }
-
-        return {
-          befores: befores.reverse(),
-          afters: 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;
-    };
-
-    this.throwOnExpectationFailure = function(value) {
-      throwOnExpectationFailure = !!value;
-    };
-
-    this.throwingExpectationFailures = function() {
-      return throwOnExpectationFailure;
-    };
-
-    this.randomizeTests = function(value) {
-      random = !!value;
-    };
-
-    this.randomTests = function() {
-      return random;
-    };
-
-    this.seed = function(value) {
-      if (value) {
-        seed = value;
-      }
-      return seed;
-    };
-
-    var queueRunnerFactory = function(options) {
-      options.catchException = catchException;
-      options.clearStack = options.clearStack || clearStack;
-      options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
-      options.fail = self.fail;
-
-      new j$.QueueRunner(options).execute();
-    };
-
-    var topSuite = new j$.Suite({
-      env: this,
-      id: getNextSuiteId(),
-      description: 'Jasmine__TopLevel__Suite',
-      queueRunner: queueRunnerFactory
-    });
-    runnableLookupTable[topSuite.id] = topSuite;
-    defaultResourcesForRunnable(topSuite.id);
-    currentDeclarationSuite = topSuite;
-
-    this.topSuite = function() {
-      return topSuite;
-    };
-
-    this.execute = function(runnablesToRun) {
-      if(!runnablesToRun) {
-        if (focusedRunnables.length) {
-          runnablesToRun = focusedRunnables;
-        } else {
-          runnablesToRun = [topSuite.id];
-        }
-      }
-
-      var order = new j$.Order({
-        random: random,
-        seed: seed
-      });
-
-      var processor = new j$.TreeProcessor({
-        tree: topSuite,
-        runnableIds: runnablesToRun,
-        queueRunnerFactory: queueRunnerFactory,
-        nodeStart: function(suite) {
-          currentlyExecutingSuites.push(suite);
-          defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
-          reporter.suiteStarted(suite.result);
-        },
-        nodeComplete: function(suite, result) {
-          if (!suite.disabled) {
-            clearResourcesForRunnable(suite.id);
-          }
-          currentlyExecutingSuites.pop();
-          reporter.suiteDone(result);
-        },
-        orderChildren: function(node) {
-          return order.sort(node.children);
-        }
-      });
-
-      if(!processor.processTree().valid) {
-        throw new Error('Invalid order: would cause a beforeAll or afterAll to be run multiple times');
-      }
-
-      reporter.jasmineStarted({
-        totalSpecsDefined: totalSpecsDefined
-      });
-
-      processor.execute(function() {
-        reporter.jasmineDone({
-          order: order
-        });
-      });
-    };
-
-    this.addReporter = function(reporterToAdd) {
-      reporter.addReporter(reporterToAdd);
-    };
-
-    var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
-      if(!currentRunnable()) {
-        throw new Error('Spies must be created in a before function or a spec');
-      }
-      return runnableResources[currentRunnable().id].spies;
-    }});
-
-    this.spyOn = function() {
-      return spyRegistry.spyOn.apply(spyRegistry, arguments);
-    };
-
-    var suiteFactory = function(description) {
-      var suite = new j$.Suite({
-        env: self,
-        id: getNextSuiteId(),
-        description: description,
-        parentSuite: currentDeclarationSuite,
-        expectationFactory: expectationFactory,
-        expectationResultFactory: expectationResultFactory,
-        throwOnExpectationFailure: throwOnExpectationFailure
-      });
-
-      runnableLookupTable[suite.id] = suite;
-      return suite;
-    };
-
-    this.describe = function(description, specDefinitions) {
-      var suite = suiteFactory(description);
-      if (specDefinitions.length > 0) {
-        throw new Error('describe does not expect a done parameter');
-      }
-      if (currentDeclarationSuite.markedPending) {
-        suite.pend();
-      }
-      addSpecsToSuite(suite, specDefinitions);
-      return suite;
-    };
-
-    this.xdescribe = function(description, specDefinitions) {
-      var suite = suiteFactory(description);
-      suite.pend();
-      addSpecsToSuite(suite, specDefinitions);
-      return suite;
-    };
-
-    var focusedRunnables = [];
-
-    this.fdescribe = function(description, specDefinitions) {
-      var suite = suiteFactory(description);
-      suite.isFocused = true;
-
-      focusedRunnables.push(suite.id);
-      unfocusAncestor();
-      addSpecsToSuite(suite, specDefinitions);
-
-      return suite;
-    };
-
-    function addSpecsToSuite(suite, specDefinitions) {
-      var parentSuite = currentDeclarationSuite;
-      parentSuite.addChild(suite);
-      currentDeclarationSuite = suite;
-
-      var declarationError = null;
-      try {
-        specDefinitions.call(suite);
-      } catch (e) {
-        declarationError = e;
-      }
-
-      if (declarationError) {
-        self.it('encountered a declaration exception', function() {
-          throw declarationError;
-        });
-      }
-
-      currentDeclarationSuite = parentSuite;
-    }
-
-    function findFocusedAncestor(suite) {
-      while (suite) {
-        if (suite.isFocused) {
-          return suite.id;
-        }
-        suite = suite.parentSuite;
-      }
-
-      return null;
-    }
-
-    function unfocusAncestor() {
-      var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
-      if (focusedAncestor) {
-        for (var i = 0; i < focusedRunnables.length; i++) {
-          if (focusedRunnables[i] === focusedAncestor) {
-            focusedRunnables.splice(i, 1);
-            break;
-          }
-        }
-      }
-    }
-
-    var specFactory = function(description, fn, suite, timeout) {
-      totalSpecsDefined++;
-      var spec = new j$.Spec({
-        id: getNextSpecId(),
-        beforeAndAfterFns: beforeAndAfterFns(suite),
-        expectationFactory: expectationFactory,
-        resultCallback: specResultCallback,
-        getSpecName: function(spec) {
-          return getSpecName(spec, suite);
-        },
-        onStart: specStarted,
-        description: description,
-        expectationResultFactory: expectationResultFactory,
-        queueRunnerFactory: queueRunnerFactory,
-        userContext: function() { return suite.clonedSharedUserContext(); },
-        queueableFn: {
-          fn: fn,
-          timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
-        },
-        throwOnExpectationFailure: throwOnExpectationFailure
-      });
-
-      runnableLookupTable[spec.id] = spec;
-
-      if (!self.specFilter(spec)) {
-        spec.disable();
-      }
-
-      return spec;
-
-      function specResultCallback(result) {
-        clearResourcesForRunnable(spec.id);
-        currentSpec = null;
-        reporter.specDone(result);
-      }
-
-      function specStarted(spec) {
-        currentSpec = spec;
-        defaultResourcesForRunnable(spec.id, suite.id);
-        reporter.specStarted(spec.result);
-      }
-    };
-
-    this.it = function(description, fn, timeout) {
-      var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
-      if (currentDeclarationSuite.markedPending) {
-        spec.pend();
-      }
-      currentDeclarationSuite.addChild(spec);
-      return spec;
-    };
-
-    this.xit = function() {
-      var spec = this.it.apply(this, arguments);
-      spec.pend('Temporarily disabled with xit');
-      return spec;
-    };
-
-    this.fit = function(description, fn, timeout){
-      var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
-      currentDeclarationSuite.addChild(spec);
-      focusedRunnables.push(spec.id);
-      unfocusAncestor();
-      return spec;
-    };
-
-    this.expect = function(actual) {
-      if (!currentRunnable()) {
-        throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out');
-      }
-
-      return currentRunnable().expect(actual);
-    };
-
-    this.beforeEach = function(beforeEachFunction, timeout) {
-      currentDeclarationSuite.beforeEach({
-        fn: beforeEachFunction,
-        timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
-      });
-    };
-
-    this.beforeAll = function(beforeAllFunction, timeout) {
-      currentDeclarationSuite.beforeAll({
-        fn: beforeAllFunction,
-        timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
-      });
-    };
-
-    this.afterEach = function(afterEachFunction, timeout) {
-      currentDeclarationSuite.afterEach({
-        fn: afterEachFunction,
-        timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
-      });
-    };
-
-    this.afterAll = function(afterAllFunction, timeout) {
-      currentDeclarationSuite.afterAll({
-        fn: afterAllFunction,
-        timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
-      });
-    };
-
-    this.pending = function(message) {
-      var fullMessage = j$.Spec.pendingSpecExceptionMessage;
-      if(message) {
-        fullMessage += message;
-      }
-      throw fullMessage;
-    };
-
-    this.fail = function(error) {
-      var message = 'Failed';
-      if (error) {
-        message += ': ';
-        message += error.message || error;
-      }
-
-      currentRunnable().addExpectationResult(false, {
-        matcherName: '',
-        passed: false,
-        expected: '',
-        actual: '',
-        message: message,
-        error: error && error.message ? error : null
-      });
-    };
-  }
-
-  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.runDetails = {};
-
-    this.jasmineStarted = function() {
-      this.started = true;
-      status = 'started';
-      timer.start();
-    };
-
-    var executionTime;
-
-    this.jasmineDone = function(runDetails) {
-      this.finished = true;
-      this.runDetails = runDetails;
-      executionTime = timer.elapsed();
-      status = 'done';
-    };
-
-    this.status = function() {
-      return status;
-    };
-
-    var suites = [],
-      suites_hash = {};
-
-    this.suiteStarted = function(result) {
-      suites_hash[result.id] = result;
-    };
-
-    this.suiteDone = function(result) {
-      storeSuite(result);
-    };
-
-    this.suiteResults = function(index, length) {
-      return suites.slice(index, index + length);
-    };
-
-    function storeSuite(result) {
-      suites.push(result);
-      suites_hash[result.id] = result;
-    }
-
-    this.suites = function() {
-      return suites_hash;
-    };
-
-    var specs = [];
-
-    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().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, delayedFunctionSchedulerFactory, mockDate) {
-    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,
-      delayedFunctionScheduler,
-      timer;
-
-
-    self.install = function() {
-      if(!originalTimingFunctionsIntact()) {
-        throw new Error('Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?');
-      }
-      replace(global, fakeTimingFunctions);
-      timer = fakeTimingFunctions;
-      delayedFunctionScheduler = delayedFunctionSchedulerFactory();
-      installed = true;
-
-      return self;
-    };
-
-    self.uninstall = function() {
-      delayedFunctionScheduler = null;
-      mockDate.uninstall();
-      replace(global, realTimingFunctions);
-
-      timer = realTimingFunctions;
-      installed = false;
-    };
-
-    self.withMock = function(closure) {
-      this.install();
-      try {
-        closure();
-      } finally {
-        this.uninstall();
-      }
-    };
-
-    self.mockDate = function(initialDate) {
-      mockDate.install(initialDate);
-    };
-
-    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) {
-        mockDate.tick(millis);
-        delayedFunctionScheduler.tick(millis);
-      } else {
-        throw new Error('Mock clock is not installed, use jasmine.clock().install()');
-      }
-    };
-
-    return self;
-
-    function originalTimingFunctionsIntact() {
-      return global.setTimeout === realTimingFunctions.setTimeout &&
-        global.clearTimeout === realTimingFunctions.clearTimeout &&
-        global.setInterval === realTimingFunctions.setInterval &&
-        global.clearInterval === realTimingFunctions.clearInterval;
-    }
-
-    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, n);
-    }
-  }
-
-  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;
-        }
-      }
-    };
-
-    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 forEachFunction(funcsToRun, callback) {
-      for (var i = 0; i < funcsToRun.length; ++i) {
-        callback(funcsToRun[i]);
-      }
-    }
-
-    function runScheduledFunctions(endTime) {
-      if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
-        return;
-      }
-
-      do {
-        currentTime = scheduledLookup.shift();
-
-        var funcsToRun = scheduledFunctions[currentTime];
-        delete scheduledFunctions[currentTime];
-
-        forEachFunction(funcsToRun, function(funcToRun) {
-          if (funcToRun.recurring) {
-            reschedule(funcToRun);
-          }
-        });
-
-        forEachFunction(funcsToRun, function(funcToRun) {
-          funcToRun.funcToCall.apply(null, funcToRun.params || []);
-        });
-      } 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 = '';
-
-      if (error.name && error.message) {
-        message += error.name + ': ' + error.message;
-      } else {
-        message += error.toString() + ' thrown';
-      }
-
-      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() {
-
-  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;
-
-    var customMatchers = options.customMatchers || {};
-    for (var matcherName in customMatchers) {
-      this[matcherName] = Expectation.prototype.wrapCompare(matcherName, customMatchers[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 {
-          if (Object.prototype.toString.apply(result.message) === '[object Function]') {
-            message = result.message();
-          } 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.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() {};
-
-    var result = {
-      matcherName: options.matcherName,
-      message: message(),
-      stack: stack(),
-      passed: options.passed
-    };
-
-    if(!result.passed) {
-      result.expected = options.expected;
-      result.actual = options.actual;
-    }
-
-    return result;
-
-    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().MockDate = function() {
-  function MockDate(global) {
-    var self = this;
-    var currentTime = 0;
-
-    if (!global || !global.Date) {
-      self.install = function() {};
-      self.tick = function() {};
-      self.uninstall = function() {};
-      return self;
-    }
-
-    var GlobalDate = global.Date;
-
-    self.install = function(mockDate) {
-      if (mockDate instanceof GlobalDate) {
-        currentTime = mockDate.getTime();
-      } else {
-        currentTime = new GlobalDate().getTime();
-      }
-
-      global.Date = FakeDate;
-    };
-
-    self.tick = function(millis) {
-      millis = millis || 0;
-      currentTime = currentTime + millis;
-    };
-
-    self.uninstall = function() {
-      currentTime = 0;
-      global.Date = GlobalDate;
-    };
-
-    createDateProperties();
-
-    return self;
-
-    function FakeDate() {
-      switch(arguments.length) {
-        case 0:
-          return new GlobalDate(currentTime);
-        case 1:
-          return new GlobalDate(arguments[0]);
-        case 2:
-          return new GlobalDate(arguments[0], arguments[1]);
-        case 3:
-          return new GlobalDate(arguments[0], arguments[1], arguments[2]);
-        case 4:
-          return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3]);
-        case 5:
-          return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
-                                arguments[4]);
-        case 6:
-          return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
-                                arguments[4], arguments[5]);
-        default:
-          return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
-                                arguments[4], arguments[5], arguments[6]);
-      }
-    }
-
-    function createDateProperties() {
-      FakeDate.prototype = GlobalDate.prototype;
-
-      FakeDate.now = function() {
-        if (GlobalDate.now) {
-          return currentTime;
-        } else {
-          throw new Error('Browser does not support Date.now()');
-        }
-      };
-
-      FakeDate.toSource = GlobalDate.toSource;
-      FakeDate.toString = GlobalDate.toString;
-      FakeDate.parse = GlobalDate.parse;
-      FakeDate.UTC = GlobalDate.UTC;
-    }
-	}
-
-  return MockDate;
-};
-
-getJasmineRequireObj().pp = function(j$) {
-
-  function PrettyPrinter() {
-    this.ppNestLevel_ = 0;
-    this.seen = [];
-  }
-
-  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 === 0 && 1/value === -Infinity) {
-        this.emitScalar('-0');
-      } 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.toString && typeof value === 'object' && !(value instanceof Array) && value.toString !== Object.prototype.toString) {
-        this.emitScalar(value.toString());
-      } else if (j$.util.arrayContains(this.seen, value)) {
-        this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
-      } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
-        this.seen.push(value);
-        if (j$.isArray_(value)) {
-          this.emitArray(value);
-        } else {
-          this.emitObject(value);
-        }
-        this.seen.pop();
-      } else {
-        this.emitScalar(value.toString());
-      }
-    } finally {
-      this.ppNestLevel_--;
-    }
-  };
-
-  PrettyPrinter.prototype.iterateObject = function(obj, fn) {
-    for (var property in obj) {
-      if (!Object.prototype.hasOwnProperty.call(obj, property)) { 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;
-    }
-    var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
-    this.append('[ ');
-    for (var i = 0; i < length; i++) {
-      if (i > 0) {
-        this.append(', ');
-      }
-      this.format(array[i]);
-    }
-    if(array.length > length){
-      this.append(', ...');
-    }
-
-    var self = this;
-    var first = array.length === 0;
-    this.iterateObject(array, function(property, isGetter) {
-      if (property.match(/^\d+$/)) {
-        return;
-      }
-
-      if (first) {
-        first = false;
-      } else {
-        self.append(', ');
-      }
-
-      self.formatProperty(array, property, isGetter);
-    });
-
-    this.append(' ]');
-  };
-
-  StringPrettyPrinter.prototype.emitObject = function(obj) {
-    var constructorName = obj.constructor ? j$.fnNameFor(obj.constructor) : 'null';
-    this.append(constructorName);
-
-    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
-      return;
-    }
-
-    var self = this;
-    this.append('({ ');
-    var first = true;
-
-    this.iterateObject(obj, function(property, isGetter) {
-      if (first) {
-        first = false;
-      } else {
-        self.append(', ');
-      }
-
-      self.formatProperty(obj, property, isGetter);
-    });
-
-    this.append(' })');
-  };
-
-  StringPrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
-      this.append(property);
-      this.append(': ');
-      if (isGetter) {
-        this.append('<getter>');
-      } else {
-        this.format(obj[property]);
-      }
-  };
-
-  StringPrettyPrinter.prototype.append = function(value) {
-    this.string += value;
-  };
-
-  return function(value) {
-    var stringPrettyPrinter = new StringPrettyPrinter();
-    stringPrettyPrinter.format(value);
-    return stringPrettyPrinter.string;
-  };
-};
-
-getJasmineRequireObj().QueueRunner = function(j$) {
-
-  function once(fn) {
-    var called = false;
-    return function() {
-      if (!called) {
-        called = true;
-        fn();
-      }
-    };
-  }
-
-  function QueueRunner(attrs) {
-    this.queueableFns = attrs.queueableFns || [];
-    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 = attrs.userContext || {};
-    this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
-    this.fail = attrs.fail || function() {};
-  }
-
-  QueueRunner.prototype.execute = function() {
-    this.run(this.queueableFns, 0);
-  };
-
-  QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
-    var length = queueableFns.length,
-      self = this,
-      iterativeIndex;
-
-
-    for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
-      var queueableFn = queueableFns[iterativeIndex];
-      if (queueableFn.fn.length > 0) {
-        attemptAsync(queueableFn);
-        return;
-      } else {
-        attemptSync(queueableFn);
-      }
-    }
-
-    var runnerDone = iterativeIndex >= length;
-
-    if (runnerDone) {
-      this.clearStack(this.onComplete);
-    }
-
-    function attemptSync(queueableFn) {
-      try {
-        queueableFn.fn.call(self.userContext);
-      } catch (e) {
-        handleException(e, queueableFn);
-      }
-    }
-
-    function attemptAsync(queueableFn) {
-      var clearTimeout = function () {
-          Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
-        },
-        next = once(function () {
-          clearTimeout(timeoutId);
-          self.run(queueableFns, iterativeIndex + 1);
-        }),
-        timeoutId;
-
-      next.fail = function() {
-        self.fail.apply(null, arguments);
-        next();
-      };
-
-      if (queueableFn.timeout) {
-        timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [function() {
-          var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
-          onException(error);
-          next();
-        }, queueableFn.timeout()]]);
-      }
-
-      try {
-        queueableFn.fn.call(self.userContext, next);
-      } catch (e) {
-        handleException(e, queueableFn);
-        next();
-      }
-    }
-
-    function onException(e) {
-      self.onException(e);
-    }
-
-    function handleException(e, queueableFn) {
-      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().SpyRegistry = function(j$) {
-
-  function SpyRegistry(options) {
-    options = options || {};
-    var currentSpies = options.currentSpies || function() { return []; };
-
-    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(methodName)) {
-        throw new Error('No method name supplied');
-      }
-
-      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 descriptor;
-      try {
-        descriptor = Object.getOwnPropertyDescriptor(obj, methodName);
-      } catch(e) {
-        // IE 8 doesn't support `definePropery` on non-DOM nodes
-      }
-
-      if (descriptor && !(descriptor.writable || descriptor.set)) {
-        throw new Error(methodName + ' is not declared writable or has no setter');
-      }
-
-      var spy = j$.createSpy(methodName, obj[methodName]);
-
-      currentSpies().push({
-        spy: spy,
-        baseObj: obj,
-        methodName: methodName,
-        originalValue: obj[methodName]
-      });
-
-      obj[methodName] = spy;
-
-      return spy;
-    };
-
-    this.clearSpies = function() {
-      var spies = currentSpies();
-      for (var i = 0; i < spies.length; i++) {
-        var spyEntry = spies[i];
-        spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
-      }
-    };
-  }
-
-  return SpyRegistry;
-};
-
-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.returnValues = function() {
-      var values = Array.prototype.slice.call(arguments);
-      plan = function () {
-        return values.shift();
-      };
-      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(j$) {
-  function Suite(attrs) {
-    this.env = attrs.env;
-    this.id = attrs.id;
-    this.parentSuite = attrs.parentSuite;
-    this.description = attrs.description;
-    this.expectationFactory = attrs.expectationFactory;
-    this.expectationResultFactory = attrs.expectationResultFactory;
-    this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
-
-    this.beforeFns = [];
-    this.afterFns = [];
-    this.beforeAllFns = [];
-    this.afterAllFns = [];
-    this.disabled = false;
-
-    this.children = [];
-
-    this.result = {
-      id: this.id,
-      description: this.description,
-      fullName: this.getFullName(),
-      failedExpectations: []
-    };
-  }
-
-  Suite.prototype.expect = function(actual) {
-    return this.expectationFactory(actual, this);
-  };
-
-  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.pend = function(message) {
-    this.markedPending = true;
-  };
-
-  Suite.prototype.beforeEach = function(fn) {
-    this.beforeFns.unshift(fn);
-  };
-
-  Suite.prototype.beforeAll = function(fn) {
-    this.beforeAllFns.push(fn);
-  };
-
-  Suite.prototype.afterEach = function(fn) {
-    this.afterFns.unshift(fn);
-  };
-
-  Suite.prototype.afterAll = function(fn) {
-    this.afterAllFns.push(fn);
-  };
-
-  Suite.prototype.addChild = function(child) {
-    this.children.push(child);
-  };
-
-  Suite.prototype.status = function() {
-    if (this.disabled) {
-      return 'disabled';
-    }
-
-    if (this.markedPending) {
-      return 'pending';
-    }
-
-    if (this.result.failedExpectations.length > 0) {
-      return 'failed';
-    } else {
-      return 'finished';
-    }
-  };
-
-  Suite.prototype.isExecutable = function() {
-    return !this.disabled;
-  };
-
-  Suite.prototype.canBeReentered = function() {
-    return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0;
-  };
-
-  Suite.prototype.getResult = function() {
-    this.result.status = this.status();
-    return this.result;
-  };
-
-  Suite.prototype.sharedUserContext = function() {
-    if (!this.sharedContext) {
-      this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {};
-    }
-
-    return this.sharedContext;
-  };
-
-  Suite.prototype.clonedSharedUserContext = function() {
-    return clone(this.sharedUserContext());
-  };
-
-  Suite.prototype.onException = function() {
-    if (arguments[0] instanceof j$.errors.ExpectationFailed) {
-      return;
-    }
-
-    if(isAfterAll(this.children)) {
-      var data = {
-        matcherName: '',
-        passed: false,
-        expected: '',
-        actual: '',
-        error: arguments[0]
-      };
-      this.result.failedExpectations.push(this.expectationResultFactory(data));
-    } else {
-      for (var i = 0; i < this.children.length; i++) {
-        var child = this.children[i];
-        child.onException.apply(child, arguments);
-      }
-    }
-  };
-
-  Suite.prototype.addExpectationResult = function () {
-    if(isAfterAll(this.children) && isFailure(arguments)){
-      var data = arguments[1];
-      this.result.failedExpectations.push(this.expectationResultFactory(data));
-      if(this.throwOnExpectationFailure) {
-        throw new j$.errors.ExpectationFailed();
-      }
-    } else {
-      for (var i = 0; i < this.children.length; i++) {
-        var child = this.children[i];
-        try {
-          child.addExpectationResult.apply(child, arguments);
-        } catch(e) {
-          // keep going
-        }
-      }
-    }
-  };
-
-  function isAfterAll(children) {
-    return children && children[0].result.status;
-  }
-
-  function isFailure(args) {
-    return !args[0];
-  }
-
-  function clone(obj) {
-    var clonedObj = {};
-    for (var prop in obj) {
-      if (obj.hasOwnProperty(prop)) {
-        clonedObj[prop] = obj[prop];
-      }
-    }
-
-    return clonedObj;
-  }
-
-  return Suite;
-};
-
-if (typeof window == void 0 && typeof exports == 'object') {
-  exports.Suite = jasmineRequire.Suite;
-}
-
-getJasmineRequireObj().Timer = function() {
-  var defaultNow = (function(Date) {
-    return function() { return new Date().getTime(); };
-  })(Date);
-
-  function Timer(options) {
-    options = options || {};
-
-    var now = options.now || defaultNow,
-      startTime;
-
-    this.start = function() {
-      startTime = now();
-    };
-
-    this.elapsed = function() {
-      return now() - startTime;
-    };
-  }
-
-  return Timer;
-};
-
-getJasmineRequireObj().TreeProcessor = function() {
-  function TreeProcessor(attrs) {
-    var tree = attrs.tree,
-        runnableIds = attrs.runnableIds,
-        queueRunnerFactory = attrs.queueRunnerFactory,
-        nodeStart = attrs.nodeStart || function() {},
-        nodeComplete = attrs.nodeComplete || function() {},
-        orderChildren = attrs.orderChildren || function(node) { return node.children; },
-        stats = { valid: true },
-        processed = false,
-        defaultMin = Infinity,
-        defaultMax = 1 - Infinity;
-
-    this.processTree = function() {
-      processNode(tree, false);
-      processed = true;
-      return stats;
-    };
-
-    this.execute = function(done) {
-      if (!processed) {
-        this.processTree();
-      }
-
-      if (!stats.valid) {
-        throw 'invalid order';
-      }
-
-      var childFns = wrapChildren(tree, 0);
-
-      queueRunnerFactory({
-        queueableFns: childFns,
-        userContext: tree.sharedUserContext(),
-        onException: function() {
-          tree.onException.apply(tree, arguments);
-        },
-        onComplete: done
-      });
-    };
-
-    function runnableIndex(id) {
-      for (var i = 0; i < runnableIds.length; i++) {
-        if (runnableIds[i] === id) {
-          return i;
-        }
-      }
-    }
-
-    function processNode(node, parentEnabled) {
-      var executableIndex = runnableIndex(node.id);
-
-      if (executableIndex !== undefined) {
-        parentEnabled = true;
-      }
-
-      parentEnabled = parentEnabled && node.isExecutable();
-
-      if (!node.children) {
-        stats[node.id] = {
-          executable: parentEnabled && node.isExecutable(),
-          segments: [{
-            index: 0,
-            owner: node,
-            nodes: [node],
-            min: startingMin(executableIndex),
-            max: startingMax(executableIndex)
-          }]
-        };
-      } else {
-        var hasExecutableChild = false;
-
-        var orderedChildren = orderChildren(node);
-
-        for (var i = 0; i < orderedChildren.length; i++) {
-          var child = orderedChildren[i];
-
-          processNode(child, parentEnabled);
-
-          if (!stats.valid) {
-            return;
-          }
-
-          var childStats = stats[child.id];
-
-          hasExecutableChild = hasExecutableChild || childStats.executable;
-        }
-
-        stats[node.id] = {
-          executable: hasExecutableChild
-        };
-
-        segmentChildren(node, orderedChildren, stats[node.id], executableIndex);
-
-        if (!node.canBeReentered() && stats[node.id].segments.length > 1) {
-          stats = { valid: false };
-        }
-      }
-    }
-
-    function startingMin(executableIndex) {
-      return executableIndex === undefined ? defaultMin : executableIndex;
-    }
-
-    function startingMax(executableIndex) {
-      return executableIndex === undefined ? defaultMax : executableIndex;
-    }
-
-    function segmentChildren(node, orderedChildren, nodeStats, executableIndex) {
-      var currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) },
-          result = [currentSegment],
-          lastMax = defaultMax,
-          orderedChildSegments = orderChildSegments(orderedChildren);
-
-      function isSegmentBoundary(minIndex) {
-        return lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1;
-      }
-
-      for (var i = 0; i < orderedChildSegments.length; i++) {
-        var childSegment = orderedChildSegments[i],
-          maxIndex = childSegment.max,
-          minIndex = childSegment.min;
-
-        if (isSegmentBoundary(minIndex)) {
-          currentSegment = {index: result.length, owner: node, nodes: [], min: defaultMin, max: defaultMax};
-          result.push(currentSegment);
-        }
-
-        currentSegment.nodes.push(childSegment);
-        currentSegment.min = Math.min(currentSegment.min, minIndex);
-        currentSegment.max = Math.max(currentSegment.max, maxIndex);
-        lastMax = maxIndex;
-      }
-
-      nodeStats.segments = result;
-    }
-
-    function orderChildSegments(children) {
-      var specifiedOrder = [],
-          unspecifiedOrder = [];
-
-      for (var i = 0; i < children.length; i++) {
-        var child = children[i],
-            segments = stats[child.id].segments;
-
-        for (var j = 0; j < segments.length; j++) {
-          var seg = segments[j];
-
-          if (seg.min === defaultMin) {
-            unspecifiedOrder.push(seg);
-          } else {
-            specifiedOrder.push(seg);
-          }
-        }
-      }
-
-      specifiedOrder.sort(function(a, b) {
-        return a.min - b.min;
-      });
-
-      return specifiedOrder.concat(unspecifiedOrder);
-    }
-
-    function executeNode(node, segmentNumber) {
-      if (node.children) {
-        return {
-          fn: function(done) {
-            nodeStart(node);
-
-            queueRunnerFactory({
-              onComplete: function() {
-                nodeComplete(node, node.getResult());
-                done();
-              },
-              queueableFns: wrapChildren(node, segmentNumber),
-              userContext: node.sharedUserContext(),
-              onException: function() {
-                node.onException.apply(node, arguments);
-              }
-            });
-          }
-        };
-      } else {
-        return {
-          fn: function(done) { node.execute(done, stats[node.id].executable); }
-        };
-      }
-    }
-
-    function wrapChildren(node, segmentNumber) {
-      var result = [],
-          segmentChildren = stats[node.id].segments[segmentNumber].nodes;
-
-      for (var i = 0; i < segmentChildren.length; i++) {
-        result.push(executeNode(segmentChildren[i].owner, segmentChildren[i].index));
-      }
-
-      if (!stats[node.id].executable) {
-        return result;
-      }
-
-      return node.beforeAllFns.concat(result).concat(node.afterAllFns);
-    }
-  }
-
-  return TreeProcessor;
-};
-
-getJasmineRequireObj().Any = function(j$) {
-
-  function Any(expectedObject) {
-    if (typeof expectedObject === 'undefined') {
-      throw new TypeError(
-        'jasmine.any() expects to be passed a constructor function. ' +
-        'Please pass one or use jasmine.anything() to match any object.'
-      );
-    }
-    this.expectedObject = expectedObject;
-  }
-
-  Any.prototype.asymmetricMatch = 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(' + j$.fnNameFor(this.expectedObject) + ')>';
-  };
-
-  return Any;
-};
-
-getJasmineRequireObj().Anything = function(j$) {
-
-  function Anything() {}
-
-  Anything.prototype.asymmetricMatch = function(other) {
-    return !j$.util.isUndefined(other) && other !== null;
-  };
-
-  Anything.prototype.jasmineToString = function() {
-    return '<jasmine.anything>';
-  };
-
-  return Anything;
-};
-
-getJasmineRequireObj().ArrayContaining = function(j$) {
-  function ArrayContaining(sample) {
-    this.sample = sample;
-  }
-
-  ArrayContaining.prototype.asymmetricMatch = function(other) {
-    var className = Object.prototype.toString.call(this.sample);
-    if (className !== '[object Array]') { throw new Error('You must provide an array to arrayContaining, not \'' + this.sample + '\'.'); }
-
-    for (var i = 0; i < this.sample.length; i++) {
-      var item = this.sample[i];
-      if (!j$.matchersUtil.contains(other, item)) {
-        return false;
-      }
-    }
-
-    return true;
-  };
-
-  ArrayContaining.prototype.jasmineToString = function () {
-    return '<jasmine.arrayContaining(' + jasmine.pp(this.sample) +')>';
-  };
-
-  return ArrayContaining;
-};
-
-getJasmineRequireObj().ObjectContaining = function(j$) {
-
-  function ObjectContaining(sample) {
-    this.sample = sample;
-  }
-
-  function getPrototype(obj) {
-    if (Object.getPrototypeOf) {
-      return Object.getPrototypeOf(obj);
-    }
-
-    if (obj.constructor.prototype == obj) {
-      return null;
-    }
-
-    return obj.constructor.prototype;
-  }
-
-  function hasProperty(obj, property) {
-    if (!obj) {
-      return false;
-    }
-
-    if (Object.prototype.hasOwnProperty.call(obj, property)) {
-      return true;
-    }
-
-    return hasProperty(getPrototype(obj), property);
-  }
-
-  ObjectContaining.prototype.asymmetricMatch = function(other) {
-    if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
-
-    for (var property in this.sample) {
-      if (!hasProperty(other, property) ||
-          !j$.matchersUtil.equals(this.sample[property], other[property])) {
-        return false;
-      }
-    }
-
-    return true;
-  };
-
-  ObjectContaining.prototype.jasmineToString = function() {
-    return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
-  };
-
-  return ObjectContaining;
-};
-
-getJasmineRequireObj().StringMatching = function(j$) {
-
-  function StringMatching(expected) {
-    if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
-      throw new Error('Expected is not a String or a RegExp');
-    }
-
-    this.regexp = new RegExp(expected);
-  }
-
-  StringMatching.prototype.asymmetricMatch = function(other) {
-    return this.regexp.test(other);
-  };
-
-  StringMatching.prototype.jasmineToString = function() {
-    return '<jasmine.stringMatching(' + this.regexp + ')>';
-  };
-
-  return StringMatching;
-};
-
-getJasmineRequireObj().errors = function() {
-  function ExpectationFailed() {}
-
-  ExpectationFailed.prototype = new Error();
-  ExpectationFailed.prototype.constructor = ExpectationFailed;
-
-  return {
-    ExpectationFailed: ExpectationFailed
-  };
-};
-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]') ||
-        (!!haystack && !haystack.indexOf))
-      {
-        for (var i = 0; i < haystack.length; i++) {
-          if (eq(haystack[i], needle, [], [], customTesters)) {
-            return true;
-          }
-        }
-        return false;
-      }
-
-      return !!haystack && 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 + '.';
-    }
-  };
-
-  function isAsymmetric(obj) {
-    return obj && j$.isA_('Function', obj.asymmetricMatch);
-  }
-
-  function asymmetricMatch(a, b) {
-    var asymmetricA = isAsymmetric(a),
-        asymmetricB = isAsymmetric(b);
-
-    if (asymmetricA && asymmetricB) {
-      return undefined;
-    }
-
-    if (asymmetricA) {
-      return a.asymmetricMatch(b);
-    }
-
-    if (asymmetricB) {
-      return b.asymmetricMatch(a);
-    }
-  }
-
-  // Equality function lovingly adapted from isEqual in
-  //   [Underscore](http://underscorejs.org)
-  function eq(a, b, aStack, bStack, customTesters) {
-    var result = true;
-
-    var asymmetricResult = asymmetricMatch(a, b);
-    if (!j$.util.isUndefined(asymmetricResult)) {
-      return asymmetricResult;
-    }
-
-    for (var i = 0; i < customTesters.length; i++) {
-      var customTesterResult = customTesters[i](a, b);
-      if (!j$.util.isUndefined(customTesterResult)) {
-        return customTesterResult;
-      }
-    }
-
-    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; }
-
-    var aIsDomNode = j$.isDomNode(a);
-    var bIsDomNode = j$.isDomNode(b);
-    if (aIsDomNode && bIsDomNode) {
-      // At first try to use DOM3 method isEqualNode
-      if (a.isEqualNode) {
-        return a.isEqualNode(b);
-      }
-      // IE8 doesn't support isEqualNode, try to use outerHTML && innerText
-      var aIsElement = a instanceof Element;
-      var bIsElement = b instanceof Element;
-      if (aIsElement && bIsElement) {
-        return a.outerHTML == b.outerHTML;
-      }
-      if (aIsElement || bIsElement) {
-        return false;
-      }
-      return a.innerText == b.innerText && a.textContent == b.textContent;
-    }
-    if (aIsDomNode || bIsDomNode) {
-      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.
-    // Compare array lengths to determine if a deep comparison is necessary.
-    if (className == '[object Array]' && a.length !== b.length) {
-      result = false;
-    }
-
-    if (result) {
-      // Objects with different constructors are not equivalent, but `Object`s
-      // or `Array`s from different frames are.
-      if (className !== '[object Array]') {
-        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 Object.prototype.hasOwnProperty.call(obj, 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 = function() { return '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().toHaveBeenCalledTimes = function(j$) {
-
-  function toHaveBeenCalledTimes() {
-    return {
-      compare: function(actual, expected) {
-        if (!j$.isSpy(actual)) {
-          throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
-        }
-
-        var args = Array.prototype.slice.call(arguments, 0),
-          result = { pass: false };
-
-        if(!expected){
-          throw new Error('Expected times failed is required as an argument.');
-        }
-
-        actual = args[0];
-        var calls = actual.calls.count();
-        var timesMessage = expected === 1 ? 'once' : expected + ' times';
-        result.pass = calls === expected;
-        result.message = result.pass ?
-          'Expected spy ' + actual.and.identity() + ' not to have been called ' + timesMessage + '. It was called ' +  calls + ' times.' :
-          'Expected spy ' + actual.and.identity() + ' to have been called ' + timesMessage + '. It was called ' +  calls + ' times.';
-        return result;
-      }
-    };
-  }
-
-  return toHaveBeenCalledTimes;
-};
-
-getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
-
-  function toHaveBeenCalledWith(util, customEqualityTesters) {
-    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 = function() { return '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, customEqualityTesters)) {
-          result.pass = true;
-          result.message = function() { return 'Expected spy ' + actual.and.identity() + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
-        } else {
-          result.message = function() { return '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(j$) {
-
-  function toMatch() {
-    return {
-      compare: function(actual, expected) {
-        if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
-          throw new Error('Expected is not a String or a RegExp');
-        }
-
-        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 = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
-
-          return result;
-        }
-
-        if (util.equals(thrown, expected)) {
-          result.pass = true;
-          result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
-        } else {
-          result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' +  j$.pp(thrown) + '.'; };
-        }
-
-        return result;
-      }
-    };
-  }
-
-  return toThrow;
-};
-
-getJasmineRequireObj().toThrowError = function(j$) {
-  function toThrowError () {
-    return {
-      compare: function(actual) {
-        var threw = false,
-          pass = {pass: true},
-          fail = {pass: false},
-          thrown;
-
-        if (typeof actual != 'function') {
-          throw new Error('Actual is not a Function');
-        }
-
-        var errorMatcher = getMatcher.apply(null, arguments);
-
-        try {
-          actual();
-        } catch (e) {
-          threw = true;
-          thrown = e;
-        }
-
-        if (!threw) {
-          fail.message = 'Expected function to throw an Error.';
-          return fail;
-        }
-
-        if (!(thrown instanceof Error)) {
-          fail.message = function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; };
-          return fail;
-        }
-
-        if (errorMatcher.hasNoSpecifics()) {
-          pass.message = 'Expected function not to throw an Error, but it threw ' + j$.fnNameFor(thrown) + '.';
-          return pass;
-        }
-
-        if (errorMatcher.matches(thrown)) {
-          pass.message = function() {
-            return 'Expected function not to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + '.';
-          };
-          return pass;
-        } else {
-          fail.message = function() {
-            return 'Expected function to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() +
-              ', but it threw ' + errorMatcher.thrownDescription(thrown) + '.';
-          };
-          return fail;
-        }
-      }
-    };
-
-    function getMatcher() {
-      var expected = null,
-          errorType = null;
-
-      if (arguments.length == 2) {
-        expected = arguments[1];
-        if (isAnErrorType(expected)) {
-          errorType = expected;
-          expected = null;
-        }
-      } else if (arguments.length > 2) {
-        errorType = arguments[1];
-        expected = arguments[2];
-        if (!isAnErrorType(errorType)) {
-          throw new Error('Expected error type is not an Error.');
-        }
-      }
-
-      if (expected && !isStringOrRegExp(expected)) {
-        if (errorType) {
-          throw new Error('Expected error message is not a string or RegExp.');
-        } else {
-          throw new Error('Expected is not an Error, string, or RegExp.');
-        }
-      }
-
-      function messageMatch(message) {
-        if (typeof expected == 'string') {
-          return expected == message;
-        } else {
-          return expected.test(message);
-        }
-      }
-
-      return {
-        errorTypeDescription: errorType ? j$.fnNameFor(errorType) : 'an exception',
-        thrownDescription: function(thrown) {
-          var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception',
-              thrownMessage = '';
-
-          if (expected) {
-            thrownMessage = ' with message ' + j$.pp(thrown.message);
-          }
-
-          return thrownName + thrownMessage;
-        },
-        messageDescription: function() {
-          if (expected === null) {
-            return '';
-          } else if (expected instanceof RegExp) {
-            return ' with a message matching ' + j$.pp(expected);
-          } else {
-            return ' with message ' + j$.pp(expected);
-          }
-        },
-        hasNoSpecifics: function() {
-          return expected === null && errorType === null;
-        },
-        matches: function(error) {
-          return (errorType === null || error instanceof errorType) &&
-            (expected === null || messageMatch(error.message));
-        }
-      };
-    }
-
-    function isStringOrRegExp(potential) {
-      return potential instanceof RegExp || (typeof potential == 'string');
-    }
-
-    function isAnErrorType(type) {
-      if (typeof type !== 'function') {
-        return false;
-      }
-
-      var Surrogate = function() {};
-      Surrogate.prototype = type.prototype;
-      return (new Surrogate()) instanceof Error;
-    }
-  }
-
-  return toThrowError;
-};
-
-getJasmineRequireObj().interface = function(jasmine, env) {
-  var jasmineInterface = {
-    describe: function(description, specDefinitions) {
-      return env.describe(description, specDefinitions);
-    },
-
-    xdescribe: function(description, specDefinitions) {
-      return env.xdescribe(description, specDefinitions);
-    },
-
-    fdescribe: function(description, specDefinitions) {
-      return env.fdescribe(description, specDefinitions);
-    },
-
-    it: function() {
-      return env.it.apply(env, arguments);
-    },
-
-    xit: function() {
-      return env.xit.apply(env, arguments);
-    },
-
-    fit: function() {
-      return env.fit.apply(env, arguments);
-    },
-
-    beforeEach: function() {
-      return env.beforeEach.apply(env, arguments);
-    },
-
-    afterEach: function() {
-      return env.afterEach.apply(env, arguments);
-    },
-
-    beforeAll: function() {
-      return env.beforeAll.apply(env, arguments);
-    },
-
-    afterAll: function() {
-      return env.afterAll.apply(env, arguments);
-    },
-
-    expect: function(actual) {
-      return env.expect(actual);
-    },
-
-    pending: function() {
-      return env.pending.apply(env, arguments);
-    },
-
-    fail: function() {
-      return env.fail.apply(env, arguments);
-    },
-
-    spyOn: function(obj, methodName) {
-      return env.spyOn(obj, methodName);
-    },
-
-    jsApiReporter: new jasmine.JsApiReporter({
-      timer: new jasmine.Timer()
-    }),
-
-    jasmine: jasmine
-  };
-
-  jasmine.addCustomEqualityTester = function(tester) {
-    env.addCustomEqualityTester(tester);
-  };
-
-  jasmine.addMatchers = function(matchers) {
-    return env.addMatchers(matchers);
-  };
-
-  jasmine.clock = function() {
-    return env.clock;
-  };
-
-  return jasmineInterface;
-};
-
-getJasmineRequireObj().version = function() {
-  return '2.4.1';
-};
diff --git a/www/assets/jasmine-2.4.1/boot.js b/www/assets/jasmine-2.99.0/boot.js
old mode 100755
new mode 100644
similarity index 97%
rename from www/assets/jasmine-2.4.1/boot.js
rename to www/assets/jasmine-2.99.0/boot.js
index a99774d..d9b5a80
--- a/www/assets/jasmine-2.4.1/boot.js
+++ b/www/assets/jasmine-2.99.0/boot.js
@@ -49,6 +49,8 @@
     getWindowLocation: function() { return window.location; }
   });
 
+  var filterSpecs = !!queryString.getParam("spec");
+
   var catchingExceptions = queryString.getParam("catch");
   env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
 
@@ -76,7 +78,8 @@
     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()
+    timer: new jasmine.Timer(),
+    filterSpecs: filterSpecs
   });
 
   /**
diff --git a/www/assets/jasmine-2.4.1/console.js b/www/assets/jasmine-2.99.0/console.js
old mode 100755
new mode 100644
similarity index 99%
rename from www/assets/jasmine-2.4.1/console.js
rename to www/assets/jasmine-2.99.0/console.js
index e154806..43a82ac
--- a/www/assets/jasmine-2.4.1/console.js
+++ b/www/assets/jasmine-2.99.0/console.js
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2008-2015 Pivotal Labs
+Copyright (c) 2008-2018 Pivotal Labs
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/www/assets/jasmine-2.4.1/jasmine-html.js b/www/assets/jasmine-2.99.0/jasmine-html.js
old mode 100755
new mode 100644
similarity index 79%
rename from www/assets/jasmine-2.4.1/jasmine-html.js
rename to www/assets/jasmine-2.99.0/jasmine-html.js
index da23532..7dd2f5e
--- a/www/assets/jasmine-2.4.1/jasmine-html.js
+++ b/www/assets/jasmine-2.99.0/jasmine-html.js
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2008-2015 Pivotal Labs
+Copyright (c) 2008-2018 Pivotal Labs
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
@@ -34,6 +34,46 @@ jasmineRequire.HtmlReporter = function(j$) {
     elapsed: function() { return 0; }
   };
 
+  function ResultsStateBuilder() {
+    this.topResults = new j$.ResultsNode({}, '', null);
+    this.currentParent = this.topResults;
+    this.specsExecuted = 0;
+    this.failureCount = 0;
+    this.pendingSpecCount = 0;
+  }
+
+  ResultsStateBuilder.prototype.suiteStarted = function(result) {
+    this.currentParent.addChild(result, 'suite');
+    this.currentParent = this.currentParent.last();
+  };
+
+  ResultsStateBuilder.prototype.suiteDone = function(result) {
+    if (this.currentParent !== this.topResults) {
+      this.currentParent = this.currentParent.parent;
+    }
+  };
+
+  ResultsStateBuilder.prototype.specStarted = function(result) {
+  };
+
+  ResultsStateBuilder.prototype.specDone = function(result) {
+    this.currentParent.addChild(result, 'spec');
+
+    if (result.status !== 'disabled') {
+      this.specsExecuted++;
+    }
+
+    if (result.status === 'failed') {
+      this.failureCount++;
+    }
+
+    if (result.status == 'pending') {
+      this.pendingSpecCount++;
+    }
+  };
+
+
+
   function HtmlReporter(options) {
     var env = options.env || {},
       getContainer = options.getContainer,
@@ -43,14 +83,13 @@ jasmineRequire.HtmlReporter = function(j$) {
       onThrowExpectationsClick = options.onThrowExpectationsClick || function() {},
       onRandomClick = options.onRandomClick || function() {},
       addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
+      filterSpecs = options.filterSpecs,
       timer = options.timer || noopTimer,
       results = [],
-      specsExecuted = 0,
-      failureCount = 0,
-      pendingSpecCount = 0,
       htmlReporterMain,
       symbols,
-      failedSuites = [];
+      failedSuites = [],
+      deprecationWarnings = [];
 
     this.initialize = function() {
       clearPrior();
@@ -76,12 +115,10 @@ jasmineRequire.HtmlReporter = function(j$) {
 
     var summary = createDom('div', {className: 'jasmine-summary'});
 
-    var topResults = new j$.ResultsNode({}, '', null),
-      currentParent = topResults;
+    var stateBuilder = new ResultsStateBuilder();
 
     this.suiteStarted = function(result) {
-      currentParent.addChild(result, 'suite');
-      currentParent = currentParent.last();
+      stateBuilder.suiteStarted(result);
     };
 
     this.suiteDone = function(result) {
@@ -89,27 +126,22 @@ jasmineRequire.HtmlReporter = function(j$) {
         failedSuites.push(result);
       }
 
-      if (currentParent == topResults) {
-        return;
-      }
-
-      currentParent = currentParent.parent;
+      stateBuilder.suiteDone(result);
+      addDeprecationWarnings(result);
     };
 
     this.specStarted = function(result) {
-      currentParent.addChild(result, 'spec');
+      stateBuilder.specStarted(result);
     };
 
     var failures = [];
     this.specDone = function(result) {
+      stateBuilder.specDone(result);
+
       if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') {
         console.error('Spec \'' + result.fullName + '\' has no expectations.');
       }
 
-      if (result.status != 'disabled') {
-        specsExecuted++;
-      }
-
       if (!symbols){
         symbols = find('.jasmine-symbol-summary');
       }
@@ -122,8 +154,6 @@ jasmineRequire.HtmlReporter = function(j$) {
       ));
 
       if (result.status == 'failed') {
-        failureCount++;
-
         var failure =
           createDom('div', {className: 'jasmine-spec-detail jasmine-failed'},
             createDom('div', {className: 'jasmine-description'},
@@ -142,9 +172,7 @@ jasmineRequire.HtmlReporter = function(j$) {
         failures.push(failure);
       }
 
-      if (result.status == 'pending') {
-        pendingSpecCount++;
-      }
+      addDeprecationWarnings(result);
     };
 
     this.jasmineDone = function(doneResult) {
@@ -207,11 +235,12 @@ jasmineRequire.HtmlReporter = function(j$) {
         }
       };
 
-      if (specsExecuted < totalSpecsDefined) {
-        var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
+      if (stateBuilder.specsExecuted < totalSpecsDefined) {
+        var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
+        var skippedLink = addToExistingQueryString('spec', '');
         alert.appendChild(
           createDom('span', {className: 'jasmine-bar jasmine-skipped'},
-            createDom('a', {href: '?', title: 'Run all specs'}, skippedMessage)
+            createDom('a', {href: skippedLink, title: 'Run all specs'}, skippedMessage)
           )
         );
       }
@@ -219,9 +248,9 @@ jasmineRequire.HtmlReporter = function(j$) {
       var statusBarClassName = 'jasmine-bar ';
 
       if (totalSpecsDefined > 0) {
-        statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount);
-        if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); }
-        statusBarClassName += (failureCount > 0) ? 'jasmine-failed' : 'jasmine-passed';
+        statusBarMessage += pluralize('spec', stateBuilder.specsExecuted) + ', ' + pluralize('failure', stateBuilder.failureCount);
+        if (stateBuilder.pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount); }
+        statusBarClassName += (stateBuilder.failureCount > 0) ? 'jasmine-failed' : 'jasmine-passed';
       } else {
         statusBarClassName += 'jasmine-skipped';
         statusBarMessage += 'No specs found';
@@ -237,24 +266,42 @@ jasmineRequire.HtmlReporter = function(j$) {
 
       alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage, seedBar));
 
-      for(i = 0; i < failedSuites.length; i++) {
+      var errorBarClassName = 'jasmine-bar jasmine-errored';
+      var errorBarMessagePrefix = 'AfterAll ';
+
+      for(var i = 0; i < failedSuites.length; i++) {
         var failedSuite = failedSuites[i];
         for(var j = 0; j < failedSuite.failedExpectations.length; j++) {
-          var errorBarMessage = 'AfterAll ' + failedSuite.failedExpectations[j].message;
-          var errorBarClassName = 'jasmine-bar jasmine-errored';
-          alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessage));
+          alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failedSuite.failedExpectations[j].message));
         }
       }
 
+      var globalFailures = (doneResult && doneResult.failedExpectations) || [];
+      for(i = 0; i < globalFailures.length; i++) {
+        var failure = globalFailures[i];
+        alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failure.message));
+      }
+
+      addDeprecationWarnings(doneResult);
+
+      var warningBarClassName = 'jasmine-bar jasmine-warning';
+      for(i = 0; i < deprecationWarnings.length; i++) {
+        var warning = deprecationWarnings[i];
+        alert.appendChild(createDom('span', {className: warningBarClassName}, 'DEPRECATION: ' + warning));
+      }
+
       var results = find('.jasmine-results');
       results.appendChild(summary);
 
-      summaryList(topResults, summary);
+      summaryList(stateBuilder.topResults, summary);
 
       function summaryList(resultsTree, domParent) {
         var specListNode;
         for (var i = 0; i < resultsTree.children.length; i++) {
           var resultNode = resultsTree.children[i];
+          if (filterSpecs && !hasActiveSpec(resultNode)) {
+            continue;
+          }
           if (resultNode.type == 'suite') {
             var suiteListNode = createDom('ul', {className: 'jasmine-suite', id: 'suite-' + resultNode.result.id},
               createDom('li', {className: 'jasmine-suite-detail'},
@@ -309,7 +356,7 @@ jasmineRequire.HtmlReporter = function(j$) {
         setMenuModeTo('jasmine-failure-list');
 
         var failureNode = find('.jasmine-failures');
-        for (var i = 0; i < failures.length; i++) {
+        for (i = 0; i < failures.length; i++) {
           failureNode.appendChild(failures[i]);
         }
       }
@@ -317,6 +364,17 @@ jasmineRequire.HtmlReporter = function(j$) {
 
     return this;
 
+    function addDeprecationWarnings(result) {
+      if (result && result.deprecationWarnings) {
+        for(var i = 0; i < result.deprecationWarnings.length; i++) {
+          var warning = result.deprecationWarnings[i].message;
+          if (!j$.util.arrayContains(warning)) {
+            deprecationWarnings.push(warning);
+          }
+        }
+      }
+    }
+
     function find(selector) {
       return getContainer().querySelector('.jasmine_html-reporter ' + selector);
     }
@@ -382,6 +440,20 @@ jasmineRequire.HtmlReporter = function(j$) {
       return (result.failedExpectations.length + result.passedExpectations.length) === 0 &&
         result.status === 'passed';
     }
+
+    function hasActiveSpec(resultNode) {
+      if (resultNode.type == 'spec' && resultNode.result.status != 'disabled') {
+        return true;
+      }
+
+      if (resultNode.type == 'suite') {
+        for (var i = 0, j = resultNode.children.length; i < j; i++) {
+          if (hasActiveSpec(resultNode.children[i])) {
+            return true;
+          }
+        }
+      }
+    }
   }
 
   return HtmlReporter;
diff --git a/www/assets/jasmine-2.4.1/jasmine.css b/www/assets/jasmine-2.99.0/jasmine.css
old mode 100755
new mode 100644
similarity index 99%
rename from www/assets/jasmine-2.4.1/jasmine.css
rename to www/assets/jasmine-2.99.0/jasmine.css
index 6319982..5207c5b
--- a/www/assets/jasmine-2.4.1/jasmine.css
+++ b/www/assets/jasmine-2.99.0/jasmine.css
@@ -33,6 +33,7 @@ body { overflow-y: scroll; }
 .jasmine_html-reporter .jasmine-bar.jasmine-passed { background-color: #007069; }
 .jasmine_html-reporter .jasmine-bar.jasmine-skipped { background-color: #bababa; }
 .jasmine_html-reporter .jasmine-bar.jasmine-errored { background-color: #ca3a11; }
+.jasmine_html-reporter .jasmine-bar.jasmine-warning { background-color: #ba9d37; color: #333; }
 .jasmine_html-reporter .jasmine-bar.jasmine-menu { background-color: #fff; color: #aaa; }
 .jasmine_html-reporter .jasmine-bar.jasmine-menu a { color: #333; }
 .jasmine_html-reporter .jasmine-bar a { color: white; }
diff --git a/www/assets/jasmine-2.99.0/jasmine.js b/www/assets/jasmine-2.99.0/jasmine.js
new file mode 100644
index 0000000..9e6c424
--- /dev/null
+++ b/www/assets/jasmine-2.99.0/jasmine.js
@@ -0,0 +1,5584 @@
+/*
+Copyright (c) 2008-2018 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.
+*/
+var getJasmineRequireObj = (function (jasmineGlobal) {
+  var jasmineRequire;
+
+  if (typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined') {
+    if (typeof global !== 'undefined') {
+      jasmineGlobal = global;
+    } else {
+      jasmineGlobal = {};
+    }
+    jasmineRequire = exports;
+  } else {
+    if (typeof window !== 'undefined' && typeof window.toString === 'function' && window.toString() === '[object GjsGlobal]') {
+      jasmineGlobal = window;
+    }
+    jasmineRequire = jasmineGlobal.jasmineRequire = {};
+  }
+
+  function getJasmineRequire() {
+    return jasmineRequire;
+  }
+
+  getJasmineRequire().core = function(jRequire) {
+    var j$ = {};
+
+    jRequire.base(j$, jasmineGlobal);
+    j$.util = jRequire.util(j$);
+    j$.errors = jRequire.errors();
+    j$.formatErrorMsg = jRequire.formatErrorMsg();
+    j$.Any = jRequire.Any(j$);
+    j$.Anything = jRequire.Anything(j$);
+    j$.CallTracker = jRequire.CallTracker(j$);
+    j$.MockDate = jRequire.MockDate();
+    j$.getClearStack = jRequire.clearStack(j$);
+    j$.Clock = jRequire.Clock();
+    j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
+    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$.ArrayContaining = jRequire.ArrayContaining(j$);
+    j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
+    j$.pp = jRequire.pp(j$);
+    j$.QueueRunner = jRequire.QueueRunner(j$);
+    j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
+    j$.Spec = jRequire.Spec(j$);
+    j$.Spy = jRequire.Spy(j$);
+    j$.SpyRegistry = jRequire.SpyRegistry(j$);
+    j$.SpyStrategy = jRequire.SpyStrategy(j$);
+    j$.StringMatching = jRequire.StringMatching(j$);
+    j$.UserContext = jRequire.UserContext(j$);
+    j$.Suite = jRequire.Suite(j$);
+    j$.Timer = jRequire.Timer();
+    j$.TreeProcessor = jRequire.TreeProcessor();
+    j$.version = jRequire.version();
+    j$.Order = jRequire.Order();
+    j$.DiffBuilder = jRequire.DiffBuilder(j$);
+    j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$);
+    j$.ObjectPath = jRequire.ObjectPath(j$);
+    j$.GlobalErrors = jRequire.GlobalErrors(j$);
+
+    j$.matchers = jRequire.requireMatchers(jRequire, j$);
+
+    return j$;
+  };
+
+  return getJasmineRequire;
+})(this);
+
+getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
+  var availableMatchers = [
+      'nothing',
+      'toBe',
+      'toBeCloseTo',
+      'toBeDefined',
+      'toBeFalsy',
+      'toBeGreaterThan',
+      'toBeGreaterThanOrEqual',
+      'toBeLessThan',
+      'toBeLessThanOrEqual',
+      'toBeNaN',
+      'toBeNegativeInfinity',
+      'toBeNull',
+      'toBePositiveInfinity',
+      'toBeTruthy',
+      'toBeUndefined',
+      'toContain',
+      'toEqual',
+      'toHaveBeenCalled',
+      'toHaveBeenCalledBefore',
+      'toHaveBeenCalledTimes',
+      '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$, jasmineGlobal) {
+  j$.unimplementedMethod_ = function() {
+    throw new Error('unimplemented method');
+  };
+
+  /**
+   * Maximum object depth the pretty printer will print to.
+   * Set this to a lower value to speed up pretty printing if you have large objects.
+   * @name jasmine.MAX_PRETTY_PRINT_DEPTH
+   */
+  j$.MAX_PRETTY_PRINT_DEPTH = 8;
+  /**
+   * Maximum number of array elements to display when pretty printing objects.
+   * This will also limit the number of keys and values displayed for an object.
+   * Elements past this number will be ellipised.
+   * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
+   */
+  j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
+  /**
+   * Maximum number of charasters to display when pretty printing objects.
+   * Characters past this number will be ellipised.
+   * @name jasmine.MAX_PRETTY_PRINT_CHARS
+   */
+  j$.MAX_PRETTY_PRINT_CHARS = 1000;
+  /**
+   * Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
+   * @name jasmine.DEFAULT_TIMEOUT_INTERVAL
+   */
+  j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+  j$.getGlobal = function() {
+    return jasmineGlobal;
+  };
+
+  /**
+   * Get the currently booted Jasmine Environment.
+   *
+   * @name jasmine.getEnv
+   * @function
+   * @return {Env}
+   */
+  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$.isObject_ = function(value) {
+    return !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value);
+  };
+
+  j$.isString_ = function(value) {
+    return j$.isA_('String', value);
+  };
+
+  j$.isNumber_ = function(value) {
+    return j$.isA_('Number', value);
+  };
+
+  j$.isFunction_ = function(value) {
+    return j$.isA_('Function', value);
+  };
+
+  j$.isAsyncFunction_ = function(value) {
+    return j$.isA_('AsyncFunction', value);
+  };
+
+  j$.isTypedArray_ = function(value) {
+    return j$.isA_('Float32Array', value) ||
+      j$.isA_('Float64Array', value) ||
+      j$.isA_('Int16Array', value) ||
+      j$.isA_('Int32Array', value) ||
+      j$.isA_('Int8Array', value) ||
+      j$.isA_('Uint16Array', value) ||
+      j$.isA_('Uint32Array', value) ||
+      j$.isA_('Uint8Array', value) ||
+      j$.isA_('Uint8ClampedArray', value);
+  };
+
+  j$.isA_ = function(typeName, value) {
+    return j$.getType_(value) === '[object ' + typeName + ']';
+  };
+
+  j$.getType_ = function(value) {
+    return Object.prototype.toString.apply(value);
+  };
+
+  j$.isDomNode = function(obj) {
+    return obj.nodeType > 0;
+  };
+
+  j$.isMap = function(obj) {
+    return typeof jasmineGlobal.Map !== 'undefined' && obj.constructor === jasmineGlobal.Map;
+  };
+
+  j$.isSet = function(obj) {
+    return typeof jasmineGlobal.Set !== 'undefined' && obj.constructor === jasmineGlobal.Set;
+  };
+
+  j$.isPromise = function(obj) {
+    return typeof jasmineGlobal.Promise !== 'undefined' && obj.constructor === jasmineGlobal.Promise;
+  };
+
+  j$.fnNameFor = function(func) {
+    if (func.name) {
+      return func.name;
+    }
+
+    var matches = func.toString().match(/^\s*function\s*(\w*)\s*\(/) ||
+      func.toString().match(/^\s*\[object\s*(\w*)Constructor\]/);
+
+    return matches ? matches[1] : '<anonymous>';
+  };
+
+  /**
+   * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+   * that will succeed if the actual value being compared is an instance of the specified class/constructor.
+   * @name jasmine.any
+   * @function
+   * @param {Constructor} clazz - The constructor to check against.
+   */
+  j$.any = function(clazz) {
+    return new j$.Any(clazz);
+  };
+
+  /**
+   * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+   * that will succeed if the actual value being compared is not `null` and not `undefined`.
+   * @name jasmine.anything
+   * @function
+   */
+  j$.anything = function() {
+    return new j$.Anything();
+  };
+
+  /**
+   * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+   * that will succeed if the actual value being compared contains at least the keys and values.
+   * @name jasmine.objectContaining
+   * @function
+   * @param {Object} sample - The subset of properties that _must_ be in the actual.
+   */
+  j$.objectContaining = function(sample) {
+    return new j$.ObjectContaining(sample);
+  };
+
+  /**
+   * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+   * that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
+   * @name jasmine.stringMatching
+   * @function
+   * @param {RegExp|String} expected
+   */
+  j$.stringMatching = function(expected) {
+    return new j$.StringMatching(expected);
+  };
+
+  /**
+   * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+   * that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
+   * @name jasmine.arrayContaining
+   * @function
+   * @param {Array} sample
+   */
+  j$.arrayContaining = function(sample) {
+    return new j$.ArrayContaining(sample);
+  };
+
+  /**
+   * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+   * that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
+   * @name jasmine.arrayWithExactContents
+   * @function
+   * @param {Array} sample
+   */
+  j$.arrayWithExactContents = function(sample) {
+    return new j$.ArrayWithExactContents(sample);
+  };
+
+  /**
+   * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
+   * @name jasmine.createSpy
+   * @function
+   * @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
+   * @param {Function} [originalFn] - Function to act as the real implementation.
+   * @return {Spy}
+   */
+  j$.createSpy = function(name, originalFn) {
+    return j$.Spy(name, originalFn);
+  };
+
+  j$.isSpy = function(putativeSpy) {
+    if (!putativeSpy) {
+      return false;
+    }
+    return putativeSpy.and instanceof j$.SpyStrategy &&
+      putativeSpy.calls instanceof j$.CallTracker;
+  };
+
+  /**
+   * Create an object with multiple {@link Spy}s as its members.
+   * @name jasmine.createSpyObj
+   * @function
+   * @param {String} [baseName] - Base name for the spies in the object.
+   * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
+   * @return {Object}
+   */
+  j$.createSpyObj = function(baseName, methodNames) {
+    var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName);
+
+    if (baseNameIsCollection && j$.util.isUndefined(methodNames)) {
+      methodNames = baseName;
+      baseName = 'unknown';
+    }
+
+    var obj = {};
+    var spiesWereSet = false;
+
+    if (j$.isArray_(methodNames)) {
+      for (var i = 0; i < methodNames.length; i++) {
+        obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
+        spiesWereSet = true;
+      }
+    } else if (j$.isObject_(methodNames)) {
+      for (var key in methodNames) {
+        if (methodNames.hasOwnProperty(key)) {
+          obj[key] = j$.createSpy(baseName + '.' + key);
+          obj[key].and.returnValue(methodNames[key]);
+          spiesWereSet = true;
+        }
+      }
+    }
+
+    if (!spiesWereSet) {
+      throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
+    }
+
+    return obj;
+  };
+};
+
+getJasmineRequireObj().util = function(j$) {
+
+  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;
+  };
+
+  util.arrayContains = function(array, search) {
+    var i = array.length;
+    while (i--) {
+      if (array[i] === search) {
+        return true;
+      }
+    }
+    return false;
+  };
+
+  util.clone = function(obj) {
+    if (Object.prototype.toString.apply(obj) === '[object Array]') {
+      return obj.slice();
+    }
+
+    var cloned = {};
+    for (var prop in obj) {
+      if (obj.hasOwnProperty(prop)) {
+        cloned[prop] = obj[prop];
+      }
+    }
+
+    return cloned;
+  };
+
+  util.cloneArgs = function(args) {
+    var clonedArgs = [];
+    var argsAsArray = j$.util.argsToArray(args);
+    for(var i = 0; i < argsAsArray.length; i++) {
+      var str = Object.prototype.toString.apply(argsAsArray[i]),
+        primitives = /^\[object (Boolean|String|RegExp|Number)/;
+
+      // All falsey values are either primitives, `null`, or `undefined.
+      if (!argsAsArray[i] || str.match(primitives)) {
+        clonedArgs.push(argsAsArray[i]);
+      } else {
+        clonedArgs.push(j$.util.clone(argsAsArray[i]));
+      }
+    }
+    return clonedArgs;
+  };
+
+  util.getPropertyDescriptor = function(obj, methodName) {
+    var descriptor,
+      proto = obj;
+
+    do {
+      descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
+      proto = Object.getPrototypeOf(proto);
+    } while (!descriptor && proto);
+
+    return descriptor;
+  };
+
+  util.objectDifference = function(obj, toRemove) {
+    var diff = {};
+
+    for (var key in obj) {
+      if (util.has(obj, key) && !util.has(toRemove, key)) {
+        diff[key] = obj[key];
+      }
+    }
+
+    return diff;
+  };
+
+  util.has = function(obj, key) {
+    return Object.prototype.hasOwnProperty.call(obj, key);
+  };
+
+  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.queueableFn = attrs.queueableFn;
+    this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return {befores: [], afters: []}; };
+    this.userContext = attrs.userContext || function() { return {}; };
+    this.onStart = attrs.onStart || 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.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
+
+    if (!this.queueableFn.fn) {
+      this.pend();
+    }
+
+    /**
+     * @typedef SpecResult
+     * @property {Int} id - The unique id of this spec.
+     * @property {String} description - The description passed to the {@link it} that created this spec.
+     * @property {String} fullName - The full description including all ancestors of this spec.
+     * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
+     * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec.
+     * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
+     * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
+     * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
+     */
+    this.result = {
+      id: this.id,
+      description: this.description,
+      fullName: this.getFullName(),
+      failedExpectations: [],
+      passedExpectations: [],
+      deprecationWarnings: [],
+      pendingReason: ''
+    };
+  }
+
+  Spec.prototype.addExpectationResult = function(passed, data, isError) {
+    var expectationResult = this.expectationResultFactory(data);
+    if (passed) {
+      this.result.passedExpectations.push(expectationResult);
+    } else {
+      this.result.failedExpectations.push(expectationResult);
+
+      if (this.throwOnExpectationFailure && !isError) {
+        throw new j$.errors.ExpectationFailed();
+      }
+    }
+  };
+
+  Spec.prototype.expect = function(actual) {
+    return this.expectationFactory(actual, this);
+  };
+
+  Spec.prototype.execute = function(onComplete, enabled) {
+    var self = this;
+
+    this.onStart(this);
+
+    var fns = this.beforeAndAfterFns();
+    var regularFns = fns.befores.concat(this.queueableFn);
+
+    var runnerConfig = {
+      isLeaf: true,
+      queueableFns: regularFns,
+      cleanupFns: fns.afters,
+      onException: function() { self.onException.apply(self, arguments); },
+      onComplete: complete,
+      userContext: this.userContext()
+    };
+
+    if (!this.isExecutable() || this.markedPending || enabled === false) {
+      runnerConfig.queueableFns = [];
+      runnerConfig.cleanupFns = [];
+      runnerConfig.onComplete = function() { complete(enabled); };
+    }
+
+    this.queueRunnerFactory(runnerConfig);
+
+    function complete(enabledAgain) {
+      self.result.status = self.status(enabledAgain);
+      self.resultCallback(self.result);
+
+      if (onComplete) {
+        onComplete();
+      }
+    }
+  };
+
+  Spec.prototype.onException = function onException(e) {
+    if (Spec.isPendingSpecException(e)) {
+      this.pend(extractCustomPendingMessage(e));
+      return;
+    }
+
+    if (e instanceof j$.errors.ExpectationFailed) {
+      return;
+    }
+
+    this.addExpectationResult(false, {
+      matcherName: '',
+      passed: false,
+      expected: '',
+      actual: '',
+      error: e
+    }, true);
+  };
+
+  Spec.prototype.disable = function() {
+    this.disabled = true;
+  };
+
+  Spec.prototype.pend = function(message) {
+    this.markedPending = true;
+    if (message) {
+      this.result.pendingReason = message;
+    }
+  };
+
+  Spec.prototype.getResult = function() {
+    this.result.status = this.status();
+    return this.result;
+  };
+
+  Spec.prototype.status = function(enabled) {
+    if (this.disabled || enabled === false) {
+      return 'disabled';
+    }
+
+    if (this.markedPending) {
+      return 'pending';
+    }
+
+    if (this.result.failedExpectations.length > 0) {
+      return 'failed';
+    } else {
+      return 'passed';
+    }
+  };
+
+  Spec.prototype.isExecutable = function() {
+    return !this.disabled;
+  };
+
+  Spec.prototype.getFullName = function() {
+    return this.getSpecName(this);
+  };
+
+  Spec.prototype.addDeprecationWarning = function(msg) {
+    this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg }));
+  };
+
+  var extractCustomPendingMessage = function(e) {
+    var fullMessage = e.toString(),
+        boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),
+        boilerplateEnd = boilerplateStart + Spec.pendingSpecExceptionMessage.length;
+
+    return fullMessage.substr(boilerplateEnd);
+  };
+
+  Spec.pendingSpecExceptionMessage = '=> marked Pending';
+
+  Spec.isPendingSpecException = function(e) {
+    return !!(e && e.toString && e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1);
+  };
+
+  return Spec;
+};
+
+if (typeof window == void 0 && typeof exports == 'object') {
+  exports.Spec = jasmineRequire.Spec;
+}
+
+/*jshint bitwise: false*/
+
+getJasmineRequireObj().Order = function() {
+  function Order(options) {
+    this.random = 'random' in options ? options.random : true;
+    var seed = this.seed = options.seed || generateSeed();
+    this.sort = this.random ? randomOrder : naturalOrder;
+
+    function naturalOrder(items) {
+      return items;
+    }
+
+    function randomOrder(items) {
+      var copy = items.slice();
+      copy.sort(function(a, b) {
+        return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id);
+      });
+      return copy;
+    }
+
+    function generateSeed() {
+      return String(Math.random()).slice(-5);
+    }
+
+    // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function
+    // used to get a different output when the key changes slighly.
+    // We use your return to sort the children randomly in a consistent way when
+    // used in conjunction with a seed
+
+    function jenkinsHash(key) {
+      var hash, i;
+      for(hash = i = 0; i < key.length; ++i) {
+        hash += key.charCodeAt(i);
+        hash += (hash << 10);
+        hash ^= (hash >> 6);
+      }
+      hash += (hash << 3);
+      hash ^= (hash >> 11);
+      hash += (hash << 15);
+      return hash;
+    }
+
+  }
+
+  return Order;
+};
+
+getJasmineRequireObj().Env = function(j$) {
+  /**
+   * _Note:_ Do not construct this directly, Jasmine will make one during booting.
+   * @name Env
+   * @classdesc The Jasmine environment
+   * @constructor
+   */
+  function Env(options) {
+    options = options || {};
+
+    var self = this;
+    var global = options.global || j$.getGlobal();
+
+    var hasExecuted = false;
+
+    var totalSpecsDefined = 0;
+
+    var catchExceptions = true;
+
+    var realSetTimeout = j$.getGlobal().setTimeout;
+    var realClearTimeout = j$.getGlobal().clearTimeout;
+    var clearStack = j$.getClearStack(j$.getGlobal());
+    this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global));
+
+    var runnableResources = {};
+
+    var currentSpec = null;
+    var currentlyExecutingSuites = [];
+    var currentDeclarationSuite = null;
+    var throwOnExpectationFailure = false;
+    var random = false;
+    var seed = null;
+
+    var currentSuite = function() {
+      return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
+    };
+
+    var currentRunnable = function() {
+      return currentSpec || currentSuite();
+    };
+
+    /**
+     * This represents the available reporter callback for an object passed to {@link Env#addReporter}.
+     * @interface Reporter
+     */
+    var reporter = new j$.ReportDispatcher([
+      /**
+       * `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
+       * @function
+       * @name Reporter#jasmineStarted
+       * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
+       */
+      'jasmineStarted',
+      /**
+       * When the entire suite has finished execution `jasmineDone` is called
+       * @function
+       * @name Reporter#jasmineDone
+       * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
+       */
+      'jasmineDone',
+      /**
+       * `suiteStarted` is invoked when a `describe` starts to run
+       * @function
+       * @name Reporter#suiteStarted
+       * @param {SuiteResult} result Information about the individual {@link describe} being run
+       */
+      'suiteStarted',
+      /**
+       * `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
+       *
+       * While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
+       * @function
+       * @name Reporter#suiteDone
+       * @param {SuiteResult} result
+       */
+      'suiteDone',
+      /**
+       * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
+       * @function
+       * @name Reporter#specStarted
+       * @param {SpecResult} result Information about the individual {@link it} being run
+       */
+      'specStarted',
+      /**
+       * `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
+       *
+       * While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
+       * @function
+       * @name Reporter#specDone
+       * @param {SpecResult} result
+       */
+      'specDone'
+    ]);
+
+    var globalErrors = new j$.GlobalErrors();
+
+    this.specFilter = function() {
+      return true;
+    };
+
+    this.addCustomEqualityTester = function(tester) {
+      if(!currentRunnable()) {
+        throw new Error('Custom Equalities must be added in a before function or a spec');
+      }
+      runnableResources[currentRunnable().id].customEqualityTesters.push(tester);
+    };
+
+    this.addMatchers = function(matchersToAdd) {
+      if(!currentRunnable()) {
+        throw new Error('Matchers must be added in a before function or a spec');
+      }
+      var customMatchers = runnableResources[currentRunnable().id].customMatchers;
+      for (var matcherName in matchersToAdd) {
+        customMatchers[matcherName] = matchersToAdd[matcherName];
+      }
+    };
+
+    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: runnableResources[spec.id].customEqualityTesters,
+        customMatchers: runnableResources[spec.id].customMatchers,
+        actual: actual,
+        addExpectationResult: addExpectationResult
+      });
+
+      function addExpectationResult(passed, result) {
+        return spec.addExpectationResult(passed, result);
+      }
+    };
+
+    var defaultResourcesForRunnable = function(id, parentRunnableId) {
+      var resources = {spies: [], customEqualityTesters: [], customMatchers: {}};
+
+      if(runnableResources[parentRunnableId]){
+        resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters);
+        resources.customMatchers = j$.util.clone(runnableResources[parentRunnableId].customMatchers);
+      }
+
+      runnableResources[id] = resources;
+    };
+
+    var clearResourcesForRunnable = function(id) {
+        spyRegistry.clearSpies();
+        delete runnableResources[id];
+    };
+
+    var beforeAndAfterFns = function(suite) {
+      return function() {
+        var befores = [],
+          afters = [];
+
+        while(suite) {
+          befores = befores.concat(suite.beforeFns);
+          afters = afters.concat(suite.afterFns);
+
+          suite = suite.parentSuite;
+        }
+
+        return {
+          befores: befores.reverse(),
+          afters: afters
+        };
+      };
+    };
+
+    var getSpecName = function(spec, suite) {
+      var fullName = [spec.description],
+          suiteFullName = suite.getFullName();
+
+      if (suiteFullName !== '') {
+        fullName.unshift(suiteFullName);
+      }
+      return fullName.join(' ');
+    };
+
+    // 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) {
+      this.deprecated('The catchExceptions option is deprecated and will be replaced with stopOnSpecFailure in Jasmine 3.0');
+      catchExceptions = !!value;
+      return catchExceptions;
+    };
+
+    this.catchingExceptions = function() {
+      return catchExceptions;
+    };
+
+    var maximumSpecCallbackDepth = 20;
+    var currentSpecCallbackDepth = 0;
+
+    var catchException = function(e) {
+      return j$.Spec.isPendingSpecException(e) || catchExceptions;
+    };
+
+    this.throwOnExpectationFailure = function(value) {
+      throwOnExpectationFailure = !!value;
+    };
+
+    this.throwingExpectationFailures = function() {
+      return throwOnExpectationFailure;
+    };
+
+    this.randomizeTests = function(value) {
+      random = !!value;
+    };
+
+    this.randomTests = function() {
+      return random;
+    };
+
+    this.seed = function(value) {
+      if (value) {
+        seed = value;
+      }
+      return seed;
+    };
+
+    this.deprecated = function(msg) {
+      var runnable = currentRunnable() || topSuite;
+      runnable.addDeprecationWarning(msg);
+      if(typeof console !== 'undefined' && typeof console.warn !== 'undefined') {
+        console.error('DEPRECATION: ' + msg);
+      }
+    };
+
+    var queueRunnerFactory = function(options) {
+      options.catchException = catchException;
+      options.clearStack = options.clearStack || clearStack;
+      options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
+      options.fail = self.fail;
+      options.globalErrors = globalErrors;
+      options.completeOnFirstError = throwOnExpectationFailure && options.isLeaf;
+      options.deprecated = self.deprecated;
+
+      new j$.QueueRunner(options).execute();
+    };
+
+    var topSuite = new j$.Suite({
+      env: this,
+      id: getNextSuiteId(),
+      description: 'Jasmine__TopLevel__Suite',
+      expectationFactory: expectationFactory,
+      expectationResultFactory: expectationResultFactory
+    });
+    defaultResourcesForRunnable(topSuite.id);
+    currentDeclarationSuite = topSuite;
+
+    this.topSuite = function() {
+      return topSuite;
+    };
+
+    this.execute = function(runnablesToRun) {
+      if (hasExecuted) {
+        this.deprecated('Executing the same Jasmine multiple times will no longer work in Jasmine 3.0');
+      }
+
+      hasExecuted = true;
+
+      if(!runnablesToRun) {
+        if (focusedRunnables.length) {
+          runnablesToRun = focusedRunnables;
+        } else {
+          runnablesToRun = [topSuite.id];
+        }
+      }
+
+      var order = new j$.Order({
+        random: random,
+        seed: seed
+      });
+
+      var processor = new j$.TreeProcessor({
+        tree: topSuite,
+        runnableIds: runnablesToRun,
+        queueRunnerFactory: queueRunnerFactory,
+        nodeStart: function(suite) {
+          currentlyExecutingSuites.push(suite);
+          defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
+          reporter.suiteStarted(suite.result);
+        },
+        nodeComplete: function(suite, result) {
+          if (suite !== currentSuite()) {
+            throw new Error('Tried to complete the wrong suite');
+          }
+
+          if (!suite.markedPending) {
+            clearResourcesForRunnable(suite.id);
+          }
+          currentlyExecutingSuites.pop();
+          reporter.suiteDone(result);
+        },
+        orderChildren: function(node) {
+          return order.sort(node.children);
+        }
+      });
+
+      if(!processor.processTree().valid) {
+        throw new Error('Invalid order: would cause a beforeAll or afterAll to be run multiple times');
+      }
+
+      /**
+       * Information passed to the {@link Reporter#jasmineStarted} event.
+       * @typedef JasmineStartedInfo
+       * @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
+       * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
+       */
+      reporter.jasmineStarted({
+        totalSpecsDefined: totalSpecsDefined,
+        order: order
+      });
+
+      currentlyExecutingSuites.push(topSuite);
+
+      globalErrors.install();
+      processor.execute(function() {
+        clearResourcesForRunnable(topSuite.id);
+        currentlyExecutingSuites.pop();
+        globalErrors.uninstall();
+
+        /**
+         * Information passed to the {@link Reporter#jasmineDone} event.
+         * @typedef JasmineDoneInfo
+         * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
+         * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
+         * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
+         */
+        reporter.jasmineDone({
+          order: order,
+          failedExpectations: topSuite.result.failedExpectations,
+          deprecationWarnings: topSuite.result.deprecationWarnings
+        });
+      });
+    };
+
+    /**
+     * Add a custom reporter to the Jasmine environment.
+     * @name Env#addReporter
+     * @function
+     * @param {Reporter} reporterToAdd The reporter to be added.
+     * @see custom_reporter
+     */
+    this.addReporter = function(reporterToAdd) {
+      reporter.addReporter(reporterToAdd);
+    };
+
+    this.provideFallbackReporter = function(reporterToAdd) {
+      reporter.provideFallbackReporter(reporterToAdd);
+    };
+
+    this.clearReporters = function() {
+      reporter.clearReporters();
+    };
+
+    var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
+      if(!currentRunnable()) {
+        throw new Error('Spies must be created in a before function or a spec');
+      }
+      return runnableResources[currentRunnable().id].spies;
+    }});
+
+    this.allowRespy = function(allow){
+      spyRegistry.allowRespy(allow);
+    };
+
+    this.spyOn = function() {
+      return spyRegistry.spyOn.apply(spyRegistry, arguments);
+    };
+
+    this.spyOnProperty = function() {
+      return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
+    };
+
+    var ensureIsFunction = function(fn, caller) {
+      if (!j$.isFunction_(fn)) {
+        throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
+      }
+    };
+
+    var ensureIsFunctionOrAsync = function(fn, caller) {
+      if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) {
+        throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
+      }
+    };
+
+    function ensureIsNotNested(method) {
+      var runnable = currentRunnable();
+      if (runnable !== null && runnable !== undefined) {
+        throw new Error('\'' + method + '\' should only be used in \'describe\' function');
+      }
+    }
+
+    var suiteFactory = function(description) {
+      var suite = new j$.Suite({
+        env: self,
+        id: getNextSuiteId(),
+        description: description,
+        parentSuite: currentDeclarationSuite,
+        expectationFactory: expectationFactory,
+        expectationResultFactory: expectationResultFactory,
+        throwOnExpectationFailure: throwOnExpectationFailure
+      });
+
+      return suite;
+    };
+
+    this.describe = function(description, specDefinitions) {
+      ensureIsNotNested('describe');
+      ensureIsFunction(specDefinitions, 'describe');
+      var suite = suiteFactory(description);
+      if (specDefinitions.length > 0) {
+        throw new Error('describe does not expect any arguments');
+      }
+      if (currentDeclarationSuite.markedPending) {
+        suite.pend();
+      }
+      addSpecsToSuite(suite, specDefinitions);
+      return suite;
+    };
+
+    this.xdescribe = function(description, specDefinitions) {
+      ensureIsNotNested('xdescribe');
+      ensureIsFunction(specDefinitions, 'xdescribe');
+      var suite = suiteFactory(description);
+      suite.pend();
+      addSpecsToSuite(suite, specDefinitions);
+      return suite;
+    };
+
+    var focusedRunnables = [];
+
+    this.fdescribe = function(description, specDefinitions) {
+      this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0');
+      ensureIsNotNested('fdescribe');
+      ensureIsFunction(specDefinitions, 'fdescribe');
+      var suite = suiteFactory(description);
+      suite.isFocused = true;
+
+      focusedRunnables.push(suite.id);
+      unfocusAncestor();
+      addSpecsToSuite(suite, specDefinitions);
+
+      return suite;
+    };
+
+    function addSpecsToSuite(suite, specDefinitions) {
+      var parentSuite = currentDeclarationSuite;
+      parentSuite.addChild(suite);
+      currentDeclarationSuite = suite;
+
+      var declarationError = null;
+      try {
+        specDefinitions.call(suite);
+      } catch (e) {
+        declarationError = e;
+      }
+
+      if (declarationError) {
+        self.it('encountered a declaration exception', function() {
+          throw declarationError;
+        });
+      }
+
+      currentDeclarationSuite = parentSuite;
+    }
+
+    function findFocusedAncestor(suite) {
+      while (suite) {
+        if (suite.isFocused) {
+          return suite.id;
+        }
+        suite = suite.parentSuite;
+      }
+
+      return null;
+    }
+
+    function unfocusAncestor() {
+      var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
+      if (focusedAncestor) {
+        for (var i = 0; i < focusedRunnables.length; i++) {
+          if (focusedRunnables[i] === focusedAncestor) {
+            focusedRunnables.splice(i, 1);
+            break;
+          }
+        }
+      }
+    }
+
+    var specFactory = function(description, fn, suite, timeout) {
+      totalSpecsDefined++;
+      var spec = new j$.Spec({
+        id: getNextSpecId(),
+        beforeAndAfterFns: beforeAndAfterFns(suite),
+        expectationFactory: expectationFactory,
+        resultCallback: specResultCallback,
+        getSpecName: function(spec) {
+          return getSpecName(spec, suite);
+        },
+        onStart: specStarted,
+        description: description,
+        expectationResultFactory: expectationResultFactory,
+        queueRunnerFactory: queueRunnerFactory,
+        userContext: function() { return suite.clonedSharedUserContext(); },
+        queueableFn: {
+          fn: fn,
+          timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
+        },
+        throwOnExpectationFailure: throwOnExpectationFailure
+      });
+
+      if (!self.specFilter(spec)) {
+        spec.disable();
+      }
+
+      return spec;
+
+      function specResultCallback(result) {
+        clearResourcesForRunnable(spec.id);
+        currentSpec = null;
+        reporter.specDone(result);
+      }
+
+      function specStarted(spec) {
+        currentSpec = spec;
+        defaultResourcesForRunnable(spec.id, suite.id);
+        reporter.specStarted(spec.result);
+      }
+    };
+
+    this.it = function(description, fn, timeout) {
+      ensureIsNotNested('it');
+      // it() sometimes doesn't have a fn argument, so only check the type if
+      // it's given.
+      if (arguments.length > 1 && typeof fn !== 'undefined') {
+        ensureIsFunctionOrAsync(fn, 'it');
+      }
+      var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
+      if (currentDeclarationSuite.markedPending) {
+        spec.pend();
+      }
+      currentDeclarationSuite.addChild(spec);
+      return spec;
+    };
+
+    this.xit = function(description, fn, timeout) {
+      ensureIsNotNested('xit');
+      // xit(), like it(), doesn't always have a fn argument, so only check the
+      // type when needed.
+      if (arguments.length > 1 && typeof fn !== 'undefined') {
+        ensureIsFunctionOrAsync(fn, 'xit');
+      }
+      var spec = this.it.apply(this, arguments);
+      spec.pend('Temporarily disabled with xit');
+      return spec;
+    };
+
+    this.fit = function(description, fn, timeout){
+      this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0');
+      ensureIsNotNested('fit');
+      ensureIsFunctionOrAsync(fn, 'fit');
+      var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
+      currentDeclarationSuite.addChild(spec);
+      focusedRunnables.push(spec.id);
+      unfocusAncestor();
+      return spec;
+    };
+
+    this.expect = function(actual) {
+      if (!currentRunnable()) {
+        throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out');
+      }
+
+      return currentRunnable().expect(actual);
+    };
+
+    this.beforeEach = function(beforeEachFunction, timeout) {
+      ensureIsNotNested('beforeEach');
+      ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
+      currentDeclarationSuite.beforeEach({
+        fn: beforeEachFunction,
+        timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
+      });
+    };
+
+    this.beforeAll = function(beforeAllFunction, timeout) {
+      ensureIsNotNested('beforeAll');
+      ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
+      currentDeclarationSuite.beforeAll({
+        fn: beforeAllFunction,
+        timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
+      });
+    };
+
+    this.afterEach = function(afterEachFunction, timeout) {
+      ensureIsNotNested('afterEach');
+      ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
+      afterEachFunction.isCleanup = true;
+      currentDeclarationSuite.afterEach({
+        fn: afterEachFunction,
+        timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
+      });
+    };
+
+    this.afterAll = function(afterAllFunction, timeout) {
+      ensureIsNotNested('afterAll');
+      ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
+      currentDeclarationSuite.afterAll({
+        fn: afterAllFunction,
+        timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
+      });
+    };
+
+    this.pending = function(message) {
+      var fullMessage = j$.Spec.pendingSpecExceptionMessage;
+      if(message) {
+        fullMessage += message;
+      }
+      throw fullMessage;
+    };
+
+    this.fail = function(error) {
+      if (!currentRunnable()) {
+        throw new Error('\'fail\' was used when there was no current spec, this could be because an asynchronous test timed out');
+      }
+
+      var message = 'Failed';
+      if (error) {
+        message += ': ';
+        if (error.message) {
+          message += error.message;
+        } else if (jasmine.isString_(error)) {
+          message += error;
+        } else {
+          // pretty print all kind of objects. This includes arrays.
+          message += jasmine.pp(error);
+        }
+      }
+
+      currentRunnable().addExpectationResult(false, {
+        matcherName: '',
+        passed: false,
+        expected: '',
+        actual: '',
+        message: message,
+        error: error && error.message ? error : null
+      });
+
+      if (self.throwingExpectationFailures()) {
+        throw new Error(message);
+      }
+    };
+  }
+
+  return Env;
+};
+
+getJasmineRequireObj().JsApiReporter = function() {
+
+  var noopTimer = {
+    start: function(){},
+    elapsed: function(){ return 0; }
+  };
+
+  /**
+   * @name jsApiReporter
+   * @classdesc {@link Reporter} added by default in `boot.js` to record results for retrieval in javascript code. An instance is made available as `jsApiReporter` on the global object.
+   * @class
+   * @hideconstructor
+   */
+  function JsApiReporter(options) {
+    var timer = options.timer || noopTimer,
+        status = 'loaded';
+
+    this.started = false;
+    this.finished = false;
+    this.runDetails = {};
+
+    this.jasmineStarted = function() {
+      this.started = true;
+      status = 'started';
+      timer.start();
+    };
+
+    var executionTime;
+
+    this.jasmineDone = function(runDetails) {
+      this.finished = true;
+      this.runDetails = runDetails;
+      executionTime = timer.elapsed();
+      status = 'done';
+    };
+
+    /**
+     * Get the current status for the Jasmine environment.
+     * @name jsApiReporter#status
+     * @function
+     * @return {String} - One of `loaded`, `started`, or `done`
+     */
+    this.status = function() {
+      return status;
+    };
+
+    var suites = [],
+      suites_hash = {};
+
+    this.suiteStarted = function(result) {
+      suites_hash[result.id] = result;
+    };
+
+    this.suiteDone = function(result) {
+      storeSuite(result);
+    };
+
+    /**
+     * Get the results for a set of suites.
+     *
+     * Retrievable in slices for easier serialization.
+     * @name jsApiReporter#suiteResults
+     * @function
+     * @param {Number} index - The position in the suites list to start from.
+     * @param {Number} length - Maximum number of suite results to return.
+     * @return {SuiteResult[]}
+     */
+    this.suiteResults = function(index, length) {
+      return suites.slice(index, index + length);
+    };
+
+    function storeSuite(result) {
+      suites.push(result);
+      suites_hash[result.id] = result;
+    }
+
+    /**
+     * Get all of the suites in a single object, with their `id` as the key.
+     * @name jsApiReporter#suites
+     * @function
+     * @return {Object} - Map of suite id to {@link SuiteResult}
+     */
+    this.suites = function() {
+      return suites_hash;
+    };
+
+    var specs = [];
+
+    this.specDone = function(result) {
+      specs.push(result);
+    };
+
+    /**
+     * Get the results for a set of specs.
+     *
+     * Retrievable in slices for easier serialization.
+     * @name jsApiReporter#specResults
+     * @function
+     * @param {Number} index - The position in the specs list to start from.
+     * @param {Number} length - Maximum number of specs results to return.
+     * @return {SpecResult[]}
+     */
+    this.specResults = function(index, length) {
+      return specs.slice(index, index + length);
+    };
+
+    /**
+     * Get all spec results.
+     * @name jsApiReporter#specs
+     * @function
+     * @return {SpecResult[]}
+     */
+    this.specs = function() {
+      return specs;
+    };
+
+    /**
+     * Get the number of milliseconds it took for the full Jasmine suite to run.
+     * @name jsApiReporter#executionTime
+     * @function
+     * @return {Number}
+     */
+    this.executionTime = function() {
+      return executionTime;
+    };
+
+  }
+
+  return JsApiReporter;
+};
+
+getJasmineRequireObj().Any = function(j$) {
+
+  function Any(expectedObject) {
+    if (typeof expectedObject === 'undefined') {
+      throw new TypeError(
+        'jasmine.any() expects to be passed a constructor function. ' +
+        'Please pass one or use jasmine.anything() to match any object.'
+      );
+    }
+    this.expectedObject = expectedObject;
+  }
+
+  Any.prototype.asymmetricMatch = 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) {
+      if (other === null) {
+        j$.getEnv().deprecated('jasmine.Any(Object) will no longer match null in Jasmine 3.0');
+      }
+      return typeof other == 'object';
+    }
+
+    if (this.expectedObject == Boolean) {
+      return typeof other == 'boolean';
+    }
+
+    /* jshint -W122 */
+    if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
+      return typeof other == 'symbol';
+    }
+    /* jshint +W122 */
+
+    return other instanceof this.expectedObject;
+  };
+
+  Any.prototype.jasmineToString = function() {
+    return '<jasmine.any(' + j$.fnNameFor(this.expectedObject) + ')>';
+  };
+
+  return Any;
+};
+
+getJasmineRequireObj().Anything = function(j$) {
+
+  function Anything() {}
+
+  Anything.prototype.asymmetricMatch = function(other) {
+    return !j$.util.isUndefined(other) && other !== null;
+  };
+
+  Anything.prototype.jasmineToString = function() {
+    return '<jasmine.anything>';
+  };
+
+  return Anything;
+};
+
+getJasmineRequireObj().ArrayContaining = function(j$) {
+  function ArrayContaining(sample) {
+    this.sample = sample;
+  }
+
+  ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
+    if (!j$.isArray_(this.sample)) {
+      throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.');
+    }
+
+    for (var i = 0; i < this.sample.length; i++) {
+      var item = this.sample[i];
+      if (!j$.matchersUtil.contains(other, item, customTesters)) {
+        return false;
+      }
+    }
+
+    return true;
+  };
+
+  ArrayContaining.prototype.jasmineToString = function () {
+    return '<jasmine.arrayContaining(' + jasmine.pp(this.sample) +')>';
+  };
+
+  return ArrayContaining;
+};
+
+getJasmineRequireObj().ArrayWithExactContents = function(j$) {
+
+  function ArrayWithExactContents(sample) {
+    this.sample = sample;
+  }
+
+  ArrayWithExactContents.prototype.asymmetricMatch = function(other, customTesters) {
+    if (!j$.isArray_(this.sample)) {
+      throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.');
+    }
+
+    if (this.sample.length !== other.length) {
+      return false;
+    }
+
+    for (var i = 0; i < this.sample.length; i++) {
+      var item = this.sample[i];
+      if (!j$.matchersUtil.contains(other, item, customTesters)) {
+        return false;
+      }
+    }
+
+    return true;
+  };
+
+  ArrayWithExactContents.prototype.jasmineToString = function() {
+    return '<jasmine.arrayWithExactContents ' + j$.pp(this.sample) + '>';
+  };
+
+  return ArrayWithExactContents;
+};
+
+getJasmineRequireObj().ObjectContaining = function(j$) {
+
+  function ObjectContaining(sample) {
+    this.sample = sample;
+  }
+
+  function getPrototype(obj) {
+    if (Object.getPrototypeOf) {
+      return Object.getPrototypeOf(obj);
+    }
+
+    if (obj.constructor.prototype == obj) {
+      return null;
+    }
+
+    return obj.constructor.prototype;
+  }
+
+  function hasProperty(obj, property) {
+    if (!obj) {
+      return false;
+    }
+
+    if (Object.prototype.hasOwnProperty.call(obj, property)) {
+      return true;
+    }
+
+    return hasProperty(getPrototype(obj), property);
+  }
+
+  ObjectContaining.prototype.asymmetricMatch = function(other, customTesters) {
+    if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
+
+    for (var property in this.sample) {
+      if (!hasProperty(other, property) ||
+          !j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) {
+        return false;
+      }
+    }
+
+    return true;
+  };
+
+  ObjectContaining.prototype.jasmineToString = function() {
+    return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
+  };
+
+  return ObjectContaining;
+};
+
+getJasmineRequireObj().StringMatching = function(j$) {
+
+  function StringMatching(expected) {
+    if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
+      throw new Error('Expected is not a String or a RegExp');
+    }
+
+    this.regexp = new RegExp(expected);
+  }
+
+  StringMatching.prototype.asymmetricMatch = function(other) {
+    return this.regexp.test(other);
+  };
+
+  StringMatching.prototype.jasmineToString = function() {
+    return '<jasmine.stringMatching(' + this.regexp + ')>';
+  };
+
+  return StringMatching;
+};
+
+getJasmineRequireObj().CallTracker = function(j$) {
+
+  /**
+   * @namespace Spy#calls
+   */
+  function CallTracker() {
+    var calls = [];
+    var opts = {};
+
+    this.track = function(context) {
+      if(opts.cloneArgs) {
+        context.args = j$.util.cloneArgs(context.args);
+      }
+      calls.push(context);
+    };
+
+    /**
+     * Check whether this spy has been invoked.
+     * @name Spy#calls#any
+     * @function
+     * @return {Boolean}
+     */
+    this.any = function() {
+      return !!calls.length;
+    };
+
+    /**
+     * Get the number of invocations of this spy.
+     * @name Spy#calls#count
+     * @function
+     * @return {Integer}
+     */
+    this.count = function() {
+      return calls.length;
+    };
+
+    /**
+     * Get the arguments that were passed to a specific invocation of this spy.
+     * @name Spy#calls#argsFor
+     * @function
+     * @param {Integer} index The 0-based invocation index.
+     * @return {Array}
+     */
+    this.argsFor = function(index) {
+      var call = calls[index];
+      return call ? call.args : [];
+    };
+
+    /**
+     * Get the raw calls array for this spy.
+     * @name Spy#calls#all
+     * @function
+     * @return {Spy.callData[]}
+     */
+    this.all = function() {
+      return calls;
+    };
+
+    /**
+     * Get all of the arguments for each invocation of this spy in the order they were received.
+     * @name Spy#calls#allArgs
+     * @function
+     * @return {Array}
+     */
+    this.allArgs = function() {
+      var callArgs = [];
+      for(var i = 0; i < calls.length; i++){
+        callArgs.push(calls[i].args);
+      }
+
+      return callArgs;
+    };
+
+    /**
+     * Get the first invocation of this spy.
+     * @name Spy#calls#first
+     * @function
+     * @return {ObjecSpy.callData}
+     */
+    this.first = function() {
+      return calls[0];
+    };
+
+    /**
+     * Get the most recent invocation of this spy.
+     * @name Spy#calls#mostRecent
+     * @function
+     * @return {ObjecSpy.callData}
+     */
+    this.mostRecent = function() {
+      return calls[calls.length - 1];
+    };
+
+    /**
+     * Reset this spy as if it has never been called.
+     * @name Spy#calls#reset
+     * @function
+     */
+    this.reset = function() {
+      calls = [];
+    };
+
+    /**
+     * Set this spy to do a shallow clone of arguments passed to each invocation.
+     * @name Spy#calls#saveArgumentsByValue
+     * @function
+     */
+    this.saveArgumentsByValue = function() {
+      opts.cloneArgs = true;
+    };
+
+  }
+
+  return CallTracker;
+};
+
+getJasmineRequireObj().clearStack = function(j$) {
+  var maxInlineCallCount = 10;
+
+  function messageChannelImpl(global, setTimeout) {
+    var channel = new global.MessageChannel(),
+        head = {},
+        tail = head;
+
+    var taskRunning = false;
+    channel.port1.onmessage = function() {
+      head = head.next;
+      var task = head.task;
+      delete head.task;
+
+      if (taskRunning) {
+        global.setTimeout(task, 0);
+      } else {
+        try {
+          taskRunning = true;
+          task();
+        } finally {
+          taskRunning = false;
+        }
+      }
+    };
+
+    var currentCallCount = 0;
+    return function clearStack(fn) {
+      currentCallCount++;
+
+      if (currentCallCount < maxInlineCallCount) {
+        tail = tail.next = { task: fn };
+        channel.port2.postMessage(0);
+      } else {
+        currentCallCount = 0;
+        setTimeout(fn);
+      }
+    };
+  }
+
+  function getClearStack(global) {
+    var currentCallCount = 0;
+    var realSetTimeout = global.setTimeout;
+    var setTimeoutImpl = function clearStack(fn) {
+        Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
+    };
+
+    if (j$.isFunction_(global.setImmediate)) {
+      var realSetImmediate = global.setImmediate;
+      return function(fn) {
+        currentCallCount++;
+
+        if (currentCallCount < maxInlineCallCount) {
+          realSetImmediate(fn);
+        } else {
+          currentCallCount = 0;
+
+          setTimeoutImpl(fn);
+        }
+      };
+    } else if (!j$.util.isUndefined(global.MessageChannel)) {
+      return messageChannelImpl(global, setTimeoutImpl);
+    } else {
+      return setTimeoutImpl;
+    }
+  }
+
+  return getClearStack;
+};
+
+getJasmineRequireObj().Clock = function() {
+
+  var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string';
+
+  /**
+   * _Note:_ Do not construct this directly, Jasmine will make one during booting. You can get the current clock with {@link jasmine.clock}.
+   * @class Clock
+   * @classdesc Jasmine's mock clock is used when testing time dependent code.
+   */
+  function Clock(global, delayedFunctionSchedulerFactory, mockDate) {
+    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,
+      delayedFunctionScheduler,
+      timer;
+
+    self.FakeTimeout = FakeTimeout;
+
+    /**
+     * Install the mock clock over the built-in methods.
+     * @name Clock#install
+     * @function
+     * @return {Clock}
+     */
+    self.install = function() {
+      if(!originalTimingFunctionsIntact()) {
+        throw new Error('Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?');
+      }
+      replace(global, fakeTimingFunctions);
+      timer = fakeTimingFunctions;
+      delayedFunctionScheduler = delayedFunctionSchedulerFactory();
+      installed = true;
+
+      return self;
+    };
+
+    /**
+     * Uninstall the mock clock, returning the built-in methods to their places.
+     * @name Clock#uninstall
+     * @function
+     */
+    self.uninstall = function() {
+      delayedFunctionScheduler = null;
+      mockDate.uninstall();
+      replace(global, realTimingFunctions);
+
+      timer = realTimingFunctions;
+      installed = false;
+    };
+
+    /**
+     * Execute a function with a mocked Clock
+     *
+     * The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes.
+     * @name Clock#withMock
+     * @function
+     * @param {closure} Function The function to be called.
+     */
+    self.withMock = function(closure) {
+      this.install();
+      try {
+        closure();
+      } finally {
+        this.uninstall();
+      }
+    };
+
+    /**
+     * Instruct the installed Clock to also mock the date returned by `new Date()`
+     * @name Clock#mockDate
+     * @function
+     * @param {Date} [initialDate=now] The `Date` to provide.
+     */
+    self.mockDate = function(initialDate) {
+      mockDate.install(initialDate);
+    };
+
+    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]);
+    };
+
+    /**
+     * Tick the Clock forward, running any enqueued timeouts along the way
+     * @name Clock#tick
+     * @function
+     * @param {int} millis The number of milliseconds to tick.
+     */
+    self.tick = function(millis) {
+      if (installed) {
+        delayedFunctionScheduler.tick(millis, function(millis) { mockDate.tick(millis); });
+      } else {
+        throw new Error('Mock clock is not installed, use jasmine.clock().install()');
+      }
+    };
+
+    return self;
+
+    function originalTimingFunctionsIntact() {
+      return global.setTimeout === realTimingFunctions.setTimeout &&
+        global.clearTimeout === realTimingFunctions.clearTimeout &&
+        global.setInterval === realTimingFunctions.setInterval &&
+        global.clearInterval === realTimingFunctions.clearInterval;
+    }
+
+    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) {
+      if (!NODE_JS) {
+        return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
+      }
+
+      var timeout = new FakeTimeout();
+
+      delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2), false, timeout);
+
+      return timeout;
+    }
+
+    function clearTimeout(id) {
+      return delayedFunctionScheduler.removeFunctionWithId(id);
+    }
+
+    function setInterval(fn, interval) {
+      if (!NODE_JS) {
+        return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
+      }
+
+      var timeout = new FakeTimeout();
+
+      delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true, timeout);
+
+      return timeout;
+    }
+
+    function clearInterval(id) {
+      return delayedFunctionScheduler.removeFunctionWithId(id);
+    }
+
+    function argSlice(argsObj, n) {
+      return Array.prototype.slice.call(argsObj, n);
+    }
+  }
+
+  /**
+   * Mocks Node.js Timeout class
+   */
+  function FakeTimeout() {}
+
+  FakeTimeout.prototype.ref = function () {
+    return this;
+  };
+
+  FakeTimeout.prototype.unref = function () {
+    return this;
+  };
+
+  return Clock;
+};
+
+getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
+  function DelayedFunctionScheduler() {
+    var self = this;
+    var scheduledLookup = [];
+    var scheduledFunctions = {};
+    var currentTime = 0;
+    var delayedFnCount = 0;
+    var deletedKeys = [];
+
+    self.tick = function(millis, tickDate) {
+      millis = millis || 0;
+      var endTime = currentTime + millis;
+
+      runScheduledFunctions(endTime, tickDate);
+      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) {
+      deletedKeys.push(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;
+        }
+      }
+    };
+
+    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 forEachFunction(funcsToRun, callback) {
+      for (var i = 0; i < funcsToRun.length; ++i) {
+        callback(funcsToRun[i]);
+      }
+    }
+
+    function runScheduledFunctions(endTime, tickDate) {
+      tickDate = tickDate || function() {};
+      if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
+        tickDate(endTime - currentTime);
+        return;
+      }
+
+      do {
+        deletedKeys = [];
+        var newCurrentTime = scheduledLookup.shift();
+        tickDate(newCurrentTime - currentTime);
+
+        currentTime = newCurrentTime;
+
+        var funcsToRun = scheduledFunctions[currentTime];
+
+        delete scheduledFunctions[currentTime];
+
+        forEachFunction(funcsToRun, function(funcToRun) {
+          if (funcToRun.recurring) {
+            reschedule(funcToRun);
+          }
+        });
+
+        forEachFunction(funcsToRun, function(funcToRun) {
+          if (j$.util.arrayContains(deletedKeys, funcToRun.timeoutKey)) {
+            // skip a timeoutKey deleted whilst we were running
+            return;
+          }
+          funcToRun.funcToCall.apply(null, funcToRun.params || []);
+        });
+      } 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);
+
+      // ran out of functions to call, but still time left on the clock
+      if (currentTime !== endTime) {
+        tickDate(endTime - currentTime);
+      }
+    }
+  }
+
+  return DelayedFunctionScheduler;
+};
+
+getJasmineRequireObj().errors = function() {
+  function ExpectationFailed() {}
+
+  ExpectationFailed.prototype = new Error();
+  ExpectationFailed.prototype.constructor = ExpectationFailed;
+
+  return {
+    ExpectationFailed: ExpectationFailed
+  };
+};
+getJasmineRequireObj().ExceptionFormatter = function() {
+  function ExceptionFormatter() {
+    this.message = function(error) {
+      var message = '';
+
+      if (error.name && error.message) {
+        message += error.name + ': ' + error.message;
+      } else {
+        message += error.toString() + ' thrown';
+      }
+
+      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() {
+
+  /**
+   * Matchers that come with Jasmine out of the box.
+   * @namespace 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;
+
+    var customMatchers = options.customMatchers || {};
+    for (var matcherName in customMatchers) {
+      this[matcherName] = Expectation.prototype.wrapCompare(matcherName, customMatchers[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 {
+          if (Object.prototype.toString.apply(result.message) === '[object Function]') {
+            message = result.message();
+          } 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,
+          error: result.error,
+          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.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() {};
+
+    /**
+     * @typedef Expectation
+     * @property {String} matcherName - The name of the matcher that was executed for this expectation.
+     * @property {String} message - The failure message for the expectation.
+     * @property {String} stack - The stack trace for the failure if available.
+     * @property {Boolean} passed - Whether the expectation passed or failed.
+     * @property {Object} expected - If the expectation failed, what was the expected value.
+     * @property {Object} actual - If the expectation failed, what actual value was produced.
+     */
+    var result = {
+      matcherName: options.matcherName,
+      message: message(),
+      stack: stack(),
+      passed: options.passed
+    };
+
+    if(!result.passed) {
+      result.expected = options.expected;
+      result.actual = options.actual;
+    }
+
+    return result;
+
+    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().formatErrorMsg = function() {
+  function generateErrorMsg(domain, usage) {
+    var usageDefinition = usage ? '\nUsage: ' + usage : '';
+
+    return function errorMsg(msg) {
+      return domain + ' : ' + msg + usageDefinition;
+    };
+  }
+
+  return generateErrorMsg;
+};
+
+getJasmineRequireObj().GlobalErrors = function(j$) {
+  function GlobalErrors(global) {
+    var handlers = [];
+    global = global || j$.getGlobal();
+
+    var onerror = function onerror() {
+      var handler = handlers[handlers.length - 1];
+
+      if (handler) {
+        handler.apply(null, Array.prototype.slice.call(arguments, 0));
+      } else {
+        throw arguments[0];
+      }
+    };
+
+    this.uninstall = function noop() {};
+
+    this.install = function install() {
+      if (global.process && global.process.listeners && j$.isFunction_(global.process.on)) {
+        var originalHandlers = global.process.listeners('uncaughtException');
+        global.process.removeAllListeners('uncaughtException');
+        global.process.on('uncaughtException', onerror);
+
+        this.uninstall = function uninstall() {
+          global.process.removeListener('uncaughtException', onerror);
+          for (var i = 0; i < originalHandlers.length; i++) {
+            global.process.on('uncaughtException', originalHandlers[i]);
+          }
+        };
+      } else {
+        var originalHandler = global.onerror;
+        global.onerror = onerror;
+
+        this.uninstall = function uninstall() {
+          global.onerror = originalHandler;
+        };
+      }
+    };
+
+    this.pushListener = function pushListener(listener) {
+      handlers.push(listener);
+    };
+
+    this.popListener = function popListener() {
+      handlers.pop();
+    };
+  }
+
+  return GlobalErrors;
+};
+
+getJasmineRequireObj().DiffBuilder = function(j$) {
+  return function DiffBuilder() {
+    var path = new j$.ObjectPath(),
+        mismatches = [];
+
+    return {
+      record: function (actual, expected, formatter) {
+        formatter = formatter || defaultFormatter;
+        mismatches.push(formatter(actual, expected, path));
+      },
+
+      getMessage: function () {
+        return mismatches.join('\n');
+      },
+
+      withPath: function (pathComponent, block) {
+        var oldPath = path;
+        path = path.add(pathComponent);
+        block();
+        path = oldPath;
+      }
+    };
+
+    function defaultFormatter (actual, expected, path) {
+      return 'Expected ' +
+        path + (path.depth() ? ' = ' : '') +
+        j$.pp(actual) +
+        ' to equal ' +
+        j$.pp(expected) +
+        '.';
+    }
+  };
+};
+
+getJasmineRequireObj().matchersUtil = function(j$) {
+  // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
+
+  return {
+    equals: equals,
+
+    contains: function(haystack, needle, customTesters) {
+      customTesters = customTesters || [];
+
+      if ((Object.prototype.toString.apply(haystack) === '[object Set]')) {
+        return haystack.has(needle);
+      }
+
+      if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
+        (!!haystack && !haystack.indexOf))
+      {
+        for (var i = 0; i < haystack.length; i++) {
+          if (equals(haystack[i], needle, customTesters)) {
+            return true;
+          }
+        }
+        return false;
+      }
+
+      return !!haystack && 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 + '.';
+    }
+  };
+
+  function isAsymmetric(obj) {
+    return obj && j$.isA_('Function', obj.asymmetricMatch);
+  }
+
+  function asymmetricMatch(a, b, customTesters, diffBuilder) {
+    var asymmetricA = isAsymmetric(a),
+        asymmetricB = isAsymmetric(b),
+        result;
+
+    if (asymmetricA && asymmetricB) {
+      return undefined;
+    }
+
+    if (asymmetricA) {
+      result = a.asymmetricMatch(b, customTesters);
+      if (!result) {
+        diffBuilder.record(a, b);
+      }
+      return result;
+    }
+
+    if (asymmetricB) {
+      result = b.asymmetricMatch(a, customTesters);
+      if (!result) {
+        diffBuilder.record(a, b);
+      }
+      return result;
+    }
+  }
+
+  function equals(a, b, customTesters, diffBuilder) {
+    customTesters = customTesters || [];
+    diffBuilder = diffBuilder || j$.NullDiffBuilder();
+
+    return eq(a, b, [], [], customTesters, diffBuilder);
+  }
+
+  // Equality function lovingly adapted from isEqual in
+  //   [Underscore](http://underscorejs.org)
+  function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
+    var result = true, i;
+
+    var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder);
+    if (!j$.util.isUndefined(asymmetricResult)) {
+      return asymmetricResult;
+    }
+
+    for (i = 0; i < customTesters.length; i++) {
+      var customTesterResult = customTesters[i](a, b);
+      if (!j$.util.isUndefined(customTesterResult)) {
+        if (!customTesterResult) {
+          diffBuilder.record(a, b);
+        }
+        return customTesterResult;
+      }
+    }
+
+    if (a instanceof Error && b instanceof Error) {
+      result = a.message == b.message;
+      if (!result) {
+        diffBuilder.record(a, b);
+      }
+      return result;
+    }
+
+    // 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) {
+      result = a !== 0 || 1 / a == 1 / b;
+      if (!result) {
+        diffBuilder.record(a, b);
+      }
+      return result;
+    }
+    // A strict comparison is necessary because `null == undefined`.
+    if (a === null || b === null) {
+      result = a === b;
+      if (!result) {
+        diffBuilder.record(a, b);
+      }
+      return result;
+    }
+    var className = Object.prototype.toString.call(a);
+    if (className != Object.prototype.toString.call(b)) {
+      diffBuilder.record(a, 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")`.
+        result = a == String(b);
+        if (!result) {
+          diffBuilder.record(a, b);
+        }
+        return result;
+      case '[object Number]':
+        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
+        // other numeric values.
+        result = a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
+        if (!result) {
+          diffBuilder.record(a, b);
+        }
+        return result;
+      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.
+        result = +a == +b;
+        if (!result) {
+          diffBuilder.record(a, b);
+        }
+        return result;
+      // 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') {
+      diffBuilder.record(a, b);
+      return false;
+    }
+
+    var aIsDomNode = j$.isDomNode(a);
+    var bIsDomNode = j$.isDomNode(b);
+    if (aIsDomNode && bIsDomNode) {
+      // At first try to use DOM3 method isEqualNode
+      if (a.isEqualNode) {
+        result = a.isEqualNode(b);
+        if (!result) {
+          diffBuilder.record(a, b);
+        }
+        return result;
+      }
+      // IE8 doesn't support isEqualNode, try to use outerHTML && innerText
+      var aIsElement = a instanceof Element;
+      var bIsElement = b instanceof Element;
+      if (aIsElement && bIsElement) {
+        result = a.outerHTML == b.outerHTML;
+        if (!result) {
+          diffBuilder.record(a, b);
+        }
+        return result;
+      }
+      if (aIsElement || bIsElement) {
+        diffBuilder.record(a, b);
+        return false;
+      }
+      result = a.innerText == b.innerText && a.textContent == b.textContent;
+      if (!result) {
+        diffBuilder.record(a, b);
+      }
+      return result;
+    }
+    if (aIsDomNode || bIsDomNode) {
+      diffBuilder.record(a, b);
+      return false;
+    }
+
+    var aIsPromise = j$.isPromise(a);
+    var bIsPromise = j$.isPromise(b);
+    if (aIsPromise && bIsPromise) {
+      return a === b;
+    }
+
+    // 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.
+    // Compare array lengths to determine if a deep comparison is necessary.
+    if (className == '[object Array]') {
+      var aLength = a.length;
+      var bLength = b.length;
+
+      diffBuilder.withPath('length', function() {
+        if (aLength !== bLength) {
+          diffBuilder.record(aLength, bLength);
+          result = false;
+        }
+      });
+
+      for (i = 0; i < aLength || i < bLength; i++) {
+        diffBuilder.withPath(i, function() {
+          result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
+        });
+      }
+      if (!result) {
+        return false;
+      }
+    } else if (j$.isMap(a) && j$.isMap(b)) {
+      if (a.size != b.size) {
+        diffBuilder.record(a, b);
+        return false;
+      }
+
+      var keysA = [];
+      var keysB = [];
+      a.forEach( function( valueA, keyA ) {
+        keysA.push( keyA );
+      });
+      b.forEach( function( valueB, keyB ) {
+        keysB.push( keyB );
+      });
+
+      // For both sets of keys, check they map to equal values in both maps.
+      // Keep track of corresponding keys (in insertion order) in order to handle asymmetric obj keys.
+      var mapKeys = [keysA, keysB];
+      var cmpKeys = [keysB, keysA];
+      var mapIter, mapKey, mapValueA, mapValueB;
+      var cmpIter, cmpKey;
+      for (i = 0; result && i < mapKeys.length; i++) {
+        mapIter = mapKeys[i];
+        cmpIter = cmpKeys[i];
+
+        for (var j = 0; result && j < mapIter.length; j++) {
+          mapKey = mapIter[j];
+          cmpKey = cmpIter[j];
+          mapValueA = a.get(mapKey);
+
+          // Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches,
+          // otherwise explicitly look up the mapKey in the other Map since we want keys with unique
+          // obj identity (that are otherwise equal) to not match.
+          if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) &&
+              eq(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
+            mapValueB = b.get(cmpKey);
+          } else {
+            mapValueB = b.get(mapKey);
+          }
+          result = eq(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
+        }
+      }
+
+      if (!result) {
+        diffBuilder.record(a, b);
+        return false;
+      }
+    } else if (j$.isSet(a) && j$.isSet(b)) {
+      if (a.size != b.size) {
+        diffBuilder.record(a, b);
+        return false;
+      }
+
+      var valuesA = [];
+      a.forEach( function( valueA ) {
+        valuesA.push( valueA );
+      });
+      var valuesB = [];
+      b.forEach( function( valueB ) {
+        valuesB.push( valueB );
+      });
+
+      // For both sets, check they are all contained in the other set
+      var setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
+      var stackPairs = [[aStack, bStack], [bStack, aStack]];
+      var baseValues, baseValue, baseStack;
+      var otherValues, otherValue, otherStack;
+      var found;
+      var prevStackSize;
+      for (i = 0; result && i < setPairs.length; i++) {
+        baseValues = setPairs[i][0];
+        otherValues = setPairs[i][1];
+        baseStack = stackPairs[i][0];
+        otherStack = stackPairs[i][1];
+        // For each value in the base set...
+        for (var k = 0; result && k < baseValues.length; k++) {
+          baseValue = baseValues[k];
+          found = false;
+          // ... test that it is present in the other set
+          for (var l = 0; !found && l < otherValues.length; l++) {
+            otherValue = otherValues[l];
+            prevStackSize = baseStack.length;
+            // compare by value equality
+            found = eq(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
+            if (!found && prevStackSize !== baseStack.length) {
+              baseStack.splice(prevStackSize);
+              otherStack.splice(prevStackSize);
+            }
+          }
+          result = result && found;
+        }
+      }
+
+      if (!result) {
+        diffBuilder.record(a, b);
+        return false;
+      }
+    } else {
+
+      // Objects with different constructors are not equivalent, but `Object`s
+      // or `Array`s from different frames are.
+      var aCtor = a.constructor, bCtor = b.constructor;
+      if (aCtor !== bCtor &&
+          isFunction(aCtor) && isFunction(bCtor) &&
+          a instanceof aCtor && b instanceof bCtor &&
+          !(aCtor instanceof aCtor && bCtor instanceof bCtor)) {
+
+        diffBuilder.record(a, b, constructorsAreDifferentFormatter);
+        return false;
+      }
+    }
+
+    // Deep compare objects.
+    var aKeys = keys(a, className == '[object Array]'), key;
+    size = aKeys.length;
+
+    // Ensure that both objects contain the same number of properties before comparing deep equality.
+    if (keys(b, className == '[object Array]').length !== size) {
+      diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
+      return false;
+    }
+
+    for (i = 0; i < size; i++) {
+      key = aKeys[i];
+      // Deep compare each member
+      if (!j$.util.has(b, key)) {
+        diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
+        result = false;
+        continue;
+      }
+
+      diffBuilder.withPath(key, function() {
+        if(!eq(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
+          result = false;
+        }
+      });
+    }
+
+    if (!result) {
+      return false;
+    }
+
+    // Remove the first object from the stack of traversed objects.
+    aStack.pop();
+    bStack.pop();
+
+    return result;
+  }
+
+  function keys(obj, isArray) {
+    var allKeys = Object.keys ? Object.keys(obj) :
+      (function(o) {
+          var keys = [];
+          for (var key in o) {
+              if (j$.util.has(o, key)) {
+                  keys.push(key);
+              }
+          }
+          return keys;
+      })(obj);
+
+    if (!isArray) {
+      return allKeys;
+    }
+
+    if (allKeys.length === 0) {
+        return allKeys;
+    }
+
+    var extraKeys = [];
+    for (var i = 0; i < allKeys.length; i++) {
+      if (!/^[0-9]+$/.test(allKeys[i])) {
+        extraKeys.push(allKeys[i]);
+      }
+    }
+
+    return extraKeys;
+  }
+
+  function has(obj, key) {
+    return Object.prototype.hasOwnProperty.call(obj, key);
+  }
+
+  function isFunction(obj) {
+    return typeof obj === 'function';
+  }
+
+  function objectKeysAreDifferentFormatter(actual, expected, path) {
+    var missingProperties = j$.util.objectDifference(expected, actual),
+        extraProperties = j$.util.objectDifference(actual, expected),
+        missingPropertiesMessage = formatKeyValuePairs(missingProperties),
+        extraPropertiesMessage = formatKeyValuePairs(extraProperties),
+        messages = [];
+
+    if (!path.depth()) {
+      path = 'object';
+    }
+
+    if (missingPropertiesMessage.length) {
+      messages.push('Expected ' + path + ' to have properties' + missingPropertiesMessage);
+    }
+
+    if (extraPropertiesMessage.length) {
+      messages.push('Expected ' + path + ' not to have properties' + extraPropertiesMessage);
+    }
+
+    return messages.join('\n');
+  }
+
+  function constructorsAreDifferentFormatter(actual, expected, path) {
+    if (!path.depth()) {
+      path = 'object';
+    }
+
+    return 'Expected ' +
+      path + ' to be a kind of ' +
+      j$.fnNameFor(expected.constructor) +
+      ', but was ' + j$.pp(actual) + '.';
+  }
+
+  function formatKeyValuePairs(obj) {
+    var formatted = '';
+    for (var key in obj) {
+      formatted += '\n    ' + key + ': ' + j$.pp(obj[key]);
+    }
+    return formatted;
+  }
+};
+
+getJasmineRequireObj().nothing = function() {
+  /**
+   * {@link expect} nothing explicitly.
+   * @function
+   * @name matchers#nothing
+   * @example
+   * expect().nothing();
+   */
+  function nothing() {
+    return {
+      compare: function() {
+        return {
+          pass: true
+        };
+      }
+    };
+  }
+
+  return nothing;
+};
+
+getJasmineRequireObj().NullDiffBuilder = function(j$) {
+  return function() {
+    return {
+      withPath: function(_, block) {
+        block();
+      },
+      record: function() {}
+    };
+  };
+};
+
+getJasmineRequireObj().ObjectPath = function(j$) {
+  function ObjectPath(components) {
+    this.components = components || [];
+  }
+
+  ObjectPath.prototype.toString = function() {
+    if (this.components.length) {
+      return '$' + map(this.components, formatPropertyAccess).join('');
+    } else {
+      return '';
+    }
+  };
+
+  ObjectPath.prototype.add = function(component) {
+    return new ObjectPath(this.components.concat([component]));
+  };
+
+  ObjectPath.prototype.depth = function() {
+    return this.components.length;
+  };
+
+  function formatPropertyAccess(prop) {
+    if (typeof prop === 'number') {
+      return '[' + prop + ']';
+    }
+
+    if (isValidIdentifier(prop)) {
+      return '.' + prop;
+    }
+
+    return '[\'' + prop + '\']';
+  }
+
+  function map(array, fn) {
+    var results = [];
+    for (var i = 0; i < array.length; i++) {
+      results.push(fn(array[i]));
+    }
+    return results;
+  }
+
+  function isValidIdentifier(string) {
+    return /^[A-Za-z\$_][A-Za-z0-9\$_]*$/.test(string);
+  }
+
+  return ObjectPath;
+};
+
+getJasmineRequireObj().toBe = function() {
+  /**
+   * {@link expect} the actual value to be `===` to the expected value.
+   * @function
+   * @name matchers#toBe
+   * @param {Object} expected - The expected value to compare against.
+   * @example
+   * expect(thing).toBe(realThing);
+   */
+  function toBe() {
+    return {
+      compare: function(actual, expected) {
+        return {
+          pass: actual === expected
+        };
+      }
+    };
+  }
+
+  return toBe;
+};
+
+getJasmineRequireObj().toBeCloseTo = function() {
+  /**
+   * {@link expect} the actual value to be within a specified precision of the expected value.
+   * @function
+   * @name matchers#toBeCloseTo
+   * @param {Object} expected - The expected value to compare against.
+   * @param {Number} [precision=2] - The number of decimal points to check.
+   * @example
+   * expect(number).toBeCloseTo(42.2, 3);
+   */
+  function toBeCloseTo() {
+    return {
+      compare: function(actual, expected, precision) {
+        if (precision !== 0) {
+          precision = precision || 2;
+        }
+
+        if (expected === null || actual === null) {
+          throw new Error('Cannot use toBeCloseTo with null. Arguments evaluated to: ' +
+            'expect(' + actual + ').toBeCloseTo(' + expected + ').'
+          );
+        }
+
+        var pow = Math.pow(10, precision + 1);
+        var delta = Math.abs(expected - actual);
+        var maxDelta = Math.pow(10, -precision) / 2;
+
+        return {
+          pass: Math.round(delta * pow) / pow <= maxDelta
+        };
+      }
+    };
+  }
+
+  return toBeCloseTo;
+};
+
+getJasmineRequireObj().toBeDefined = function() {
+  /**
+   * {@link expect} the actual value to be defined. (Not `undefined`)
+   * @function
+   * @name matchers#toBeDefined
+   * @example
+   * expect(result).toBeDefined();
+   */
+  function toBeDefined() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: (void 0 !== actual)
+        };
+      }
+    };
+  }
+
+  return toBeDefined;
+};
+
+getJasmineRequireObj().toBeFalsy = function() {
+  /**
+   * {@link expect} the actual value to be falsy
+   * @function
+   * @name matchers#toBeFalsy
+   * @example
+   * expect(result).toBeFalsy();
+   */
+  function toBeFalsy() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: !!!actual
+        };
+      }
+    };
+  }
+
+  return toBeFalsy;
+};
+
+getJasmineRequireObj().toBeGreaterThan = function() {
+  /**
+   * {@link expect} the actual value to be greater than the expected value.
+   * @function
+   * @name matchers#toBeGreaterThan
+   * @param {Number} expected - The value to compare against.
+   * @example
+   * expect(result).toBeGreaterThan(3);
+   */
+  function toBeGreaterThan() {
+    return {
+      compare: function(actual, expected) {
+        return {
+          pass: actual > expected
+        };
+      }
+    };
+  }
+
+  return toBeGreaterThan;
+};
+
+
+getJasmineRequireObj().toBeGreaterThanOrEqual = function() {
+  /**
+   * {@link expect} the actual value to be greater than or equal to the expected value.
+   * @function
+   * @name matchers#toBeGreaterThanOrEqual
+   * @param {Number} expected - The expected value to compare against.
+   * @example
+   * expect(result).toBeGreaterThanOrEqual(25);
+   */
+  function toBeGreaterThanOrEqual() {
+    return {
+      compare: function(actual, expected) {
+        return {
+          pass: actual >= expected
+        };
+      }
+    };
+  }
+
+  return toBeGreaterThanOrEqual;
+};
+
+getJasmineRequireObj().toBeLessThan = function() {
+  /**
+   * {@link expect} the actual value to be less than the expected value.
+   * @function
+   * @name matchers#toBeLessThan
+   * @param {Number} expected - The expected value to compare against.
+   * @example
+   * expect(result).toBeLessThan(0);
+   */
+  function toBeLessThan() {
+    return {
+
+      compare: function(actual, expected) {
+        return {
+          pass: actual < expected
+        };
+      }
+    };
+  }
+
+  return toBeLessThan;
+};
+
+getJasmineRequireObj().toBeLessThanOrEqual = function() {
+  /**
+   * {@link expect} the actual value to be less than or equal to the expected value.
+   * @function
+   * @name matchers#toBeLessThanOrEqual
+   * @param {Number} expected - The expected value to compare against.
+   * @example
+   * expect(result).toBeLessThanOrEqual(123);
+   */
+  function toBeLessThanOrEqual() {
+    return {
+
+      compare: function(actual, expected) {
+        return {
+          pass: actual <= expected
+        };
+      }
+    };
+  }
+
+  return toBeLessThanOrEqual;
+};
+
+getJasmineRequireObj().toBeNaN = function(j$) {
+  /**
+   * {@link expect} the actual value to be `NaN` (Not a Number).
+   * @function
+   * @name matchers#toBeNaN
+   * @example
+   * expect(thing).toBeNaN();
+   */
+  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 = function() { return 'Expected ' + j$.pp(actual) + ' to be NaN.'; };
+        }
+
+        return result;
+      }
+    };
+  }
+
+  return toBeNaN;
+};
+
+getJasmineRequireObj().toBeNegativeInfinity = function(j$) {
+  /**
+   * {@link expect} the actual value to be `-Infinity` (-infinity).
+   * @function
+   * @name matchers#toBeNegativeInfinity
+   * @example
+   * expect(thing).toBeNegativeInfinity();
+   */
+  function toBeNegativeInfinity() {
+    return {
+      compare: function(actual) {
+        var result = {
+          pass: (actual === Number.NEGATIVE_INFINITY)
+        };
+
+        if (result.pass) {
+          result.message = 'Expected actual to be -Infinity.';
+        } else {
+          result.message = function() { return 'Expected ' + j$.pp(actual) + ' not to be -Infinity.'; };
+        }
+
+        return result;
+      }
+    };
+  }
+
+  return toBeNegativeInfinity;
+};
+
+getJasmineRequireObj().toBeNull = function() {
+  /**
+   * {@link expect} the actual value to be `null`.
+   * @function
+   * @name matchers#toBeNull
+   * @example
+   * expect(result).toBeNull();
+   */
+  function toBeNull() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: actual === null
+        };
+      }
+    };
+  }
+
+  return toBeNull;
+};
+
+getJasmineRequireObj().toBePositiveInfinity = function(j$) {
+  /**
+   * {@link expect} the actual value to be `Infinity` (infinity).
+   * @function
+   * @name matchers#toBePositiveInfinity
+   * @example
+   * expect(thing).toBePositiveInfinity();
+   */
+  function toBePositiveInfinity() {
+    return {
+      compare: function(actual) {
+        var result = {
+          pass: (actual === Number.POSITIVE_INFINITY)
+        };
+
+        if (result.pass) {
+          result.message = 'Expected actual to be Infinity.';
+        } else {
+          result.message = function() { return 'Expected ' + j$.pp(actual) + ' not to be Infinity.'; };
+        }
+
+        return result;
+      }
+    };
+  }
+
+  return toBePositiveInfinity;
+};
+
+getJasmineRequireObj().toBeTruthy = function() {
+  /**
+   * {@link expect} the actual value to be truthy.
+   * @function
+   * @name matchers#toBeTruthy
+   * @example
+   * expect(thing).toBeTruthy();
+   */
+  function toBeTruthy() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: !!actual
+        };
+      }
+    };
+  }
+
+  return toBeTruthy;
+};
+
+getJasmineRequireObj().toBeUndefined = function() {
+  /**
+   * {@link expect} the actual value to be `undefined`.
+   * @function
+   * @name matchers#toBeUndefined
+   * @example
+   * expect(result).toBeUndefined():
+   */
+  function toBeUndefined() {
+    return {
+      compare: function(actual) {
+        return {
+          pass: void 0 === actual
+        };
+      }
+    };
+  }
+
+  return toBeUndefined;
+};
+
+getJasmineRequireObj().toContain = function() {
+  /**
+   * {@link expect} the actual value to contain a specific value.
+   * @function
+   * @name matchers#toContain
+   * @param {Object} expected - The value to look for.
+   * @example
+   * expect(array).toContain(anElement);
+   * expect(string).toContain(substring);
+   */
+  function toContain(util, customEqualityTesters) {
+    customEqualityTesters = customEqualityTesters || [];
+
+    return {
+      compare: function(actual, expected) {
+
+        return {
+          pass: util.contains(actual, expected, customEqualityTesters)
+        };
+      }
+    };
+  }
+
+  return toContain;
+};
+
+getJasmineRequireObj().toEqual = function(j$) {
+  /**
+   * {@link expect} the actual value to be equal to the expected, using deep equality comparison.
+   * @function
+   * @name matchers#toEqual
+   * @param {Object} expected - Expected value
+   * @example
+   * expect(bigObject).toEqual({"foo": ['bar', 'baz']});
+   */
+  function toEqual(util, customEqualityTesters) {
+    customEqualityTesters = customEqualityTesters || [];
+
+    return {
+      compare: function(actual, expected) {
+        var result = {
+            pass: false
+          },
+          diffBuilder = j$.DiffBuilder();
+
+        result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder);
+
+        // TODO: only set error message if test fails
+        result.message = diffBuilder.getMessage();
+
+        return result;
+      }
+    };
+  }
+
+  return toEqual;
+};
+
+getJasmineRequireObj().toHaveBeenCalled = function(j$) {
+
+  var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalled>', 'expect(<spyObj>).toHaveBeenCalled()');
+
+  /**
+   * {@link expect} the actual (a {@link Spy}) to have been called.
+   * @function
+   * @name matchers#toHaveBeenCalled
+   * @example
+   * expect(mySpy).toHaveBeenCalled();
+   * expect(mySpy).not.toHaveBeenCalled();
+   */
+  function toHaveBeenCalled() {
+    return {
+      compare: function(actual) {
+        var result = {};
+
+        if (!j$.isSpy(actual)) {
+          throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
+        }
+
+        if (arguments.length > 1) {
+          throw new Error(getErrorMsg('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().toHaveBeenCalledBefore = function(j$) {
+
+  var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledBefore>', 'expect(<spyObj>).toHaveBeenCalledBefore(<spyObj>)');
+
+  /**
+   * {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}.
+   * @function
+   * @name matchers#toHaveBeenCalledBefore
+   * @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}.
+   * @example
+   * expect(mySpy).toHaveBeenCalledBefore(otherSpy);
+   */
+  function toHaveBeenCalledBefore() {
+    return {
+      compare: function(firstSpy, latterSpy) {
+        if (!j$.isSpy(firstSpy)) {
+          throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(firstSpy) + '.'));
+        }
+        if (!j$.isSpy(latterSpy)) {
+          throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(latterSpy) + '.'));
+        }
+
+        var result = { pass: false };
+
+        if (!firstSpy.calls.count()) {
+          result.message = 'Expected spy ' +  firstSpy.and.identity() + ' to have been called.';
+          return result;
+        }
+        if (!latterSpy.calls.count()) {
+          result.message = 'Expected spy ' +  latterSpy.and.identity() + ' to have been called.';
+          return result;
+        }
+
+        var latest1stSpyCall = firstSpy.calls.mostRecent().invocationOrder;
+        var first2ndSpyCall = latterSpy.calls.first().invocationOrder;
+
+        result.pass = latest1stSpyCall < first2ndSpyCall;
+
+        if (result.pass) {
+          result.message = 'Expected spy ' + firstSpy.and.identity() + ' to not have been called before spy ' + latterSpy.and.identity() + ', but it was';
+        } else {
+          var first1stSpyCall = firstSpy.calls.first().invocationOrder;
+          var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder;
+
+          if(first1stSpyCall < first2ndSpyCall) {
+            result.message = 'Expected latest call to spy ' + firstSpy.and.identity() + ' to have been called before first call to spy ' + latterSpy.and.identity() + ' (no interleaved calls)';
+          } else if (latest2ndSpyCall > latest1stSpyCall) {
+            result.message = 'Expected first call to spy ' + latterSpy.and.identity() + ' to have been called after latest call to spy ' + firstSpy.and.identity() + ' (no interleaved calls)';
+          } else {
+            result.message = 'Expected spy ' + firstSpy.and.identity() + ' to have been called before spy ' + latterSpy.and.identity();
+          }
+        }
+
+        return result;
+      }
+    };
+  }
+
+  return toHaveBeenCalledBefore;
+};
+
+getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
+
+  var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledTimes>', 'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)');
+
+  /**
+   * {@link expect} the actual (a {@link Spy}) to have been called the specified number of times.
+   * @function
+   * @name matchers#toHaveBeenCalledTimes
+   * @param {Number} expected - The number of invocations to look for.
+   * @example
+   * expect(mySpy).toHaveBeenCalledTimes(3);
+   */
+  function toHaveBeenCalledTimes() {
+    return {
+      compare: function(actual, expected) {
+        if (!j$.isSpy(actual)) {
+          throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
+        }
+
+        var args = Array.prototype.slice.call(arguments, 0),
+          result = { pass: false };
+
+        if (!j$.isNumber_(expected)){
+          throw new Error(getErrorMsg('The expected times failed is a required argument and must be a number.'));
+        }
+
+        actual = args[0];
+        var calls = actual.calls.count();
+        var timesMessage = expected === 1 ? 'once' : expected + ' times';
+        result.pass = calls === expected;
+        result.message = result.pass ?
+          'Expected spy ' + actual.and.identity() + ' not to have been called ' + timesMessage + '. It was called ' +  calls + ' times.' :
+          'Expected spy ' + actual.and.identity() + ' to have been called ' + timesMessage + '. It was called ' +  calls + ' times.';
+        return result;
+      }
+    };
+  }
+
+  return toHaveBeenCalledTimes;
+};
+
+getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
+
+  var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledWith>', 'expect(<spyObj>).toHaveBeenCalledWith(...arguments)');
+
+  /**
+   * {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once.
+   * @function
+   * @name matchers#toHaveBeenCalledWith
+   * @param {...Object} - The arguments to look for
+   * @example
+   * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
+   */
+  function toHaveBeenCalledWith(util, customEqualityTesters) {
+    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(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
+        }
+
+        if (!actual.calls.any()) {
+          result.message = function() { return '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, customEqualityTesters)) {
+          result.pass = true;
+          result.message = function() { return 'Expected spy ' + actual.and.identity() + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
+        } else {
+          result.message = function() { return '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(j$) {
+
+  var getErrorMsg = j$.formatErrorMsg('<toMatch>', 'expect(<expectation>).toMatch(<string> || <regexp>)');
+
+  /**
+   * {@link expect} the actual value to match a regular expression
+   * @function
+   * @name matchers#toMatch
+   * @param {RegExp|String} expected - Value to look for in the string.
+   * @example
+   * expect("my string").toMatch(/string$/);
+   * expect("other string").toMatch("her");
+   */
+  function toMatch() {
+    return {
+      compare: function(actual, expected) {
+        if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
+          throw new Error(getErrorMsg('Expected is not a String or a RegExp'));
+        }
+
+        var regexp = new RegExp(expected);
+
+        return {
+          pass: regexp.test(actual)
+        };
+      }
+    };
+  }
+
+  return toMatch;
+};
+
+getJasmineRequireObj().toThrow = function(j$) {
+
+  var getErrorMsg = j$.formatErrorMsg('<toThrow>', 'expect(function() {<expectation>}).toThrow()');
+
+  /**
+   * {@link expect} a function to `throw` something.
+   * @function
+   * @name matchers#toThrow
+   * @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked.
+   * @example
+   * expect(function() { return 'things'; }).toThrow('foo');
+   * expect(function() { return 'stuff'; }).toThrow();
+   */
+  function toThrow(util) {
+    return {
+      compare: function(actual, expected) {
+        var result = { pass: false },
+          threw = false,
+          thrown;
+
+        if (typeof actual != 'function') {
+          throw new Error(getErrorMsg('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 = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
+
+          return result;
+        }
+
+        if (util.equals(thrown, expected)) {
+          result.pass = true;
+          result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
+        } else {
+          result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' +  j$.pp(thrown) + '.'; };
+        }
+
+        return result;
+      }
+    };
+  }
+
+  return toThrow;
+};
+
+getJasmineRequireObj().toThrowError = function(j$) {
+
+  var getErrorMsg =  j$.formatErrorMsg('<toThrowError>', 'expect(function() {<expectation>}).toThrowError(<ErrorConstructor>, <message>)');
+
+  /**
+   * {@link expect} a function to `throw` an `Error`.
+   * @function
+   * @name matchers#toThrowError
+   * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used.
+   * @param {RegExp|String} [message] - The message that should be set on the thrown `Error`
+   * @example
+   * expect(function() { return 'things'; }).toThrowError(MyCustomError, 'message');
+   * expect(function() { return 'things'; }).toThrowError(MyCustomError, /bar/);
+   * expect(function() { return 'stuff'; }).toThrowError(MyCustomError);
+   * expect(function() { return 'other'; }).toThrowError(/foo/);
+   * expect(function() { return 'other'; }).toThrowError();
+   */
+  function toThrowError () {
+    return {
+      compare: function(actual) {
+        var threw = false,
+          pass = {pass: true},
+          fail = {pass: false},
+          thrown;
+
+        if (typeof actual != 'function') {
+          throw new Error(getErrorMsg('Actual is not a Function'));
+        }
+
+        var errorMatcher = getMatcher.apply(null, arguments);
+
+        try {
+          actual();
+        } catch (e) {
+          threw = true;
+          thrown = e;
+        }
+
+        if (!threw) {
+          fail.message = 'Expected function to throw an Error.';
+          return fail;
+        }
+
+        // Get Error constructor of thrown
+        if (!isErrorObject(thrown)) {
+          fail.message = function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; };
+          return fail;
+        }
+
+        if (errorMatcher.hasNoSpecifics()) {
+          pass.message = 'Expected function not to throw an Error, but it threw ' + j$.fnNameFor(thrown) + '.';
+          return pass;
+        }
+
+        if (errorMatcher.matches(thrown)) {
+          pass.message = function() {
+            return 'Expected function not to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + '.';
+          };
+          return pass;
+        } else {
+          fail.message = function() {
+            return 'Expected function to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() +
+              ', but it threw ' + errorMatcher.thrownDescription(thrown) + '.';
+          };
+          return fail;
+        }
+      }
+    };
+
+    function getMatcher() {
+      var expected = null,
+          errorType = null;
+
+      if (arguments.length == 2) {
+        expected = arguments[1];
+        if (isAnErrorType(expected)) {
+          errorType = expected;
+          expected = null;
+        }
+      } else if (arguments.length > 2) {
+        errorType = arguments[1];
+        expected = arguments[2];
+        if (!isAnErrorType(errorType)) {
+          throw new Error(getErrorMsg('Expected error type is not an Error.'));
+        }
+      }
+
+      if (expected && !isStringOrRegExp(expected)) {
+        if (errorType) {
+          throw new Error(getErrorMsg('Expected error message is not a string or RegExp.'));
+        } else {
+          throw new Error(getErrorMsg('Expected is not an Error, string, or RegExp.'));
+        }
+      }
+
+      function messageMatch(message) {
+        if (typeof expected == 'string') {
+          return expected == message;
+        } else {
+          return expected.test(message);
+        }
+      }
+
+      return {
+        errorTypeDescription: errorType ? j$.fnNameFor(errorType) : 'an exception',
+        thrownDescription: function(thrown) {
+          var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception',
+              thrownMessage = '';
+
+          if (expected) {
+            thrownMessage = ' with message ' + j$.pp(thrown.message);
+          }
+
+          return thrownName + thrownMessage;
+        },
+        messageDescription: function() {
+          if (expected === null) {
+            return '';
+          } else if (expected instanceof RegExp) {
+            return ' with a message matching ' + j$.pp(expected);
+          } else {
+            return ' with message ' + j$.pp(expected);
+          }
+        },
+        hasNoSpecifics: function() {
+          return expected === null && errorType === null;
+        },
+        matches: function(error) {
+          return (errorType === null || error instanceof errorType) &&
+            (expected === null || messageMatch(error.message));
+        }
+      };
+    }
+
+    function isStringOrRegExp(potential) {
+      return potential instanceof RegExp || (typeof potential == 'string');
+    }
+
+    function isAnErrorType(type) {
+      if (typeof type !== 'function') {
+        return false;
+      }
+
+      var Surrogate = function() {};
+      Surrogate.prototype = type.prototype;
+      return isErrorObject(new Surrogate());
+    }
+
+    function isErrorObject(thrown) {
+      if (thrown instanceof Error) {
+        return true;
+      }
+      if (thrown && thrown.constructor && thrown.constructor.constructor &&
+          (thrown instanceof (thrown.constructor.constructor('return this')()).Error)) {
+        return true;
+      }
+      return false;
+    }
+  }
+
+  return toThrowError;
+};
+
+getJasmineRequireObj().MockDate = function() {
+  function MockDate(global) {
+    var self = this;
+    var currentTime = 0;
+
+    if (!global || !global.Date) {
+      self.install = function() {};
+      self.tick = function() {};
+      self.uninstall = function() {};
+      return self;
+    }
+
+    var GlobalDate = global.Date;
+
+    self.install = function(mockDate) {
+      if (mockDate instanceof GlobalDate) {
+        currentTime = mockDate.getTime();
+      } else {
+        currentTime = new GlobalDate().getTime();
+      }
+
+      global.Date = FakeDate;
+    };
+
+    self.tick = function(millis) {
+      millis = millis || 0;
+      currentTime = currentTime + millis;
+    };
+
+    self.uninstall = function() {
+      currentTime = 0;
+      global.Date = GlobalDate;
+    };
+
+    createDateProperties();
+
+    return self;
+
+    function FakeDate() {
+      switch(arguments.length) {
+        case 0:
+          return new GlobalDate(currentTime);
+        case 1:
+          return new GlobalDate(arguments[0]);
+        case 2:
+          return new GlobalDate(arguments[0], arguments[1]);
+        case 3:
+          return new GlobalDate(arguments[0], arguments[1], arguments[2]);
+        case 4:
+          return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3]);
+        case 5:
+          return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
+                                arguments[4]);
+        case 6:
+          return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
+                                arguments[4], arguments[5]);
+        default:
+          return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
+                                arguments[4], arguments[5], arguments[6]);
+      }
+    }
+
+    function createDateProperties() {
+      FakeDate.prototype = GlobalDate.prototype;
+
+      FakeDate.now = function() {
+        if (GlobalDate.now) {
+          return currentTime;
+        } else {
+          throw new Error('Browser does not support Date.now()');
+        }
+      };
+
+      FakeDate.toSource = GlobalDate.toSource;
+      FakeDate.toString = GlobalDate.toString;
+      FakeDate.parse = GlobalDate.parse;
+      FakeDate.UTC = GlobalDate.UTC;
+    }
+	}
+
+  return MockDate;
+};
+
+getJasmineRequireObj().pp = function(j$) {
+
+  function PrettyPrinter() {
+    this.ppNestLevel_ = 0;
+    this.seen = [];
+    this.length = 0;
+    this.stringParts = [];
+  }
+
+  function hasCustomToString(value) {
+    // value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
+    // iframe, web worker)
+    return j$.isFunction_(value.toString) && value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
+  }
+
+  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 === 0 && 1/value === -Infinity) {
+        this.emitScalar('-0');
+      } 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 (j$.isSet(value)) {
+        this.emitSet(value);
+      } else if (j$.isMap(value)) {
+        this.emitMap(value);
+      } else if (j$.isTypedArray_(value)) {
+        this.emitTypedArray(value);
+      } else if (value.toString && typeof value === 'object' && !j$.isArray_(value) && hasCustomToString(value)) {
+        this.emitScalar(value.toString());
+      } else if (j$.util.arrayContains(this.seen, value)) {
+        this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
+      } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
+        this.seen.push(value);
+        if (j$.isArray_(value)) {
+          this.emitArray(value);
+        } else {
+          this.emitObject(value);
+        }
+        this.seen.pop();
+      } else {
+        this.emitScalar(value.toString());
+      }
+    } catch (e) {
+      if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
+        throw e;
+      }
+    } finally {
+      this.ppNestLevel_--;
+    }
+  };
+
+  PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+    var objKeys = keys(obj, j$.isArray_(obj));
+    var isGetter = function isGetter(prop) {};
+
+    if (obj.__lookupGetter__) {
+      isGetter = function isGetter(prop) {
+        var getter = obj.__lookupGetter__(prop);
+        return !j$.util.isUndefined(getter) && getter !== null;
+      };
+
+    }
+    var length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
+    for (var i = 0; i < length; i++) {
+      var property = objKeys[i];
+      fn(property, isGetter(property));
+    }
+
+    return objKeys.length > length;
+  };
+
+  PrettyPrinter.prototype.emitScalar = function(value) {
+    this.append(value);
+  };
+
+  PrettyPrinter.prototype.emitString = function(value) {
+    this.append('\'' + value + '\'');
+  };
+
+  PrettyPrinter.prototype.emitArray = function(array) {
+    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+      this.append('Array');
+      return;
+    }
+    var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
+    this.append('[ ');
+    for (var i = 0; i < length; i++) {
+      if (i > 0) {
+        this.append(', ');
+      }
+      this.format(array[i]);
+    }
+    if(array.length > length){
+      this.append(', ...');
+    }
+
+    var self = this;
+    var first = array.length === 0;
+    var truncated = this.iterateObject(array, function(property, isGetter) {
+      if (first) {
+        first = false;
+      } else {
+        self.append(', ');
+      }
+
+      self.formatProperty(array, property, isGetter);
+    });
+
+    if (truncated) { this.append(', ...'); }
+
+    this.append(' ]');
+  };
+
+  PrettyPrinter.prototype.emitSet = function(set) {
+    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+      this.append('Set');
+      return;
+    }
+    this.append('Set( ');
+    var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
+    var i = 0;
+    set.forEach( function( value, key ) {
+      if (i >= size) {
+        return;
+      }
+      if (i > 0) {
+        this.append(', ');
+      }
+      this.format(value);
+
+      i++;
+    }, this );
+    if (set.size > size){
+      this.append(', ...');
+    }
+    this.append(' )');
+  };
+
+  PrettyPrinter.prototype.emitMap = function(map) {
+    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+      this.append('Map');
+      return;
+    }
+    this.append('Map( ');
+    var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
+    var i = 0;
+    map.forEach( function( value, key ) {
+      if (i >= size) {
+        return;
+      }
+      if (i > 0) {
+        this.append(', ');
+      }
+      this.format([key,value]);
+
+      i++;
+    }, this );
+    if (map.size > size){
+      this.append(', ...');
+    }
+    this.append(' )');
+  };
+
+  PrettyPrinter.prototype.emitObject = function(obj) {
+    var ctor = obj.constructor,
+        constructorName;
+
+    constructorName = typeof ctor === 'function' && obj instanceof ctor ?
+      j$.fnNameFor(obj.constructor) :
+      'null';
+
+    this.append(constructorName);
+
+    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+      return;
+    }
+
+    var self = this;
+    this.append('({ ');
+    var first = true;
+
+    var truncated = this.iterateObject(obj, function(property, isGetter) {
+      if (first) {
+        first = false;
+      } else {
+        self.append(', ');
+      }
+
+      self.formatProperty(obj, property, isGetter);
+    });
+
+    if (truncated) { this.append(', ...'); }
+
+    this.append(' })');
+  };
+
+  PrettyPrinter.prototype.emitTypedArray = function(arr) {
+    var constructorName = j$.fnNameFor(arr.constructor),
+      limitedArray = Array.prototype.slice.call(arr, 0, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH),
+      itemsString = Array.prototype.join.call(limitedArray, ', ');
+
+    if (limitedArray.length !== arr.length) {
+      itemsString += ', ...';
+    }
+
+    this.append(constructorName + ' [ ' + itemsString + ' ]');
+  };
+
+  PrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
+      this.append(property);
+      this.append(': ');
+      if (isGetter) {
+        this.append('<getter>');
+      } else {
+        this.format(obj[property]);
+      }
+  };
+
+  PrettyPrinter.prototype.append = function(value) {
+    var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
+    this.length += result.value.length;
+    this.stringParts.push(result.value);
+
+    if (result.truncated) {
+      throw new MaxCharsReachedError();
+    }
+  };
+
+
+  function truncate(s, maxlen) {
+    if (s.length <= maxlen) {
+      return { value: s, truncated: false };
+    }
+
+    s = s.substring(0, maxlen - 4) + ' ...';
+    return { value: s, truncated: true };
+  }
+
+  function MaxCharsReachedError() {
+    this.message = 'Exceeded ' + j$.MAX_PRETTY_PRINT_CHARS +
+      ' characters while pretty-printing a value';
+  }
+
+  MaxCharsReachedError.prototype = new Error();
+
+  function keys(obj, isArray) {
+    var allKeys = Object.keys ? Object.keys(obj) :
+      (function(o) {
+          var keys = [];
+          for (var key in o) {
+              if (j$.util.has(o, key)) {
+                  keys.push(key);
+              }
+          }
+          return keys;
+      })(obj);
+
+    if (!isArray) {
+      return allKeys;
+    }
+
+    if (allKeys.length === 0) {
+        return allKeys;
+    }
+
+    var extraKeys = [];
+    for (var i = 0; i < allKeys.length; i++) {
+      if (!/^[0-9]+$/.test(allKeys[i])) {
+        extraKeys.push(allKeys[i]);
+      }
+    }
+
+    return extraKeys;
+  }
+  return function(value) {
+    var prettyPrinter = new PrettyPrinter();
+    prettyPrinter.format(value);
+    return prettyPrinter.stringParts.join('');
+  };
+};
+
+getJasmineRequireObj().QueueRunner = function(j$) {
+
+  function once(fn) {
+    var called = false;
+    return function() {
+      if (!called) {
+        called = true;
+        fn.apply(null, arguments);
+      }
+      return null;
+    };
+  }
+
+  function QueueRunner(attrs) {
+    var queueableFns = attrs.queueableFns || [];
+    this.queueableFns = queueableFns.concat(attrs.cleanupFns || []);
+    this.firstCleanupIx = queueableFns.length;
+    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 = attrs.userContext || new j$.UserContext();
+    this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
+    this.fail = attrs.fail || function() {};
+    this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
+    this.completeOnFirstError = !!attrs.completeOnFirstError;
+    this.deprecated = attrs.deprecated;
+  }
+
+  QueueRunner.prototype.execute = function() {
+    var self = this;
+    this.handleFinalError = function(error) {
+      self.onException(error);
+    };
+    this.globalErrors.pushListener(this.handleFinalError);
+    this.run(0);
+  };
+
+  QueueRunner.prototype.skipToCleanup = function(lastRanIndex) {
+    if (lastRanIndex < this.firstCleanupIx) {
+      this.run(this.firstCleanupIx);
+    } else {
+      this.run(lastRanIndex + 1);
+    }
+  };
+
+  QueueRunner.prototype.run = function(recursiveIndex) {
+    var length = this.queueableFns.length,
+      self = this,
+      iterativeIndex;
+
+
+    for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
+      var result = attempt(iterativeIndex);
+
+      if (!result.completedSynchronously) {
+        return;
+      }
+
+      if (this.completeOnFirstError && result.errored) {
+        this.skipToCleanup(iterativeIndex);
+        return;
+      }
+    }
+
+    this.clearStack(function() {
+      self.globalErrors.popListener(self.handleFinalError);
+      self.onComplete();
+    });
+
+    function attempt() {
+      var clearTimeout = function () {
+          Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
+        },
+        setTimeout = function(delayedFn, delay) {
+          return Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [delayedFn, delay]]);
+        },
+        completedSynchronously = true,
+        handleError = function(error) {
+          onException(error);
+          next();
+        },
+        cleanup = once(function() {
+          clearTimeout(timeoutId);
+          self.globalErrors.popListener(handleError);
+        }),
+        next = once(function (err) {
+          cleanup();
+
+          if (err instanceof Error) {
+            self.deprecated('done callback received an Error object. Jasmine 3.0 will treat this as a failure');
+          }
+
+          function runNext() {
+            if (self.completeOnFirstError && errored) {
+              self.skipToCleanup(iterativeIndex);
+            } else {
+              self.run(iterativeIndex + 1);
+            }
+          }
+
+          if (completedSynchronously) {
+            setTimeout(runNext);
+          } else {
+            runNext();
+          }
+        }),
+        errored = false,
+        queueableFn = self.queueableFns[iterativeIndex],
+        timeoutId;
+
+      next.fail = function() {
+        self.fail.apply(null, arguments);
+        errored = true;
+        next();
+      };
+
+      self.globalErrors.pushListener(handleError);
+
+      if (queueableFn.timeout) {
+        timeoutId = setTimeout(function() {
+          var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
+          onException(error);
+          next();
+        }, queueableFn.timeout());
+      }
+
+      try {
+        if (queueableFn.fn.length === 0) {
+          var maybeThenable = queueableFn.fn.call(self.userContext);
+
+          if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
+            maybeThenable.then(next, onPromiseRejection);
+            completedSynchronously = false;
+            return { completedSynchronously: false };
+          }
+        } else {
+          queueableFn.fn.call(self.userContext, next);
+          completedSynchronously = false;
+          return { completedSynchronously: false };
+        }
+      } catch (e) {
+        handleException(e, queueableFn);
+        errored = true;
+      }
+
+      cleanup();
+      return { completedSynchronously: true, errored: errored };
+
+      function onException(e) {
+        self.onException(e);
+        errored = true;
+      }
+
+      function onPromiseRejection(e) {
+        onException(e);
+        next();
+      }
+
+      function handleException(e, queueableFn) {
+        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(j$) {
+  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 = [];
+    var fallbackReporter = null;
+
+    this.addReporter = function(reporter) {
+      reporters.push(reporter);
+    };
+
+    this.provideFallbackReporter = function(reporter) {
+      fallbackReporter = reporter;
+    };
+
+    this.clearReporters = function() {
+      reporters = [];
+    };
+
+    return this;
+
+    function dispatch(method, args) {
+      if (reporters.length === 0 && fallbackReporter !== null) {
+          reporters.push(fallbackReporter);
+      }
+      for (var i = 0; i < reporters.length; i++) {
+        var reporter = reporters[i];
+        if (reporter[method]) {
+          reporter[method].apply(reporter, j$.util.cloneArgs(args));
+        }
+      }
+    }
+  }
+
+  return ReportDispatcher;
+};
+
+
+getJasmineRequireObj().interface = function(jasmine, env) {
+  var jasmineInterface = {
+    /**
+     * Callback passed to parts of the Jasmine base interface.
+     *
+     * By default Jasmine assumes this function completes synchronously.
+     * If you have code that you need to test asynchronously, you can declare that you receive a `done` callback, return a Promise, or use the `async` keyword if it is supported in your environment.
+     * @callback implementationCallback
+     * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
+     * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
+     */
+
+    /**
+     * Create a group of specs (often called a suite).
+     *
+     * Calls to `describe` can be nested within other calls to compose your suite as a tree.
+     * @name describe
+     * @function
+     * @global
+     * @param {String} description Textual description of the group
+     * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
+     */
+    describe: function(description, specDefinitions) {
+      return env.describe(description, specDefinitions);
+    },
+
+    /**
+     * A temporarily disabled [`describe`]{@link describe}
+     *
+     * Specs within an `xdescribe` will be marked pending and not executed
+     * @name xdescribe
+     * @function
+     * @global
+     * @param {String} description Textual description of the group
+     * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
+     */
+    xdescribe: function(description, specDefinitions) {
+      return env.xdescribe(description, specDefinitions);
+    },
+
+    /**
+     * A focused [`describe`]{@link describe}
+     *
+     * If suites or specs are focused, only those that are focused will be executed
+     * @see fit
+     * @name fdescribe
+     * @function
+     * @global
+     * @param {String} description Textual description of the group
+     * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
+     */
+    fdescribe: function(description, specDefinitions) {
+      return env.fdescribe(description, specDefinitions);
+    },
+
+    /**
+     * Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code.
+     *
+     * A spec whose expectations all succeed will be passing and a spec with any failures will fail.
+     * @name it
+     * @function
+     * @global
+     * @param {String} description Textual description of what this spec is checking
+     * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`.
+     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
+     */
+    it: function() {
+      return env.it.apply(env, arguments);
+    },
+
+    /**
+     * A temporarily disabled [`it`]{@link it}
+     *
+     * The spec will report as `pending` and will not be executed.
+     * @name xit
+     * @function
+     * @global
+     * @param {String} description Textual description of what this spec is checking.
+     * @param {implementationCallback} [testFunction] Function that contains the code of your test. Will not be executed.
+     */
+    xit: function() {
+      return env.xit.apply(env, arguments);
+    },
+
+    /**
+     * A focused [`it`]{@link it}
+     *
+     * If suites or specs are focused, only those that are focused will be executed.
+     * @name fit
+     * @function
+     * @global
+     * @param {String} description Textual description of what this spec is checking.
+     * @param {implementationCallback} testFunction Function that contains the code of your test.
+     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
+     */
+    fit: function() {
+      return env.fit.apply(env, arguments);
+    },
+
+    /**
+     * Run some shared setup before each of the specs in the {@link describe} in which it is called.
+     * @name beforeEach
+     * @function
+     * @global
+     * @param {implementationCallback} [function] Function that contains the code to setup your specs.
+     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach.
+     */
+    beforeEach: function() {
+      return env.beforeEach.apply(env, arguments);
+    },
+
+    /**
+     * Run some shared teardown after each of the specs in the {@link describe} in which it is called.
+     * @name afterEach
+     * @function
+     * @global
+     * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
+     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach.
+     */
+    afterEach: function() {
+      return env.afterEach.apply(env, arguments);
+    },
+
+    /**
+     * Run some shared setup once before all of the specs in the {@link describe} are run.
+     *
+     * _Note:_ Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
+     * @name beforeAll
+     * @function
+     * @global
+     * @param {implementationCallback} [function] Function that contains the code to setup your specs.
+     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll.
+     */
+    beforeAll: function() {
+      return env.beforeAll.apply(env, arguments);
+    },
+
+    /**
+     * Run some shared teardown once after all of the specs in the {@link describe} are run.
+     *
+     * _Note:_ Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
+     * @name afterAll
+     * @function
+     * @global
+     * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
+     * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll.
+     */
+    afterAll: function() {
+      return env.afterAll.apply(env, arguments);
+    },
+
+    /**
+     * Create an expectation for a spec.
+     * @name expect
+     * @function
+     * @global
+     * @param {Object} actual - Actual computed value to test expectations against.
+     * @return {matchers}
+     */
+    expect: function(actual) {
+      return env.expect(actual);
+    },
+
+    /**
+     * Mark a spec as pending, expectation results will be ignored.
+     * @name pending
+     * @function
+     * @global
+     * @param {String} [message] - Reason the spec is pending.
+     */
+    pending: function() {
+      return env.pending.apply(env, arguments);
+    },
+
+    /**
+     * Explicitly mark a spec as failed.
+     * @name fail
+     * @function
+     * @global
+     * @param {String|Error} [error] - Reason for the failure.
+    */
+    fail: function() {
+      return env.fail.apply(env, arguments);
+    },
+
+    /**
+     * Install a spy onto an existing object.
+     * @name spyOn
+     * @function
+     * @global
+     * @param {Object} obj - The object upon which to install the {@link Spy}.
+     * @param {String} methodName - The name of the method to replace with a {@link Spy}.
+     * @returns {Spy}
+     */
+    spyOn: function(obj, methodName) {
+      return env.spyOn(obj, methodName);
+    },
+
+    /**
+     * Install a spy on a property installed with `Object.defineProperty` onto an existing object.
+     * @name spyOnProperty
+     * @function
+     * @global
+     * @param {Object} obj - The object upon which to install the {@link Spy}
+     * @param {String} propertyName - The name of the property to replace with a {@link Spy}.
+     * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on.
+     * @returns {Spy}
+     */
+    spyOnProperty: function(obj, methodName, accessType) {
+      return env.spyOnProperty(obj, methodName, accessType);
+    },
+
+    jsApiReporter: new jasmine.JsApiReporter({
+      timer: new jasmine.Timer()
+    }),
+
+    /**
+     * @namespace jasmine
+     */
+    jasmine: jasmine
+  };
+
+  /**
+   * Add a custom equality tester for the current scope of specs.
+   *
+   * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
+   * @name jasmine.addCustomEqualityTester
+   * @function
+   * @param {Function} tester - A function which takes two arguments to compare and returns a `true` or `false` comparison result if it knows how to compare them, and `undefined` otherwise.
+   * @see custom_equality
+   */
+  jasmine.addCustomEqualityTester = function(tester) {
+    env.addCustomEqualityTester(tester);
+  };
+
+  /**
+   * Add custom matchers for the current scope of specs.
+   *
+   * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
+   * @name jasmine.addMatchers
+   * @function
+   * @param {Object} matchers - Keys from this object will be the new matcher names.
+   * @see custom_matcher
+   */
+  jasmine.addMatchers = function(matchers) {
+    return env.addMatchers(matchers);
+  };
+
+  /**
+   * Get the currently booted mock {Clock} for this Jasmine environment.
+   * @name jasmine.clock
+   * @function
+   * @returns {Clock}
+   */
+  jasmine.clock = function() {
+    return env.clock;
+  };
+
+  return jasmineInterface;
+};
+
+getJasmineRequireObj().Spy = function (j$) {
+
+  var nextOrder = (function() {
+    var order = 0;
+
+    return function() {
+      return order++;
+    };
+  })();
+
+  /**
+   * _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj}
+   * @constructor
+   * @name Spy
+   */
+  function Spy(name, originalFn) {
+    var numArgs = (typeof originalFn === 'function' ? originalFn.length : 0),
+      wrapper = makeFunc(numArgs, function () {
+        return spy.apply(this, Array.prototype.slice.call(arguments));
+      }),
+      spyStrategy = new j$.SpyStrategy({
+        name: name,
+        fn: originalFn,
+        getSpy: function () {
+          return wrapper;
+        }
+      }),
+      callTracker = new j$.CallTracker(),
+      spy = function () {
+        /**
+         * @name Spy.callData
+         * @property {object} object - `this` context for the invocation.
+         * @property {number} invocationOrder - Order of the invocation.
+         * @property {Array} args - The arguments passed for this invocation.
+         */
+        var callData = {
+          object: this,
+          invocationOrder: nextOrder(),
+          args: Array.prototype.slice.apply(arguments)
+        };
+
+        callTracker.track(callData);
+        var returnValue = spyStrategy.exec.apply(this, arguments);
+        callData.returnValue = returnValue;
+
+        return returnValue;
+      };
+
+    function makeFunc(length, fn) {
+      switch (length) {
+        case 1 : return function (a) { return fn.apply(this, arguments); };
+        case 2 : return function (a,b) { return fn.apply(this, arguments); };
+        case 3 : return function (a,b,c) { return fn.apply(this, arguments); };
+        case 4 : return function (a,b,c,d) { return fn.apply(this, arguments); };
+        case 5 : return function (a,b,c,d,e) { return fn.apply(this, arguments); };
+        case 6 : return function (a,b,c,d,e,f) { return fn.apply(this, arguments); };
+        case 7 : return function (a,b,c,d,e,f,g) { return fn.apply(this, arguments); };
+        case 8 : return function (a,b,c,d,e,f,g,h) { return fn.apply(this, arguments); };
+        case 9 : return function (a,b,c,d,e,f,g,h,i) { return fn.apply(this, arguments); };
+        default : return function () { return fn.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');
+      }
+
+      wrapper[prop] = originalFn[prop];
+    }
+
+    wrapper.and = spyStrategy;
+    wrapper.calls = callTracker;
+
+    return wrapper;
+  }
+
+  return Spy;
+};
+
+getJasmineRequireObj().SpyRegistry = function(j$) {
+
+  var getErrorMsg = j$.formatErrorMsg('<spyOn>', 'spyOn(<object>, <methodName>)');
+
+  function SpyRegistry(options) {
+    options = options || {};
+    var global = options.global || j$.getGlobal();
+    var currentSpies = options.currentSpies || function() { return []; };
+
+    this.allowRespy = function(allow){
+      this.respy = allow;
+    };
+
+    this.spyOn = function(obj, methodName) {
+
+      if (j$.util.isUndefined(obj) || obj === null) {
+        throw new Error(getErrorMsg('could not find an object to spy upon for ' + methodName + '()'));
+      }
+
+      if (j$.util.isUndefined(methodName) || methodName === null) {
+        throw new Error(getErrorMsg('No method name supplied'));
+      }
+
+      if (j$.util.isUndefined(obj[methodName])) {
+        throw new Error(getErrorMsg(methodName + '() method does not exist'));
+      }
+
+      if (obj[methodName] && j$.isSpy(obj[methodName])  ) {
+        if ( !!this.respy ){
+          return obj[methodName];
+        }else {
+          throw new Error(getErrorMsg(methodName + ' has already been spied upon'));
+        }
+      }
+
+      var descriptor;
+      try {
+        descriptor = Object.getOwnPropertyDescriptor(obj, methodName);
+      } catch(e) {
+        // IE 8 doesn't support `definePropery` on non-DOM nodes
+      }
+
+      if (descriptor && !(descriptor.writable || descriptor.set)) {
+        throw new Error(getErrorMsg(methodName + ' is not declared writable or has no setter'));
+      }
+
+      var originalMethod = obj[methodName],
+        spiedMethod = j$.createSpy(methodName, originalMethod),
+        restoreStrategy;
+
+      if (Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror')) {
+        restoreStrategy = function() {
+          obj[methodName] = originalMethod;
+        };
+      } else {
+        restoreStrategy = function() {
+          if (!delete obj[methodName]) {
+            obj[methodName] = originalMethod;
+          }
+        };
+      }
+
+      currentSpies().push({
+        restoreObjectToOriginalState: restoreStrategy
+      });
+
+      obj[methodName] = spiedMethod;
+
+      return spiedMethod;
+    };
+
+    this.spyOnProperty = function (obj, propertyName, accessType) {
+      accessType = accessType || 'get';
+
+      if (j$.util.isUndefined(obj)) {
+        throw new Error('spyOn could not find an object to spy upon for ' + propertyName + '');
+      }
+
+      if (j$.util.isUndefined(propertyName)) {
+        throw new Error('No property name supplied');
+      }
+
+      var descriptor;
+      try {
+        descriptor = j$.util.getPropertyDescriptor(obj, propertyName);
+      } catch(e) {
+        // IE 8 doesn't support `definePropery` on non-DOM nodes
+      }
+
+      if (!descriptor) {
+        throw new Error(propertyName + ' property does not exist');
+      }
+
+      if (!descriptor.configurable) {
+        throw new Error(propertyName + ' is not declared configurable');
+      }
+
+      if(!descriptor[accessType]) {
+        throw new Error('Property ' + propertyName + ' does not have access type ' + accessType);
+      }
+
+      if (j$.isSpy(descriptor[accessType])) {
+        //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
+        throw new Error(propertyName + ' has already been spied upon');
+      }
+
+      var originalDescriptor = j$.util.clone(descriptor),
+        spy = j$.createSpy(propertyName, descriptor[accessType]),
+        restoreStrategy;
+
+      if (Object.prototype.hasOwnProperty.call(obj, propertyName)) {
+        restoreStrategy = function() {
+          Object.defineProperty(obj, propertyName, originalDescriptor);
+        };
+      } else {
+        restoreStrategy = function() {
+          delete obj[propertyName];
+        };
+      }
+
+      currentSpies().push({
+        restoreObjectToOriginalState: restoreStrategy
+      });
+
+      descriptor[accessType] = spy;
+
+      Object.defineProperty(obj, propertyName, descriptor);
+
+      return spy;
+    };
+
+    this.clearSpies = function() {
+      var spies = currentSpies();
+      for (var i = spies.length - 1; i >= 0; i--) {
+        var spyEntry = spies[i];
+        spyEntry.restoreObjectToOriginalState();
+      }
+    };
+  }
+
+  return SpyRegistry;
+};
+
+getJasmineRequireObj().SpyStrategy = function(j$) {
+
+  /**
+   * @namespace Spy#and
+   */
+  function SpyStrategy(options) {
+    options = options || {};
+
+    var identity = options.name || 'unknown',
+        originalFn = options.fn || function() {},
+        getSpy = options.getSpy || function() {},
+        plan = function() {};
+
+    /**
+     * Return the identifying information for the spy.
+     * @name Spy#and#identity
+     * @function
+     * @returns {String}
+     */
+    this.identity = function() {
+      return identity;
+    };
+
+    /**
+     * Execute the current spy strategy.
+     * @name Spy#and#exec
+     * @function
+     */
+    this.exec = function() {
+      return plan.apply(this, arguments);
+    };
+
+    /**
+     * Tell the spy to call through to the real implementation when invoked.
+     * @name Spy#and#callThrough
+     * @function
+     */
+    this.callThrough = function() {
+      plan = originalFn;
+      return getSpy();
+    };
+
+    /**
+     * Tell the spy to return the value when invoked.
+     * @name Spy#and#returnValue
+     * @function
+     * @param {*} value The value to return.
+     */
+    this.returnValue = function(value) {
+      plan = function() {
+        return value;
+      };
+      return getSpy();
+    };
+
+    /**
+     * Tell the spy to return one of the specified values (sequentially) each time the spy is invoked.
+     * @name Spy#and#returnValues
+     * @function
+     * @param {...*} values - Values to be returned on subsequent calls to the spy.
+     */
+    this.returnValues = function() {
+      var values = Array.prototype.slice.call(arguments);
+      plan = function () {
+        return values.shift();
+      };
+      return getSpy();
+    };
+
+    /**
+     * Tell the spy to throw an error when invoked.
+     * @name Spy#and#throwError
+     * @function
+     * @param {Error|String} something Thing to throw
+     */
+    this.throwError = function(something) {
+      var error = (something instanceof Error) ? something : new Error(something);
+      plan = function() {
+        throw error;
+      };
+      return getSpy();
+    };
+
+    /**
+     * Tell the spy to call a fake implementation when invoked.
+     * @name Spy#and#callFake
+     * @function
+     * @param {Function} fn The function to invoke with the passed parameters.
+     */
+    this.callFake = function(fn) {
+      if(!(j$.isFunction_(fn) || j$.isAsyncFunction_(fn))) {
+        throw new Error('Argument passed to callFake should be a function, got ' + fn);
+      }
+      plan = fn;
+      return getSpy();
+    };
+
+    /**
+     * Tell the spy to do nothing when invoked. This is the default.
+     * @name Spy#and#stub
+     * @function
+     */
+    this.stub = function(fn) {
+      plan = function() {};
+      return getSpy();
+    };
+  }
+
+  return SpyStrategy;
+};
+
+getJasmineRequireObj().Suite = function(j$) {
+  function Suite(attrs) {
+    this.env = attrs.env;
+    this.id = attrs.id;
+    this.parentSuite = attrs.parentSuite;
+    this.description = attrs.description;
+    this.expectationFactory = attrs.expectationFactory;
+    this.expectationResultFactory = attrs.expectationResultFactory;
+    this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
+
+    this.beforeFns = [];
+    this.afterFns = [];
+    this.beforeAllFns = [];
+    this.afterAllFns = [];
+
+    this.children = [];
+
+    /**
+     * @typedef SuiteResult
+     * @property {Int} id - The unique id of this suite.
+     * @property {String} description - The description text passed to the {@link describe} that made this suite.
+     * @property {String} fullName - The full description including all ancestors of this suite.
+     * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
+     * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
+     * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
+     */
+    this.result = {
+      id: this.id,
+      description: this.description,
+      fullName: this.getFullName(),
+      failedExpectations: [],
+      deprecationWarnings: []
+    };
+  }
+
+  Suite.prototype.expect = function(actual) {
+    return this.expectationFactory(actual, this);
+  };
+
+  Suite.prototype.getFullName = function() {
+    var fullName = [];
+    for (var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite) {
+      if (parentSuite.parentSuite) {
+        fullName.unshift(parentSuite.description);
+      }
+    }
+    return fullName.join(' ');
+  };
+
+  Suite.prototype.pend = function() {
+    this.markedPending = true;
+  };
+
+  Suite.prototype.beforeEach = function(fn) {
+    this.beforeFns.unshift(fn);
+  };
+
+  Suite.prototype.beforeAll = function(fn) {
+    this.beforeAllFns.push(fn);
+  };
+
+  Suite.prototype.afterEach = function(fn) {
+    this.afterFns.unshift(fn);
+  };
+
+  Suite.prototype.afterAll = function(fn) {
+    this.afterAllFns.unshift(fn);
+  };
+
+  Suite.prototype.addChild = function(child) {
+    this.children.push(child);
+  };
+
+  Suite.prototype.status = function() {
+    if (this.markedPending) {
+      return 'pending';
+    }
+
+    if (this.result.failedExpectations.length > 0) {
+      return 'failed';
+    } else {
+      return 'finished';
+    }
+  };
+
+  Suite.prototype.isExecutable = function() {
+    return !this.markedPending;
+  };
+
+  Suite.prototype.canBeReentered = function() {
+    return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0;
+  };
+
+  Suite.prototype.getResult = function() {
+    this.result.status = this.status();
+    return this.result;
+  };
+
+  Suite.prototype.sharedUserContext = function() {
+    if (!this.sharedContext) {
+      this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext();
+    }
+
+    return this.sharedContext;
+  };
+
+  Suite.prototype.clonedSharedUserContext = function() {
+    return j$.UserContext.fromExisting(this.sharedUserContext());
+  };
+
+  Suite.prototype.onException = function() {
+    if (arguments[0] instanceof j$.errors.ExpectationFailed) {
+      return;
+    }
+
+    if(isAfterAll(this.children)) {
+      var data = {
+        matcherName: '',
+        passed: false,
+        expected: '',
+        actual: '',
+        error: arguments[0]
+      };
+      this.result.failedExpectations.push(this.expectationResultFactory(data));
+    } else {
+      for (var i = 0; i < this.children.length; i++) {
+        var child = this.children[i];
+        child.onException.apply(child, arguments);
+      }
+    }
+  };
+
+  Suite.prototype.addExpectationResult = function () {
+    if(isAfterAll(this.children) && isFailure(arguments)){
+      var data = arguments[1];
+      this.result.failedExpectations.push(this.expectationResultFactory(data));
+      if(this.throwOnExpectationFailure) {
+        throw new j$.errors.ExpectationFailed();
+      }
+    } else {
+      for (var i = 0; i < this.children.length; i++) {
+        var child = this.children[i];
+        try {
+          child.addExpectationResult.apply(child, arguments);
+        } catch(e) {
+          // keep going
+        }
+      }
+    }
+  };
+
+  Suite.prototype.addDeprecationWarning = function(msg) {
+    this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg }));
+  };
+
+  function isAfterAll(children) {
+    return children && children[0].result.status;
+  }
+
+  function isFailure(args) {
+    return !args[0];
+  }
+
+  return Suite;
+};
+
+if (typeof window == void 0 && typeof exports == 'object') {
+  exports.Suite = jasmineRequire.Suite;
+}
+
+getJasmineRequireObj().Timer = function() {
+  var defaultNow = (function(Date) {
+    return function() { return new Date().getTime(); };
+  })(Date);
+
+  function Timer(options) {
+    options = options || {};
+
+    var now = options.now || defaultNow,
+      startTime;
+
+    this.start = function() {
+      startTime = now();
+    };
+
+    this.elapsed = function() {
+      return now() - startTime;
+    };
+  }
+
+  return Timer;
+};
+
+getJasmineRequireObj().TreeProcessor = function() {
+  function TreeProcessor(attrs) {
+    var tree = attrs.tree,
+        runnableIds = attrs.runnableIds,
+        queueRunnerFactory = attrs.queueRunnerFactory,
+        nodeStart = attrs.nodeStart || function() {},
+        nodeComplete = attrs.nodeComplete || function() {},
+        orderChildren = attrs.orderChildren || function(node) { return node.children; },
+        stats = { valid: true },
+        processed = false,
+        defaultMin = Infinity,
+        defaultMax = 1 - Infinity;
+
+    this.processTree = function() {
+      processNode(tree, false);
+      processed = true;
+      return stats;
+    };
+
+    this.execute = function(done) {
+      if (!processed) {
+        this.processTree();
+      }
+
+      if (!stats.valid) {
+        throw 'invalid order';
+      }
+
+      var childFns = wrapChildren(tree, 0);
+
+      queueRunnerFactory({
+        queueableFns: childFns,
+        userContext: tree.sharedUserContext(),
+        onException: function() {
+          tree.onException.apply(tree, arguments);
+        },
+        onComplete: done
+      });
+    };
+
+    function runnableIndex(id) {
+      for (var i = 0; i < runnableIds.length; i++) {
+        if (runnableIds[i] === id) {
+          return i;
+        }
+      }
+    }
+
+    function processNode(node, parentEnabled) {
+      var executableIndex = runnableIndex(node.id);
+
+      if (executableIndex !== undefined) {
+        parentEnabled = true;
+      }
+
+      parentEnabled = parentEnabled && node.isExecutable();
+
+      if (!node.children) {
+        stats[node.id] = {
+          executable: parentEnabled && node.isExecutable(),
+          segments: [{
+            index: 0,
+            owner: node,
+            nodes: [node],
+            min: startingMin(executableIndex),
+            max: startingMax(executableIndex)
+          }]
+        };
+      } else {
+        var hasExecutableChild = false;
+
+        var orderedChildren = orderChildren(node);
+
+        for (var i = 0; i < orderedChildren.length; i++) {
+          var child = orderedChildren[i];
+
+          processNode(child, parentEnabled);
+
+          if (!stats.valid) {
+            return;
+          }
+
+          var childStats = stats[child.id];
+
+          hasExecutableChild = hasExecutableChild || childStats.executable;
+        }
+
+        stats[node.id] = {
+          executable: hasExecutableChild
+        };
+
+        segmentChildren(node, orderedChildren, stats[node.id], executableIndex);
+
+        if (!node.canBeReentered() && stats[node.id].segments.length > 1) {
+          stats = { valid: false };
+        }
+      }
+    }
+
+    function startingMin(executableIndex) {
+      return executableIndex === undefined ? defaultMin : executableIndex;
+    }
+
+    function startingMax(executableIndex) {
+      return executableIndex === undefined ? defaultMax : executableIndex;
+    }
+
+    function segmentChildren(node, orderedChildren, nodeStats, executableIndex) {
+      var currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) },
+          result = [currentSegment],
+          lastMax = defaultMax,
+          orderedChildSegments = orderChildSegments(orderedChildren);
+
+      function isSegmentBoundary(minIndex) {
+        return lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1;
+      }
+
+      for (var i = 0; i < orderedChildSegments.length; i++) {
+        var childSegment = orderedChildSegments[i],
+          maxIndex = childSegment.max,
+          minIndex = childSegment.min;
+
+        if (isSegmentBoundary(minIndex)) {
+          currentSegment = {index: result.length, owner: node, nodes: [], min: defaultMin, max: defaultMax};
+          result.push(currentSegment);
+        }
+
+        currentSegment.nodes.push(childSegment);
+        currentSegment.min = Math.min(currentSegment.min, minIndex);
+        currentSegment.max = Math.max(currentSegment.max, maxIndex);
+        lastMax = maxIndex;
+      }
+
+      nodeStats.segments = result;
+    }
+
+    function orderChildSegments(children) {
+      var specifiedOrder = [],
+          unspecifiedOrder = [];
+
+      for (var i = 0; i < children.length; i++) {
+        var child = children[i],
+            segments = stats[child.id].segments;
+
+        for (var j = 0; j < segments.length; j++) {
+          var seg = segments[j];
+
+          if (seg.min === defaultMin) {
+            unspecifiedOrder.push(seg);
+          } else {
+            specifiedOrder.push(seg);
+          }
+        }
+      }
+
+      specifiedOrder.sort(function(a, b) {
+        return a.min - b.min;
+      });
+
+      return specifiedOrder.concat(unspecifiedOrder);
+    }
+
+    function executeNode(node, segmentNumber) {
+      if (node.children) {
+        return {
+          fn: function(done) {
+            nodeStart(node);
+
+            queueRunnerFactory({
+              onComplete: function() {
+                nodeComplete(node, node.getResult());
+                done();
+              },
+              queueableFns: wrapChildren(node, segmentNumber),
+              userContext: node.sharedUserContext(),
+              onException: function() {
+                node.onException.apply(node, arguments);
+              }
+            });
+          }
+        };
+      } else {
+        return {
+          fn: function(done) { node.execute(done, stats[node.id].executable); }
+        };
+      }
+    }
+
+    function wrapChildren(node, segmentNumber) {
+      var result = [],
+          segmentChildren = stats[node.id].segments[segmentNumber].nodes;
+
+      for (var i = 0; i < segmentChildren.length; i++) {
+        result.push(executeNode(segmentChildren[i].owner, segmentChildren[i].index));
+      }
+
+      if (!stats[node.id].executable) {
+        return result;
+      }
+
+      return node.beforeAllFns.concat(result).concat(node.afterAllFns);
+    }
+  }
+
+  return TreeProcessor;
+};
+
+getJasmineRequireObj().UserContext = function(j$) {
+  function UserContext() {
+  }
+
+  UserContext.fromExisting = function(oldContext) {
+    var context = new UserContext();
+
+    for (var prop in oldContext) {
+      if (oldContext.hasOwnProperty(prop)) {
+        context[prop] = oldContext[prop];
+      }
+    }
+
+    return context;
+  };
+
+  return  UserContext;
+};
+
+getJasmineRequireObj().version = function() {
+  return '2.99.0';
+};
diff --git a/www/assets/jasmine-2.4.1/jasmine_favicon.png b/www/assets/jasmine-2.99.0/jasmine_favicon.png
old mode 100755
new mode 100644
similarity index 100%
rename from www/assets/jasmine-2.4.1/jasmine_favicon.png
rename to www/assets/jasmine-2.99.0/jasmine_favicon.png


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org