diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..7c5ee8ea
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,4 @@
+{
+ "cSpell.words": ["Btns", "postid", "uniqueid", "uuidv"],
+ "liveServer.settings.port": 5501
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..6bbd382e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2008-2019 Pivotal Labs
+Copyright (c) 2008-2023 The Jasmine developers
+
+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.
diff --git a/MyClasses.js b/MyClasses.js
new file mode 100644
index 00000000..a00f657f
--- /dev/null
+++ b/MyClasses.js
@@ -0,0 +1,143 @@
+
+export class SocialMedia {
+ #posts;
+ constructor() {
+ this.#posts = [];
+ }
+
+ setPost(postArray) {
+ this.#posts = postArray;
+ }
+
+ createPost(author, text) { return new Post(author, text) };
+
+ addPost(author, text){
+ const newPost = this.createPost(author, text);
+ this.#posts.push(newPost)
+ return newPost;
+ };
+
+ getPosts(){ return this.#posts };
+
+ getPost(id){
+ const post = this.#posts.find((post) => {
+ return post.getId() === id;
+ })
+ return post;
+ };
+
+ deletePost(id) {
+ const postToDelete = this.getPost(id);
+ const newPostArray = [];
+ this.#posts.forEach((post) => {
+ if (post !== postToDelete ) return newPostArray.push(post);
+ });
+ this.setPost(newPostArray);
+ };
+
+}
+
+export class Post {
+ #author;
+ #text;
+ #comments;
+ #id;
+ #likes;
+ constructor(author, text) {
+ this.#author = author;
+ this.#text = text;
+ this.#comments = [];
+ this.#likes = 0;
+ this.#id = new Date().getTime() + Math.random();
+ }
+
+ getId() {return this.#id};
+
+ getPost() {return `${this.#author}\n${this.#text}`};
+
+ getText() {return this.#text};
+
+ getAuthor() {return this.#author};
+
+ getComments() {return this.#comments};
+
+ getComment(id){
+ const comment = this.#comments.find((comment) => {
+ return comment.getId() === id;
+ })
+ return comment;
+ };
+
+ setComments(commentsArray) {
+ this.#comments = commentsArray;
+ }
+
+ getLikeCt() {return this.#likes};
+
+ deleteComment(id) {
+ const commentToDelete = this.getComment(id);
+ const newCommentArray = [];
+ this.#comments.forEach((comment) => {
+ if (comment !== commentToDelete ) return newCommentArray.push(comment);
+ });
+ this.setComments(newCommentArray);
+ }
+
+ likePost(type) {
+ let success = false;
+ switch (type) {
+ case "like":
+ this.#likes += 1;
+ success = true;
+ break;
+ case "dislike":
+ this.#likes -= 1;
+ success = true;
+ break;
+ }
+ if (success)console.log("Successfully liked comment");
+ return this;
+ };
+
+ createComment(author, text) {
+ return new Comment(author, text, this);
+ };
+
+ addComment(author, text){
+ const comment = this.createComment(author, text);
+ this.#comments.push(comment);
+ return comment;
+ };
+
+};
+
+export class Comment extends Post {
+ #author;
+ #text;
+ #parentPost;
+ #likes;
+ constructor(author, text, parentPost) {
+ super(author, text);
+ this.#author = author;
+ this.#text = text;
+ this.#likes = 0;
+ this.#parentPost = parentPost;
+ }
+
+ getParent() {return this.#parentPost};
+
+ createCommentReply(otherCommentAuthor, reply) {
+ const replyPrefix = `@${this.#author} `;
+
+ const replyText = replyPrefix + reply;
+ const newComment = this.#parentPost.addComment(otherCommentAuthor, replyText);
+
+ return newComment;
+ };
+}
+
+
+
+
+
+
diff --git a/README.md b/README.md
index 20395898..99cc8810 100644
--- a/README.md
+++ b/README.md
@@ -3,3 +3,55 @@
This project has been created by a student at Parsity, an online software engineering course. The work in this repository is wholly of the student based on a sample starter project that can be accessed by looking at the repository that this project forks.
If you have any questions about this project or the program in general, visit [parsity.io](https://parsity.io/) or email hello@parsity.io.
+
+## How to run
+
+To run this project please use a web server to run this.
+
+1. Download the Live Server Extension from VSCode
+
+2. Open index.html
+3. At the bottom of your page on the right, click the "Go live" button. Alternatively you can also right click and select "start live server" as well
+
+
+4. The app should open up in your most recent browser
+
+## What is it?
+
+A rendition of the popular social media website "reddit".
+
+### features include
+
+- View posts and comments
+ 
+- Comment on a posts
+ 
+- Reply to a comment (will append the '@[commentAuthor]' to the message)
+ 
+ 
+- Like/dislike Post (Like count will update on click)
+- Delete post (with confirmation page on click of delete button)
+- Delete comment (with confirmation page on click of delete button)
+
+### files overview
+
+- **index.html**: the main html page. The entrypoint of app.
+- **main.js**: houses the html manipulating logic.
+- **MyClasses.js**: houses the classes used for the app (SocialMedia, Post, Comment).
+- **style.css**: custom styles used for the app.
+- **SpecRunner.html**: entrypoint for testing suite (jasmine.js).
+- **spec/ReRedditSpec.js**: houses the tests for app.
+
+### technology used
+
+- plain old JS
+- Bootstrap v5
+- Jquery
+- uuidv4
+- Jasmine
+
+### how to run
+
+- run the "index.html"
+
+_A parsity project by Thanh_
diff --git a/SpecRunner.html b/SpecRunner.html
new file mode 100644
index 00000000..aa67a3f5
--- /dev/null
+++ b/SpecRunner.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
diff --git a/lib/jasmine-5.1.2/boot0.js b/lib/jasmine-5.1.2/boot0.js
new file mode 100644
index 00000000..d9afe769
--- /dev/null
+++ b/lib/jasmine-5.1.2/boot0.js
@@ -0,0 +1,65 @@
+/*
+Copyright (c) 2008-2019 Pivotal Labs
+Copyright (c) 2008-2024 The Jasmine developers
+
+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.
+*/
+/**
+ This file starts the process of "booting" Jasmine. It initializes Jasmine,
+ makes its globals available, and creates the env. This file should be loaded
+ after `jasmine.js` and `jasmine_html.js`, but before `boot1.js` or any project
+ source files or spec files are loaded.
+ */
+(function() {
+ const jasmineRequire = window.jasmineRequire || require('./jasmine.js');
+
+ /**
+ * ## Require & Instantiate
+ *
+ * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
+ */
+ const jasmine = jasmineRequire.core(jasmineRequire),
+ global = jasmine.getGlobal();
+ global.jasmine = jasmine;
+
+ /**
+ * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
+ */
+ jasmineRequire.html(jasmine);
+
+ /**
+ * Create the Jasmine environment. This is used to run all specs in a project.
+ */
+ const env = jasmine.getEnv();
+
+ /**
+ * ## The Global Interface
+ *
+ * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
+ */
+ const jasmineInterface = jasmineRequire.interface(jasmine, env);
+
+ /**
+ * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
+ */
+ for (const property in jasmineInterface) {
+ global[property] = jasmineInterface[property];
+ }
+})();
diff --git a/lib/jasmine-5.1.2/boot1.js b/lib/jasmine-5.1.2/boot1.js
new file mode 100644
index 00000000..33d105b7
--- /dev/null
+++ b/lib/jasmine-5.1.2/boot1.js
@@ -0,0 +1,133 @@
+/*
+Copyright (c) 2008-2019 Pivotal Labs
+Copyright (c) 2008-2024 The Jasmine developers
+
+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.
+*/
+/**
+ This file finishes 'booting' Jasmine, performing all of the necessary
+ initialization before executing the loaded environment and all of a project's
+ specs. This file should be loaded after `boot0.js` but before any project
+ source files or spec files are loaded. Thus this file can also be used to
+ customize Jasmine for a project.
+
+ If a project is using Jasmine via the standalone distribution, this file can
+ be customized directly. If you only wish to configure the Jasmine env, you
+ can load another file that calls `jasmine.getEnv().configure({...})`
+ after `boot0.js` is loaded and before this file is loaded.
+ */
+
+(function() {
+ const env = jasmine.getEnv();
+
+ /**
+ * ## Runner Parameters
+ *
+ * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
+ */
+
+ const queryString = new jasmine.QueryString({
+ getWindowLocation: function() {
+ return window.location;
+ }
+ });
+
+ const filterSpecs = !!queryString.getParam('spec');
+
+ const config = {
+ stopOnSpecFailure: queryString.getParam('stopOnSpecFailure'),
+ stopSpecOnExpectationFailure: queryString.getParam(
+ 'stopSpecOnExpectationFailure'
+ ),
+ hideDisabled: queryString.getParam('hideDisabled')
+ };
+
+ const random = queryString.getParam('random');
+
+ if (random !== undefined && random !== '') {
+ config.random = random;
+ }
+
+ const seed = queryString.getParam('seed');
+ if (seed) {
+ config.seed = seed;
+ }
+
+ /**
+ * ## Reporters
+ * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
+ */
+ const htmlReporter = new jasmine.HtmlReporter({
+ env: env,
+ navigateWithNewParam: function(key, value) {
+ return queryString.navigateWithNewParam(key, value);
+ },
+ addToExistingQueryString: function(key, value) {
+ return queryString.fullStringWithNewParam(key, value);
+ },
+ 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(),
+ filterSpecs: filterSpecs
+ });
+
+ /**
+ * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
+ */
+ env.addReporter(jsApiReporter);
+ env.addReporter(htmlReporter);
+
+ /**
+ * Filter which specs will be run by matching the start of the full name against the `spec` query param.
+ */
+ const specFilter = new jasmine.HtmlSpecFilter({
+ filterString: function() {
+ return queryString.getParam('spec');
+ }
+ });
+
+ config.specFilter = function(spec) {
+ return specFilter.matches(spec.getFullName());
+ };
+
+ env.configure(config);
+
+ /**
+ * ## Execution
+ *
+ * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
+ */
+ const currentWindowOnload = window.onload;
+
+ window.onload = function() {
+ if (currentWindowOnload) {
+ currentWindowOnload();
+ }
+ htmlReporter.initialize();
+ env.execute();
+ };
+})();
diff --git a/lib/jasmine-5.1.2/jasmine-html.js b/lib/jasmine-5.1.2/jasmine-html.js
new file mode 100644
index 00000000..0be90bff
--- /dev/null
+++ b/lib/jasmine-5.1.2/jasmine-html.js
@@ -0,0 +1,964 @@
+/*
+Copyright (c) 2008-2019 Pivotal Labs
+Copyright (c) 2008-2024 The Jasmine developers
+
+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.
+*/
+// eslint-disable-next-line no-var
+var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
+
+jasmineRequire.html = function(j$) {
+ j$.ResultsNode = jasmineRequire.ResultsNode();
+ j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
+ j$.QueryString = jasmineRequire.QueryString();
+ j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
+};
+
+jasmineRequire.HtmlReporter = function(j$) {
+ 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) {
+ this.currentParent.updateResult(result);
+ if (this.currentParent !== this.topResults) {
+ this.currentParent = this.currentParent.parent;
+ }
+
+ if (result.status === 'failed') {
+ this.failureCount++;
+ }
+ };
+
+ ResultsStateBuilder.prototype.specStarted = function(result) {};
+
+ ResultsStateBuilder.prototype.specDone = function(result) {
+ this.currentParent.addChild(result, 'spec');
+
+ if (result.status !== 'excluded') {
+ this.specsExecuted++;
+ }
+
+ if (result.status === 'failed') {
+ this.failureCount++;
+ }
+
+ if (result.status == 'pending') {
+ this.pendingSpecCount++;
+ }
+ };
+
+ ResultsStateBuilder.prototype.jasmineDone = function(result) {
+ if (result.failedExpectations) {
+ this.failureCount += result.failedExpectations.length;
+ }
+ };
+
+ function HtmlReporter(options) {
+ function config() {
+ return (options.env && options.env.configuration()) || {};
+ }
+
+ const getContainer = options.getContainer;
+ const createElement = options.createElement;
+ const createTextNode = options.createTextNode;
+ const navigateWithNewParam = options.navigateWithNewParam || function() {};
+ const addToExistingQueryString =
+ options.addToExistingQueryString || defaultQueryString;
+ const filterSpecs = options.filterSpecs;
+ let htmlReporterMain;
+ let symbols;
+ const deprecationWarnings = [];
+ const failures = [];
+
+ this.initialize = function() {
+ clearPrior();
+ htmlReporterMain = createDom(
+ 'div',
+ { className: 'jasmine_html-reporter' },
+ createDom(
+ 'div',
+ { className: 'jasmine-banner' },
+ createDom('a', {
+ className: 'jasmine-title',
+ href: 'http://jasmine.github.io/',
+ target: '_blank'
+ }),
+ createDom('span', { className: 'jasmine-version' }, j$.version)
+ ),
+ createDom('ul', { className: 'jasmine-symbol-summary' }),
+ createDom('div', { className: 'jasmine-alert' }),
+ createDom(
+ 'div',
+ { className: 'jasmine-results' },
+ createDom('div', { className: 'jasmine-failures' })
+ )
+ );
+ getContainer().appendChild(htmlReporterMain);
+ };
+
+ let totalSpecsDefined;
+ this.jasmineStarted = function(options) {
+ totalSpecsDefined = options.totalSpecsDefined || 0;
+ };
+
+ const summary = createDom('div', { className: 'jasmine-summary' });
+
+ const stateBuilder = new ResultsStateBuilder();
+
+ this.suiteStarted = function(result) {
+ stateBuilder.suiteStarted(result);
+ };
+
+ this.suiteDone = function(result) {
+ stateBuilder.suiteDone(result);
+
+ if (result.status === 'failed') {
+ failures.push(failureDom(result));
+ }
+ addDeprecationWarnings(result, 'suite');
+ };
+
+ this.specStarted = function(result) {
+ stateBuilder.specStarted(result);
+ };
+
+ this.specDone = function(result) {
+ stateBuilder.specDone(result);
+
+ if (noExpectations(result)) {
+ const noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
+ if (result.status === 'failed') {
+ console.error(noSpecMsg);
+ } else {
+ console.warn(noSpecMsg);
+ }
+ }
+
+ if (!symbols) {
+ symbols = find('.jasmine-symbol-summary');
+ }
+
+ symbols.appendChild(
+ createDom('li', {
+ className: this.displaySpecInCorrectFormat(result),
+ id: 'spec_' + result.id,
+ title: result.fullName
+ })
+ );
+
+ if (result.status === 'failed') {
+ failures.push(failureDom(result));
+ }
+
+ addDeprecationWarnings(result, 'spec');
+ };
+
+ this.displaySpecInCorrectFormat = function(result) {
+ return noExpectations(result) && result.status === 'passed'
+ ? 'jasmine-empty'
+ : this.resultStatus(result.status);
+ };
+
+ this.resultStatus = function(status) {
+ if (status === 'excluded') {
+ return config().hideDisabled
+ ? 'jasmine-excluded-no-display'
+ : 'jasmine-excluded';
+ }
+ return 'jasmine-' + status;
+ };
+
+ this.jasmineDone = function(doneResult) {
+ stateBuilder.jasmineDone(doneResult);
+ const banner = find('.jasmine-banner');
+ const alert = find('.jasmine-alert');
+ const order = doneResult && doneResult.order;
+
+ alert.appendChild(
+ createDom(
+ 'span',
+ { className: 'jasmine-duration' },
+ 'finished in ' + doneResult.totalTime / 1000 + 's'
+ )
+ );
+
+ banner.appendChild(optionsMenu(config()));
+
+ if (stateBuilder.specsExecuted < totalSpecsDefined) {
+ const skippedMessage =
+ 'Ran ' +
+ stateBuilder.specsExecuted +
+ ' of ' +
+ totalSpecsDefined +
+ ' specs - run all';
+ // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906
+ const skippedLink =
+ (window.location.pathname || '') +
+ addToExistingQueryString('spec', '');
+ alert.appendChild(
+ createDom(
+ 'span',
+ { className: 'jasmine-bar jasmine-skipped' },
+ createDom(
+ 'a',
+ { href: skippedLink, title: 'Run all specs' },
+ skippedMessage
+ )
+ )
+ );
+ }
+ let statusBarMessage = '';
+ let statusBarClassName = 'jasmine-overall-result jasmine-bar ';
+ const globalFailures =
+ (doneResult && doneResult.failedExpectations) || [];
+ const failed = stateBuilder.failureCount + globalFailures.length > 0;
+
+ if (totalSpecsDefined > 0 || failed) {
+ statusBarMessage +=
+ pluralize('spec', stateBuilder.specsExecuted) +
+ ', ' +
+ pluralize('failure', stateBuilder.failureCount);
+ if (stateBuilder.pendingSpecCount) {
+ statusBarMessage +=
+ ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount);
+ }
+ }
+
+ if (doneResult.overallStatus === 'passed') {
+ statusBarClassName += ' jasmine-passed ';
+ } else if (doneResult.overallStatus === 'incomplete') {
+ statusBarClassName += ' jasmine-incomplete ';
+ statusBarMessage =
+ 'Incomplete: ' +
+ doneResult.incompleteReason +
+ ', ' +
+ statusBarMessage;
+ } else {
+ statusBarClassName += ' jasmine-failed ';
+ }
+
+ let seedBar;
+ if (order && order.random) {
+ seedBar = createDom(
+ 'span',
+ { className: 'jasmine-seed-bar' },
+ ', randomized with seed ',
+ createDom(
+ 'a',
+ {
+ title: 'randomized with seed ' + order.seed,
+ href: seedHref(order.seed)
+ },
+ order.seed
+ )
+ );
+ }
+
+ alert.appendChild(
+ createDom(
+ 'span',
+ { className: statusBarClassName },
+ statusBarMessage,
+ seedBar
+ )
+ );
+
+ const errorBarClassName = 'jasmine-bar jasmine-errored';
+ const afterAllMessagePrefix = 'AfterAll ';
+
+ for (let i = 0; i < globalFailures.length; i++) {
+ alert.appendChild(
+ createDom(
+ 'span',
+ { className: errorBarClassName },
+ globalFailureMessage(globalFailures[i])
+ )
+ );
+ }
+
+ function globalFailureMessage(failure) {
+ if (failure.globalErrorType === 'load') {
+ const prefix = 'Error during loading: ' + failure.message;
+
+ if (failure.filename) {
+ return (
+ prefix + ' in ' + failure.filename + ' line ' + failure.lineno
+ );
+ } else {
+ return prefix;
+ }
+ } else if (failure.globalErrorType === 'afterAll') {
+ return afterAllMessagePrefix + failure.message;
+ } else {
+ return failure.message;
+ }
+ }
+
+ addDeprecationWarnings(doneResult);
+
+ for (let i = 0; i < deprecationWarnings.length; i++) {
+ const children = [];
+ let context;
+
+ switch (deprecationWarnings[i].runnableType) {
+ case 'spec':
+ context = '(in spec: ' + deprecationWarnings[i].runnableName + ')';
+ break;
+ case 'suite':
+ context = '(in suite: ' + deprecationWarnings[i].runnableName + ')';
+ break;
+ default:
+ context = '';
+ }
+
+ deprecationWarnings[i].message.split('\n').forEach(function(line) {
+ children.push(line);
+ children.push(createDom('br'));
+ });
+
+ children[0] = 'DEPRECATION: ' + children[0];
+ children.push(context);
+
+ if (deprecationWarnings[i].stack) {
+ children.push(createExpander(deprecationWarnings[i].stack));
+ }
+
+ alert.appendChild(
+ createDom(
+ 'span',
+ { className: 'jasmine-bar jasmine-warning' },
+ children
+ )
+ );
+ }
+
+ const results = find('.jasmine-results');
+ results.appendChild(summary);
+
+ summaryList(stateBuilder.topResults, summary);
+
+ if (failures.length) {
+ alert.appendChild(
+ createDom(
+ 'span',
+ { className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
+ createDom('span', {}, 'Spec List | '),
+ createDom(
+ 'a',
+ { className: 'jasmine-failures-menu', href: '#' },
+ 'Failures'
+ )
+ )
+ );
+ alert.appendChild(
+ createDom(
+ 'span',
+ { className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
+ createDom(
+ 'a',
+ { className: 'jasmine-spec-list-menu', href: '#' },
+ 'Spec List'
+ ),
+ createDom('span', {}, ' | Failures ')
+ )
+ );
+
+ find('.jasmine-failures-menu').onclick = function() {
+ setMenuModeTo('jasmine-failure-list');
+ return false;
+ };
+ find('.jasmine-spec-list-menu').onclick = function() {
+ setMenuModeTo('jasmine-spec-list');
+ return false;
+ };
+
+ setMenuModeTo('jasmine-failure-list');
+
+ const failureNode = find('.jasmine-failures');
+ for (let i = 0; i < failures.length; i++) {
+ failureNode.appendChild(failures[i]);
+ }
+ }
+ };
+
+ return this;
+
+ function failureDom(result) {
+ const failure = createDom(
+ 'div',
+ { className: 'jasmine-spec-detail jasmine-failed' },
+ failureDescription(result, stateBuilder.currentParent),
+ createDom('div', { className: 'jasmine-messages' })
+ );
+ const messages = failure.childNodes[1];
+
+ for (let i = 0; i < result.failedExpectations.length; i++) {
+ const expectation = result.failedExpectations[i];
+ messages.appendChild(
+ createDom(
+ 'div',
+ { className: 'jasmine-result-message' },
+ expectation.message
+ )
+ );
+ messages.appendChild(
+ createDom(
+ 'div',
+ { className: 'jasmine-stack-trace' },
+ expectation.stack
+ )
+ );
+ }
+
+ if (result.failedExpectations.length === 0) {
+ messages.appendChild(
+ createDom(
+ 'div',
+ { className: 'jasmine-result-message' },
+ 'Spec has no expectations'
+ )
+ );
+ }
+
+ if (result.debugLogs) {
+ messages.appendChild(debugLogTable(result.debugLogs));
+ }
+
+ return failure;
+ }
+
+ function debugLogTable(debugLogs) {
+ const tbody = createDom('tbody');
+
+ debugLogs.forEach(function(entry) {
+ tbody.appendChild(
+ createDom(
+ 'tr',
+ {},
+ createDom('td', {}, entry.timestamp.toString()),
+ createDom('td', {}, entry.message)
+ )
+ );
+ });
+
+ return createDom(
+ 'div',
+ { className: 'jasmine-debug-log' },
+ createDom(
+ 'div',
+ { className: 'jasmine-debug-log-header' },
+ 'Debug logs'
+ ),
+ createDom(
+ 'table',
+ {},
+ createDom(
+ 'thead',
+ {},
+ createDom(
+ 'tr',
+ {},
+ createDom('th', {}, 'Time (ms)'),
+ createDom('th', {}, 'Message')
+ )
+ ),
+ tbody
+ )
+ );
+ }
+
+ function summaryList(resultsTree, domParent) {
+ let specListNode;
+ for (let i = 0; i < resultsTree.children.length; i++) {
+ const resultNode = resultsTree.children[i];
+ if (filterSpecs && !hasActiveSpec(resultNode)) {
+ continue;
+ }
+ if (resultNode.type === 'suite') {
+ const suiteListNode = createDom(
+ 'ul',
+ { className: 'jasmine-suite', id: 'suite-' + resultNode.result.id },
+ createDom(
+ 'li',
+ {
+ className:
+ 'jasmine-suite-detail jasmine-' + resultNode.result.status
+ },
+ createDom(
+ 'a',
+ { href: specHref(resultNode.result) },
+ resultNode.result.description
+ )
+ )
+ );
+
+ summaryList(resultNode, suiteListNode);
+ domParent.appendChild(suiteListNode);
+ }
+ if (resultNode.type === 'spec') {
+ if (domParent.getAttribute('class') !== 'jasmine-specs') {
+ specListNode = createDom('ul', { className: 'jasmine-specs' });
+ domParent.appendChild(specListNode);
+ }
+ let specDescription = resultNode.result.description;
+ if (noExpectations(resultNode.result)) {
+ specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
+ }
+ if (resultNode.result.status === 'pending') {
+ if (resultNode.result.pendingReason !== '') {
+ specDescription +=
+ ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
+ } else {
+ specDescription += ' PENDING';
+ }
+ }
+ specListNode.appendChild(
+ createDom(
+ 'li',
+ {
+ className: 'jasmine-' + resultNode.result.status,
+ id: 'spec-' + resultNode.result.id
+ },
+ createDom(
+ 'a',
+ { href: specHref(resultNode.result) },
+ specDescription
+ )
+ )
+ );
+ }
+ }
+ }
+
+ function optionsMenu(config) {
+ const optionsMenuDom = createDom(
+ 'div',
+ { className: 'jasmine-run-options' },
+ createDom('span', { className: 'jasmine-trigger' }, 'Options'),
+ createDom(
+ 'div',
+ { className: 'jasmine-payload' },
+ createDom(
+ 'div',
+ { className: 'jasmine-stop-on-failure' },
+ createDom('input', {
+ className: 'jasmine-fail-fast',
+ id: 'jasmine-fail-fast',
+ type: 'checkbox'
+ }),
+ createDom(
+ 'label',
+ { className: 'jasmine-label', for: 'jasmine-fail-fast' },
+ 'stop execution on spec failure'
+ )
+ ),
+ createDom(
+ 'div',
+ { className: 'jasmine-throw-failures' },
+ createDom('input', {
+ className: 'jasmine-throw',
+ id: 'jasmine-throw-failures',
+ type: 'checkbox'
+ }),
+ createDom(
+ 'label',
+ { className: 'jasmine-label', for: 'jasmine-throw-failures' },
+ 'stop spec on expectation failure'
+ )
+ ),
+ createDom(
+ 'div',
+ { className: 'jasmine-random-order' },
+ createDom('input', {
+ className: 'jasmine-random',
+ id: 'jasmine-random-order',
+ type: 'checkbox'
+ }),
+ createDom(
+ 'label',
+ { className: 'jasmine-label', for: 'jasmine-random-order' },
+ 'run tests in random order'
+ )
+ ),
+ createDom(
+ 'div',
+ { className: 'jasmine-hide-disabled' },
+ createDom('input', {
+ className: 'jasmine-disabled',
+ id: 'jasmine-hide-disabled',
+ type: 'checkbox'
+ }),
+ createDom(
+ 'label',
+ { className: 'jasmine-label', for: 'jasmine-hide-disabled' },
+ 'hide disabled tests'
+ )
+ )
+ )
+ );
+
+ const failFastCheckbox = optionsMenuDom.querySelector(
+ '#jasmine-fail-fast'
+ );
+ failFastCheckbox.checked = config.stopOnSpecFailure;
+ failFastCheckbox.onclick = function() {
+ navigateWithNewParam('stopOnSpecFailure', !config.stopOnSpecFailure);
+ };
+
+ const throwCheckbox = optionsMenuDom.querySelector(
+ '#jasmine-throw-failures'
+ );
+ throwCheckbox.checked = config.stopSpecOnExpectationFailure;
+ throwCheckbox.onclick = function() {
+ navigateWithNewParam(
+ 'stopSpecOnExpectationFailure',
+ !config.stopSpecOnExpectationFailure
+ );
+ };
+
+ const randomCheckbox = optionsMenuDom.querySelector(
+ '#jasmine-random-order'
+ );
+ randomCheckbox.checked = config.random;
+ randomCheckbox.onclick = function() {
+ navigateWithNewParam('random', !config.random);
+ };
+
+ const hideDisabled = optionsMenuDom.querySelector(
+ '#jasmine-hide-disabled'
+ );
+ hideDisabled.checked = config.hideDisabled;
+ hideDisabled.onclick = function() {
+ navigateWithNewParam('hideDisabled', !config.hideDisabled);
+ };
+
+ const optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
+ optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
+ isOpen = /\bjasmine-open\b/;
+
+ optionsTrigger.onclick = function() {
+ if (isOpen.test(optionsPayload.className)) {
+ optionsPayload.className = optionsPayload.className.replace(
+ isOpen,
+ ''
+ );
+ } else {
+ optionsPayload.className += ' jasmine-open';
+ }
+ };
+
+ return optionsMenuDom;
+ }
+
+ function failureDescription(result, suite) {
+ const wrapper = createDom(
+ 'div',
+ { className: 'jasmine-description' },
+ createDom(
+ 'a',
+ { title: result.description, href: specHref(result) },
+ result.description
+ )
+ );
+ let suiteLink;
+
+ while (suite && suite.parent) {
+ wrapper.insertBefore(createTextNode(' > '), wrapper.firstChild);
+ suiteLink = createDom(
+ 'a',
+ { href: suiteHref(suite) },
+ suite.result.description
+ );
+ wrapper.insertBefore(suiteLink, wrapper.firstChild);
+
+ suite = suite.parent;
+ }
+
+ return wrapper;
+ }
+
+ function suiteHref(suite) {
+ const els = [];
+
+ while (suite && suite.parent) {
+ els.unshift(suite.result.description);
+ suite = suite.parent;
+ }
+
+ // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906
+ return (
+ (window.location.pathname || '') +
+ addToExistingQueryString('spec', els.join(' '))
+ );
+ }
+
+ function addDeprecationWarnings(result, runnableType) {
+ if (result && result.deprecationWarnings) {
+ for (let i = 0; i < result.deprecationWarnings.length; i++) {
+ const warning = result.deprecationWarnings[i].message;
+ deprecationWarnings.push({
+ message: warning,
+ stack: result.deprecationWarnings[i].stack,
+ runnableName: result.fullName,
+ runnableType: runnableType
+ });
+ }
+ }
+ }
+
+ function createExpander(stackTrace) {
+ const expandLink = createDom('a', { href: '#' }, 'Show stack trace');
+ const root = createDom(
+ 'div',
+ { className: 'jasmine-expander' },
+ expandLink,
+ createDom(
+ 'div',
+ { className: 'jasmine-expander-contents jasmine-stack-trace' },
+ stackTrace
+ )
+ );
+
+ expandLink.addEventListener('click', function(e) {
+ e.preventDefault();
+
+ if (root.classList.contains('jasmine-expanded')) {
+ root.classList.remove('jasmine-expanded');
+ expandLink.textContent = 'Show stack trace';
+ } else {
+ root.classList.add('jasmine-expanded');
+ expandLink.textContent = 'Hide stack trace';
+ }
+ });
+
+ return root;
+ }
+
+ function find(selector) {
+ return getContainer().querySelector('.jasmine_html-reporter ' + selector);
+ }
+
+ function clearPrior() {
+ const oldReporter = find('');
+
+ if (oldReporter) {
+ getContainer().removeChild(oldReporter);
+ }
+ }
+
+ function createDom(type, attrs, childrenArrayOrVarArgs) {
+ const el = createElement(type);
+ let children;
+
+ if (j$.isArray_(childrenArrayOrVarArgs)) {
+ children = childrenArrayOrVarArgs;
+ } else {
+ children = [];
+
+ for (let i = 2; i < arguments.length; i++) {
+ children.push(arguments[i]);
+ }
+ }
+
+ for (let i = 0; i < children.length; i++) {
+ const child = children[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (const attr in attrs) {
+ if (attr == 'className') {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+ }
+
+ function pluralize(singular, count) {
+ const word = count == 1 ? singular : singular + 's';
+
+ return '' + count + ' ' + word;
+ }
+
+ function specHref(result) {
+ // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906
+ return (
+ (window.location.pathname || '') +
+ addToExistingQueryString('spec', result.fullName)
+ );
+ }
+
+ function seedHref(seed) {
+ // include window.location.pathname to fix issue with karma-jasmine-html-reporter in angular: see https://github.com/jasmine/jasmine/issues/1906
+ return (
+ (window.location.pathname || '') +
+ addToExistingQueryString('seed', seed)
+ );
+ }
+
+ function defaultQueryString(key, value) {
+ return '?' + key + '=' + value;
+ }
+
+ function setMenuModeTo(mode) {
+ htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
+ }
+
+ function noExpectations(result) {
+ const allExpectations =
+ result.failedExpectations.length + result.passedExpectations.length;
+
+ return (
+ allExpectations === 0 &&
+ (result.status === 'passed' || result.status === 'failed')
+ );
+ }
+
+ function hasActiveSpec(resultNode) {
+ if (resultNode.type == 'spec' && resultNode.result.status != 'excluded') {
+ return true;
+ }
+
+ if (resultNode.type == 'suite') {
+ for (let i = 0, j = resultNode.children.length; i < j; i++) {
+ if (hasActiveSpec(resultNode.children[i])) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return HtmlReporter;
+};
+
+jasmineRequire.HtmlSpecFilter = function() {
+ function HtmlSpecFilter(options) {
+ const filterString =
+ options &&
+ options.filterString() &&
+ options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
+ const filterPattern = new RegExp(filterString);
+
+ this.matches = function(specName) {
+ return filterPattern.test(specName);
+ };
+ }
+
+ return HtmlSpecFilter;
+};
+
+jasmineRequire.ResultsNode = function() {
+ function ResultsNode(result, type, parent) {
+ this.result = result;
+ this.type = type;
+ this.parent = parent;
+
+ this.children = [];
+
+ this.addChild = function(result, type) {
+ this.children.push(new ResultsNode(result, type, this));
+ };
+
+ this.last = function() {
+ return this.children[this.children.length - 1];
+ };
+
+ this.updateResult = function(result) {
+ this.result = result;
+ };
+ }
+
+ return ResultsNode;
+};
+
+jasmineRequire.QueryString = function() {
+ function QueryString(options) {
+ this.navigateWithNewParam = function(key, value) {
+ options.getWindowLocation().search = this.fullStringWithNewParam(
+ key,
+ value
+ );
+ };
+
+ this.fullStringWithNewParam = function(key, value) {
+ const paramMap = queryStringToParamMap();
+ paramMap[key] = value;
+ return toQueryString(paramMap);
+ };
+
+ this.getParam = function(key) {
+ return queryStringToParamMap()[key];
+ };
+
+ return this;
+
+ function toQueryString(paramMap) {
+ const qStrPairs = [];
+ for (const prop in paramMap) {
+ qStrPairs.push(
+ encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop])
+ );
+ }
+ return '?' + qStrPairs.join('&');
+ }
+
+ function queryStringToParamMap() {
+ const paramStr = options.getWindowLocation().search.substring(1);
+ let params = [];
+ const paramMap = {};
+
+ if (paramStr.length > 0) {
+ params = paramStr.split('&');
+ for (let i = 0; i < params.length; i++) {
+ const p = params[i].split('=');
+ let value = decodeURIComponent(p[1]);
+ if (value === 'true' || value === 'false') {
+ value = JSON.parse(value);
+ }
+ paramMap[decodeURIComponent(p[0])] = value;
+ }
+ }
+
+ return paramMap;
+ }
+ }
+
+ return QueryString;
+};
diff --git a/lib/jasmine-5.1.2/jasmine.css b/lib/jasmine-5.1.2/jasmine.css
new file mode 100644
index 00000000..1f364464
--- /dev/null
+++ b/lib/jasmine-5.1.2/jasmine.css
@@ -0,0 +1,298 @@
+@charset "UTF-8";
+body {
+ overflow-y: scroll;
+}
+
+.jasmine_html-reporter {
+ width: 100%;
+ background-color: #eee;
+ padding: 5px;
+ margin: -8px;
+ font-size: 11px;
+ font-family: Monaco, "Lucida Console", monospace;
+ line-height: 14px;
+ color: #333;
+}
+.jasmine_html-reporter a {
+ text-decoration: none;
+}
+.jasmine_html-reporter a:hover {
+ text-decoration: underline;
+}
+.jasmine_html-reporter p, .jasmine_html-reporter h1, .jasmine_html-reporter h2, .jasmine_html-reporter h3, .jasmine_html-reporter h4, .jasmine_html-reporter h5, .jasmine_html-reporter h6 {
+ margin: 0;
+ line-height: 14px;
+}
+.jasmine_html-reporter .jasmine-banner,
+.jasmine_html-reporter .jasmine-symbol-summary,
+.jasmine_html-reporter .jasmine-summary,
+.jasmine_html-reporter .jasmine-result-message,
+.jasmine_html-reporter .jasmine-spec .jasmine-description,
+.jasmine_html-reporter .jasmine-spec-detail .jasmine-description,
+.jasmine_html-reporter .jasmine-alert .jasmine-bar,
+.jasmine_html-reporter .jasmine-stack-trace {
+ padding-left: 9px;
+ padding-right: 9px;
+}
+.jasmine_html-reporter .jasmine-banner {
+ position: relative;
+}
+.jasmine_html-reporter .jasmine-banner .jasmine-title {
+ background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAZCAMAAACGusnyAAACdlBMVEX/////AP+AgICqVaqAQICZM5mAVYCSSZKAQICOOY6ATYCLRouAQICJO4mSSYCIRIiPQICHPIeOR4CGQ4aMQICGPYaLRoCFQ4WKQICPPYWJRYCOQoSJQICNPoSIRICMQoSHQICHRICKQoOHQICKPoOJO4OJQYOMQICMQ4CIQYKLQICIPoKLQ4CKQICNPoKJQISMQ4KJQoSLQYKJQISLQ4KIQoSKQYKIQICIQISMQoSKQYKLQIOLQoOJQYGLQIOKQIOMQoGKQYOLQYGKQIOLQoGJQYOJQIOKQYGJQIOKQoGKQIGLQIKLQ4KKQoGLQYKJQIGKQYKJQIGKQIKJQoGKQYKLQIGKQYKLQIOJQoKKQoOJQYKKQIOJQoKKQoOKQIOLQoKKQYOLQYKJQIOKQoKKQYKKQoKJQYOKQYKLQIOKQoKLQYOKQYKLQIOJQoGKQYKJQYGJQoGKQYKLQoGLQYGKQoGJQYKKQYGJQIKKQoGJQYKLQIKKQYGLQYKKQYGKQYGKQYKJQYOKQoKJQYOKQYKLQYOLQYOKQYKLQYOKQoKKQYKKQYOKQYOJQYKKQYKLQYKKQIKKQoKKQYKKQYKKQoKJQIKKQYKLQYKKQYKKQIKKQYKKQYKKQYKKQIKKQYKJQYGLQYGKQYKKQYKKQYGKQIKKQYGKQYOJQoKKQYOLQYKKQYOKQoKKQYKKQoKKQYKKQYKJQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKJQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKmIDpEAAAA0XRSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAiIyQlJycoKissLS4wMTQ1Njc4OTo7PDw+P0BCQ0RISUpLTE1OUFNUVVdYWFlaW15fYGFiY2ZnaGlqa2xtb3BxcnN0dnh5ent8fX5/gIGChIWIioyNjo+QkZOUlZaYmZqbnJ2eoKGio6WmqKmsra6vsLGztre4ubq7vL2+wMHDxMjJysvNzs/Q0dLU1tfY2dvc3t/g4eLj5ebn6Onq6+zt7u/w8vP09fb3+Pn6+/z9/vkVQXAAAAMaSURBVHhe5dXxV1N1GMfxz2ABbDgIAm5VDJOyVDIJLUMaVpBWUZUaGbmqoGpZRSiGiRWp6KoZ5AB0ZY50RImZQIlahKkMYXv/R90dBvET/rJfOr3Ouc8v99zPec59zvf56j+vYKlViSf7250X4Mr3O29Tgq08BdGB4DhcekEJ5YkQKFsgWZdtj9JpV+I8xPjLFqkrsEIqO8PHSpis36jWazcqjEsfJjkvRssVU37SdIOu4XCf5vEJPsnwJpnRNU9JmxhMk8l1gehIrq7hTFjzOD+Vf88629qKMJVNltInFeRexRQyJlNeqd1iGDlSzrIUIyXbyFfm3RYprcQRe7lqtWyGYbfc6dT0R2vmdOOkX3u55C1rP37ftiH+tDby4r/RBT0w8TyEkr+epB9XgPDmSYYWbrhCuFYaIyw3fDQAXTnSkh+ANofiHmWf9l+FY1I90FdQTetstO00o23novzVsJ7uB3/C5TkbjRwZ5JerwV4iRWq9HFbFMaK/d0TYqayRiQPuIxxS3Bu8JWU90/60tKi7vkhaznez0a/TbVOKj5CaOZh6fWG6/Lyv9B/ZLR1gw/S/fpbeVD3MCW1li6SvWDOn65tr99/uvWtBS0XDm4s1t+sOHpG0kpBKx/l77wOSnxLpcx6TXmXLTPQOKYOf9Q1dfr8/SJ2mFdCvl1Yl93DiHUZvXeLJbGSzYu5gVJ2slbSakOR8dxCq5adQ2oFLqsE9Ex3L4qQO0eOPeU5x56bypXp4onSEb5OkICX6lDat55TeoztNKQcJaakrz9KCb95oD69IKq+yKW4XPjknaS52V0TZqE2cTtXjcHSCRmUO88e+85hj3EP74i9p8pylw7lxgMDyyl6OV7ZejnjNMfatu87LxRbH0IS35gt2a4ZjmGpVBdKK3Wr6INk8jWWSGqbA55CKgjBRC6E9w78ydTg3ABS3AFV1QN0Y4Aa2pgEjWnQURj9L0ayK6R2ysEqxHUKzYnLvvyU+i9KM2JHJzE4vyZOyDcOwOsySajeLPc8sNvPJkFlyJd20wpqAzZeAfZ3oWybxd+P/3j+SG3uSBdf2VQAAAABJRU5ErkJggg==") no-repeat;
+ background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iNjgxLjk2MjUyIgogICBoZWlnaHQ9IjE4Ny41IgogICBpZD0ic3ZnMiIKICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhOCI+PHJkZjpSREY+PGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPjxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PjxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PGRlZnMKICAgICBpZD0iZGVmczYiPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTgiPjxwYXRoCiAgICAgICAgIGQ9Ik0gMCwxNTAwIDAsMCBsIDU0NTUuNzQsMCAwLDE1MDAgTCAwLDE1MDAgeiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgyMCIgLz48L2NsaXBQYXRoPjwvZGVmcz48ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjUsMCwwLC0xLjI1LDAsMTg3LjUpIgogICAgIGlkPSJnMTAiPjxnCiAgICAgICB0cmFuc2Zvcm09InNjYWxlKDAuMSwwLjEpIgogICAgICAgaWQ9ImcxMiI+PGcKICAgICAgICAgaWQ9ImcxNCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxOCkiCiAgICAgICAgICAgaWQ9ImcxNiI+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTU0NCw1OTkuNDM0IGMgMC45MiwtNDAuMzUyIDI1LjY4LC04MS42MDIgNzEuNTMsLTgxLjYwMiAyNy41MSwwIDQ3LjY4LDEyLjgzMiA2MS40NCwzNS43NTQgMTIuODMsMjIuOTMgMTIuODMsNTYuODUyIDEyLjgzLDgyLjUyNyBsIDAsMzI5LjE4NCAtNzEuNTIsMCAwLDEwNC41NDMgMjY2LjgzLDAgMCwtMTA0LjU0MyAtNzAuNiwwIDAsLTM0NC43NyBjIDAsLTU4LjY5MSAtMy42OCwtMTA0LjUzMSAtNDQuOTMsLTE1Mi4yMTggLTM2LjY4LC00Mi4xOCAtOTYuMjgsLTY2LjAyIC0xNTMuMTQsLTY2LjAyIC0xMTcuMzcsMCAtMjA3LjI0LDc3Ljk0MSAtMjAyLjY0LDE5Ny4xNDUgbCAxMzAuMiwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMjIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDIzMDEuNCw2NjIuNjk1IGMgMCw4MC43MDMgLTY2Ljk0LDE0NS44MTMgLTE0Ny42MywxNDUuODEzIC04My40NCwwIC0xNDcuNjMsLTY4Ljc4MSAtMTQ3LjYzLC0xNTEuMzAxIDAsLTc5Ljc4NSA2Ni45NCwtMTQ1LjgwMSAxNDUuOCwtMTQ1LjgwMSA4NC4zNSwwIDE0OS40Niw2Ny44NTIgMTQ5LjQ2LDE1MS4yODkgeiBtIC0xLjgzLC0xODEuNTQ3IGMgLTM1Ljc3LC01NC4wOTcgLTkzLjUzLC03OC44NTkgLTE1Ny43MiwtNzguODU5IC0xNDAuMywwIC0yNTEuMjQsMTE2LjQ0OSAtMjUxLjI0LDI1NC45MTggMCwxNDIuMTI5IDExMy43LDI2MC40MSAyNTYuNzQsMjYwLjQxIDYzLjI3LDAgMTE4LjI5LC0yOS4zMzYgMTUyLjIyLC04Mi41MjMgbCAwLDY5LjY4NyAxNzUuMTQsMCAwLC0xMDQuNTI3IC02MS40NCwwIDAsLTI4MC41OTggNjEuNDQsMCAwLC0xMDQuNTI3IC0xNzUuMTQsMCAwLDY2LjAxOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAyNjIyLjMzLDU1Ny4yNTggYyAzLjY3LC00NC4wMTYgMzMuMDEsLTczLjM0OCA3OC44NiwtNzMuMzQ4IDMzLjkzLDAgNjYuOTMsMjMuODI0IDY2LjkzLDYwLjUwNCAwLDQ4LjYwNiAtNDUuODQsNTYuODU2IC04My40NCw2Ni45NDEgLTg1LjI4LDIyLjAwNCAtMTc4LjgxLDQ4LjYwNiAtMTc4LjgxLDE1NS44NzkgMCw5My41MzYgNzguODYsMTQ3LjYzMyAxNjUuOTgsMTQ3LjYzMyA0NCwwIDgzLjQzLC05LjE3NiAxMTAuOTQsLTQ0LjAwOCBsIDAsMzMuOTIyIDgyLjUzLDAgMCwtMTMyLjk2NSAtMTA4LjIxLDAgYyAtMS44MywzNC44NTYgLTI4LjQyLDU3Ljc3NCAtNjMuMjYsNTcuNzc0IC0zMC4yNiwwIC02Mi4zNSwtMTcuNDIyIC02Mi4zNSwtNTEuMzQ4IDAsLTQ1Ljg0NyA0NC45MywtNTUuOTMgODAuNjksLTY0LjE4IDg4LjAyLC0yMC4xNzUgMTgyLjQ3LC00Ny42OTUgMTgyLjQ3LC0xNTcuNzM0IDAsLTk5LjAyNyAtODMuNDQsLTE1NC4wMzkgLTE3NS4xMywtMTU0LjAzOSAtNDkuNTMsMCAtOTQuNDYsMTUuNTgyIC0xMjYuNTUsNTMuMTggbCAwLC00MC4zNCAtODUuMjcsMCAwLDE0Mi4xMjkgMTE0LjYyLDAiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGgyNiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMjk4OC4xOCw4MDAuMjU0IC02My4yNiwwIDAsMTA0LjUyNyAxNjUuMDUsMCAwLC03My4zNTUgYyAzMS4xOCw1MS4zNDcgNzguODYsODUuMjc3IDE0MS4yMSw4NS4yNzcgNjcuODUsMCAxMjQuNzEsLTQxLjI1OCAxNTIuMjEsLTEwMi42OTkgMjYuNiw2Mi4zNTEgOTIuNjIsMTAyLjY5OSAxNjAuNDcsMTAyLjY5OSA1My4xOSwwIDEwNS40NiwtMjIgMTQxLjIxLC02Mi4zNTEgMzguNTIsLTQ0LjkzOCAzOC41MiwtOTMuNTMyIDM4LjUyLC0xNDkuNDU3IGwgMCwtMTg1LjIzOSA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40MiwwIDAsMTA0LjUyNyA2My4yOCwwIDAsMTU3LjcxNSBjIDAsMzIuMTAyIDAsNjAuNTI3IC0xNC42Nyw4OC45NTcgLTE4LjM0LDI2LjU4MiAtNDguNjEsNDAuMzQ0IC03OS43Nyw0MC4zNDQgLTMwLjI2LDAgLTYzLjI4LC0xMi44NDQgLTgyLjUzLC0zNi42NzIgLTIyLjkzLC0yOS4zNTUgLTIyLjkzLC01Ni44NjMgLTIyLjkzLC05Mi42MjkgbCAwLC0xNTcuNzE1IDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM4LjQxLDAgMCwxMDQuNTI3IDYzLjI4LDAgMCwxNTAuMzgzIGMgMCwyOS4zNDggMCw2Ni4wMjMgLTE0LjY3LDkxLjY5OSAtMTUuNTksMjkuMzM2IC00Ny42OSw0NC45MzQgLTgwLjcsNDQuOTM0IC0zMS4xOCwwIC01Ny43NywtMTEuMDA4IC03Ny45NCwtMzUuNzc0IC0yNC43NywtMzAuMjUzIC0yNi42LC02Mi4zNDMgLTI2LjYsLTk5Ljk0MSBsIDAsLTE1MS4zMDEgNjMuMjcsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNiwwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAzOTk4LjY2LDk1MS41NDcgLTExMS44NywwIDAsMTE4LjI5MyAxMTEuODcsMCAwLC0xMTguMjkzIHogbSAwLC00MzEuODkxIDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM5LjMzLDAgMCwxMDQuNTI3IDY0LjE5LDAgMCwyODAuNTk4IC02My4yNywwIDAsMTA0LjUyNyAxNzUuMTQsMCAwLC0zODUuMTI1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzAiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDQxNTkuMTIsODAwLjI1NCAtNjMuMjcsMCAwLDEwNC41MjcgMTc1LjE0LDAgMCwtNjkuNjg3IGMgMjkuMzUsNTQuMTAxIDg0LjM2LDgwLjY5OSAxNDQuODcsODAuNjk5IDUzLjE5LDAgMTA1LjQ1LC0yMi4wMTYgMTQxLjIyLC02MC41MjcgNDAuMzQsLTQ0LjkzNCA0MS4yNiwtODguMDMyIDQxLjI2LC0xNDMuOTU3IGwgMCwtMTkxLjY1MyA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40LDAgMCwxMDQuNTI3IDYzLjI2LDAgMCwxNTguNjM3IGMgMCwzMC4yNjIgMCw2MS40MzQgLTE5LjI2LDg4LjAzNSAtMjAuMTcsMjYuNTgyIC01My4xOCwzOS40MTQgLTg2LjE5LDM5LjQxNCAtMzMuOTMsMCAtNjguNzcsLTEzLjc1IC04OC45NCwtNDEuMjUgLTIxLjA5LC0yNy41IC0yMS4wOSwtNjkuNjg3IC0yMS4wOSwtMTAyLjcwNyBsIDAsLTE0Mi4xMjkgNjMuMjYsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNywwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDMyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA1MDgyLjQ4LDcwMy45NjUgYyAtMTkuMjQsNzAuNjA1IC04MS42LDExNS41NDcgLTE1NC4wNCwxMTUuNTQ3IC02Ni4wNCwwIC0xMjkuMywtNTEuMzQ4IC0xNDMuMDUsLTExNS41NDcgbCAyOTcuMDksMCB6IG0gODUuMjcsLTE0NC44ODMgYyAtMzguNTEsLTkzLjUyMyAtMTI5LjI3LC0xNTYuNzkzIC0yMzEuMDUsLTE1Ni43OTMgLTE0My4wNywwIC0yNTcuNjgsMTExLjg3MSAtMjU3LjY4LDI1NS44MzYgMCwxNDQuODgzIDEwOS4xMiwyNjEuMzI4IDI1NC45MSwyNjEuMzI4IDY3Ljg3LDAgMTM1LjcyLC0zMC4yNTggMTgzLjM5LC03OC44NjMgNDguNjIsLTUxLjM0NCA2OC43OSwtMTEzLjY5NSA2OC43OSwtMTgzLjM4MyBsIC0zLjY3LC0zOS40MzQgLTM5Ni4xMywwIGMgMTQuNjcsLTY3Ljg2MyA3Ny4wMywtMTE3LjM2MyAxNDYuNzIsLTExNy4zNjMgNDguNTksMCA5MC43NiwxOC4zMjggMTE4LjI4LDU4LjY3MiBsIDExNi40NCwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDY5MC44OTUsODUwLjcwMyA5MC43NSwwIDIyLjU0MywzMS4wMzUgMCwyNDMuMTIyIC0xMzUuODI5LDAgMCwtMjQzLjE0MSAyMi41MzYsLTMxLjAxNiIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDM2IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA2MzIuMzk1LDc0Mi4yNTggMjguMDM5LDg2LjMwNCAtMjIuNTUxLDMxLjA0IC0yMzEuMjIzLDc1LjEyOCAtNDEuOTc2LC0xMjkuMTgzIDIzMS4yNTcsLTc1LjEzNyAzNi40NTQsMTEuODQ4IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzgiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDcxNy40NDksNjUzLjEwNSAtNzMuNDEsNTMuMzYgLTM2LjQ4OCwtMTEuODc1IC0xNDIuOTAzLC0xOTYuNjkyIDEwOS44ODMsLTc5LjgyOCAxNDIuOTE4LDE5Ni43MDMgMCwzOC4zMzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0MCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gODI4LjUyLDcwNi40NjUgLTczLjQyNiwtNTMuMzQgMC4wMTEsLTM4LjM1OSBMIDg5OC4wMDQsNDE4LjA3IDEwMDcuOSw0OTcuODk4IDg2NC45NzMsNjk0LjYwOSA4MjguNTIsNzA2LjQ2NSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA4MTIuMDg2LDgyOC41ODYgMjguMDU1LC04Ni4zMiAzNi40ODQsLTExLjgzNiAyMzEuMjI1LDc1LjExNyAtNDEuOTcsMTI5LjE4MyAtMjMxLjIzOSwtNzUuMTQgLTIyLjU1NSwtMzEuMDA0IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNDQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDczNi4zMDEsMTMzNS44OCBjIC0zMjMuMDQ3LDAgLTU4NS44NzUsLTI2Mi43OCAtNTg1Ljg3NSwtNTg1Ljc4MiAwLC0zMjMuMTE4IDI2Mi44MjgsLTU4NS45NzcgNTg1Ljg3NSwtNTg1Ljk3NyAzMjMuMDE5LDAgNTg1LjgwOSwyNjIuODU5IDU4NS44MDksNTg1Ljk3NyAwLDMyMy4wMDIgLTI2Mi43OSw1ODUuNzgyIC01ODUuODA5LDU4NS43ODIgbCAwLDAgeiBtIDAsLTExOC42MSBjIDI1Ny45NzIsMCA0NjcuMTg5LC0yMDkuMTMgNDY3LjE4OSwtNDY3LjE3MiAwLC0yNTguMTI5IC0yMDkuMjE3LC00NjcuMzQ4IC00NjcuMTg5LC00NjcuMzQ4IC0yNTguMDc0LDAgLTQ2Ny4yNTQsMjA5LjIxOSAtNDY3LjI1NCw0NjcuMzQ4IDAsMjU4LjA0MiAyMDkuMTgsNDY3LjE3MiA0NjcuMjU0LDQ2Ny4xNzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0NiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTA5MS4xMyw2MTkuODgzIC0xNzUuNzcxLDU3LjEyMSAxMS42MjksMzUuODA4IDE3NS43NjIsLTU3LjEyMSAtMTEuNjIsLTM1LjgwOCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQ4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA4NjYuOTU3LDkwMi4wNzQgODM2LjUsOTI0LjE5OSA5NDUuMTIxLDEwNzMuNzMgOTc1LjU4NiwxMDUxLjYxIDg2Ni45NTcsOTAyLjA3NCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDUwIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA2MDcuNDY1LDkwMy40NDUgNDk4Ljg1NSwxMDUyLjk3IDUyOS4zMiwxMDc1LjEgNjM3LjkzLDkyNS41NjYgNjA3LjQ2NSw5MDMuNDQ1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDM4MC42ODgsNjIyLjEyOSAtMTEuNjI2LDM1LjgwMSAxNzUuNzU4LDU3LjA5IDExLjYyMSwtMzUuODAxIC0xNzUuNzUzLC01Ny4wOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDU0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA3MTYuMjg5LDM3Ni41OSAzNy42NDA2LDAgMCwxODQuODE2IC0zNy42NDA2LDAgMCwtMTg0LjgxNiB6IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTYiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4=") no-repeat, none;
+ background-size: 100%;
+ display: block;
+ float: left;
+ width: 90px;
+ height: 25px;
+}
+.jasmine_html-reporter .jasmine-banner .jasmine-version {
+ margin-left: 14px;
+ position: relative;
+ top: 6px;
+}
+.jasmine_html-reporter #jasmine_content {
+ position: fixed;
+ right: 100%;
+}
+.jasmine_html-reporter .jasmine-banner {
+ margin-top: 14px;
+}
+.jasmine_html-reporter .jasmine-duration {
+ color: #fff;
+ float: right;
+ line-height: 28px;
+ padding-right: 9px;
+}
+.jasmine_html-reporter .jasmine-symbol-summary {
+ overflow: hidden;
+ margin: 14px 0;
+}
+.jasmine_html-reporter .jasmine-symbol-summary li {
+ display: inline-block;
+ height: 10px;
+ width: 14px;
+ font-size: 16px;
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-passed {
+ font-size: 14px;
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-passed:before {
+ color: #007069;
+ content: "•";
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed {
+ line-height: 9px;
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed:before {
+ color: #ca3a11;
+ content: "×";
+ font-weight: bold;
+ margin-left: -1px;
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded {
+ font-size: 14px;
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded:before {
+ color: #bababa;
+ content: "•";
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded-no-display {
+ font-size: 14px;
+ display: none;
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending {
+ line-height: 17px;
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending:before {
+ color: #ba9d37;
+ content: "*";
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty {
+ font-size: 14px;
+}
+.jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty:before {
+ color: #ba9d37;
+ content: "•";
+}
+.jasmine_html-reporter .jasmine-run-options {
+ float: right;
+ margin-right: 5px;
+ border: 1px solid #8a4182;
+ color: #8a4182;
+ position: relative;
+ line-height: 20px;
+}
+.jasmine_html-reporter .jasmine-run-options .jasmine-trigger {
+ cursor: pointer;
+ padding: 8px 16px;
+}
+.jasmine_html-reporter .jasmine-run-options .jasmine-payload {
+ position: absolute;
+ display: none;
+ right: -1px;
+ border: 1px solid #8a4182;
+ background-color: #eee;
+ white-space: nowrap;
+ padding: 4px 8px;
+}
+.jasmine_html-reporter .jasmine-run-options .jasmine-payload.jasmine-open {
+ display: block;
+}
+.jasmine_html-reporter .jasmine-bar {
+ line-height: 28px;
+ font-size: 14px;
+ display: block;
+ color: #eee;
+}
+.jasmine_html-reporter .jasmine-bar.jasmine-failed, .jasmine_html-reporter .jasmine-bar.jasmine-errored {
+ background-color: #ca3a11;
+ border-bottom: 1px solid #eee;
+}
+.jasmine_html-reporter .jasmine-bar.jasmine-passed {
+ background-color: #007069;
+}
+.jasmine_html-reporter .jasmine-bar.jasmine-incomplete {
+ background-color: #bababa;
+}
+.jasmine_html-reporter .jasmine-bar.jasmine-skipped {
+ background-color: #bababa;
+}
+.jasmine_html-reporter .jasmine-bar.jasmine-warning {
+ margin-top: 14px;
+ margin-bottom: 14px;
+ background-color: #ba9d37;
+ color: #333;
+}
+.jasmine_html-reporter .jasmine-bar.jasmine-menu {
+ background-color: #fff;
+ color: #000;
+}
+.jasmine_html-reporter .jasmine-bar.jasmine-menu a {
+ color: blue;
+ text-decoration: underline;
+}
+.jasmine_html-reporter .jasmine-bar a {
+ color: white;
+}
+.jasmine_html-reporter.jasmine-spec-list .jasmine-bar.jasmine-menu.jasmine-failure-list,
+.jasmine_html-reporter.jasmine-spec-list .jasmine-results .jasmine-failures {
+ display: none;
+}
+.jasmine_html-reporter.jasmine-failure-list .jasmine-bar.jasmine-menu.jasmine-spec-list,
+.jasmine_html-reporter.jasmine-failure-list .jasmine-summary {
+ display: none;
+}
+.jasmine_html-reporter .jasmine-results {
+ margin-top: 14px;
+}
+.jasmine_html-reporter .jasmine-summary {
+ margin-top: 14px;
+}
+.jasmine_html-reporter .jasmine-summary ul {
+ list-style-type: none;
+ margin-left: 14px;
+ padding-top: 0;
+ padding-left: 0;
+}
+.jasmine_html-reporter .jasmine-summary ul.jasmine-suite {
+ margin-top: 7px;
+ margin-bottom: 7px;
+}
+.jasmine_html-reporter .jasmine-summary li.jasmine-passed a {
+ color: #007069;
+}
+.jasmine_html-reporter .jasmine-summary li.jasmine-failed a {
+ color: #ca3a11;
+}
+.jasmine_html-reporter .jasmine-summary li.jasmine-empty a {
+ color: #ba9d37;
+}
+.jasmine_html-reporter .jasmine-summary li.jasmine-pending a {
+ color: #ba9d37;
+}
+.jasmine_html-reporter .jasmine-summary li.jasmine-excluded a {
+ color: #bababa;
+}
+.jasmine_html-reporter .jasmine-specs li.jasmine-passed a:before {
+ content: "• ";
+}
+.jasmine_html-reporter .jasmine-specs li.jasmine-failed a:before {
+ content: "× ";
+}
+.jasmine_html-reporter .jasmine-specs li.jasmine-empty a:before {
+ content: "* ";
+}
+.jasmine_html-reporter .jasmine-specs li.jasmine-pending a:before {
+ content: "• ";
+}
+.jasmine_html-reporter .jasmine-specs li.jasmine-excluded a:before {
+ content: "• ";
+}
+.jasmine_html-reporter .jasmine-description + .jasmine-suite {
+ margin-top: 0;
+}
+.jasmine_html-reporter .jasmine-suite {
+ margin-top: 14px;
+}
+.jasmine_html-reporter .jasmine-suite a {
+ color: #333;
+}
+.jasmine_html-reporter .jasmine-failures .jasmine-spec-detail {
+ margin-bottom: 28px;
+}
+.jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description {
+ background-color: #ca3a11;
+ color: white;
+}
+.jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description a {
+ color: white;
+}
+.jasmine_html-reporter .jasmine-result-message {
+ padding-top: 14px;
+ color: #333;
+ white-space: pre-wrap;
+}
+.jasmine_html-reporter .jasmine-result-message span.jasmine-result {
+ display: block;
+}
+.jasmine_html-reporter .jasmine-stack-trace {
+ margin: 5px 0 0 0;
+ max-height: 224px;
+ overflow: auto;
+ line-height: 18px;
+ color: #666;
+ border: 1px solid #ddd;
+ background: white;
+ white-space: pre;
+}
+.jasmine_html-reporter .jasmine-expander a {
+ display: block;
+ margin-left: 14px;
+ color: blue;
+ text-decoration: underline;
+}
+.jasmine_html-reporter .jasmine-expander-contents {
+ display: none;
+}
+.jasmine_html-reporter .jasmine-expanded {
+ padding-bottom: 10px;
+}
+.jasmine_html-reporter .jasmine-expanded .jasmine-expander-contents {
+ display: block;
+ margin-left: 14px;
+ padding: 5px;
+}
+.jasmine_html-reporter .jasmine-debug-log {
+ margin: 5px 0 0 0;
+ padding: 5px;
+ color: #666;
+ border: 1px solid #ddd;
+ background: white;
+}
+.jasmine_html-reporter .jasmine-debug-log table {
+ border-spacing: 0;
+}
+.jasmine_html-reporter .jasmine-debug-log table, .jasmine_html-reporter .jasmine-debug-log th, .jasmine_html-reporter .jasmine-debug-log td {
+ border: 1px solid #ddd;
+}
\ No newline at end of file
diff --git a/lib/jasmine-5.1.2/jasmine.js b/lib/jasmine-5.1.2/jasmine.js
new file mode 100644
index 00000000..1378b62c
--- /dev/null
+++ b/lib/jasmine-5.1.2/jasmine.js
@@ -0,0 +1,10817 @@
+/*
+Copyright (c) 2008-2019 Pivotal Labs
+Copyright (c) 2008-2024 The Jasmine developers
+
+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.
+*/
+// eslint-disable-next-line no-unused-vars,no-var
+var getJasmineRequireObj = (function(jasmineGlobal) {
+ let 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) {
+ const 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$);
+ j$.getClearStack = jRequire.clearStack(j$);
+ j$.Clock = jRequire.Clock();
+ j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
+ j$.Deprecator = jRequire.Deprecator(j$);
+ j$.Env = jRequire.Env(j$);
+ j$.StackTrace = jRequire.StackTrace(j$);
+ j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
+ j$.ExpectationFilterChain = jRequire.ExpectationFilterChain();
+ j$.Expector = jRequire.Expector(j$);
+ j$.Expectation = jRequire.Expectation(j$);
+ j$.buildExpectationResult = jRequire.buildExpectationResult(j$);
+ j$.JsApiReporter = jRequire.JsApiReporter(j$);
+ j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$);
+ j$.basicPrettyPrinter_ = j$.makePrettyPrinter();
+ j$.MatchersUtil = jRequire.MatchersUtil(j$);
+ j$.ObjectContaining = jRequire.ObjectContaining(j$);
+ j$.ArrayContaining = jRequire.ArrayContaining(j$);
+ j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
+ j$.MapContaining = jRequire.MapContaining(j$);
+ j$.SetContaining = jRequire.SetContaining(j$);
+ j$.QueueRunner = jRequire.QueueRunner(j$);
+ j$.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$);
+ j$.SkipAfterBeforeAllErrorPolicy = jRequire.SkipAfterBeforeAllErrorPolicy(
+ j$
+ );
+ j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy(
+ j$
+ );
+ j$.reporterEvents = jRequire.reporterEvents(j$);
+ j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
+ j$.ParallelReportDispatcher = jRequire.ParallelReportDispatcher(j$);
+ j$.RunableResources = jRequire.RunableResources(j$);
+ j$.Runner = jRequire.Runner(j$);
+ j$.Spec = jRequire.Spec(j$);
+ j$.Spy = jRequire.Spy(j$);
+ j$.SpyFactory = jRequire.SpyFactory(j$);
+ j$.SpyRegistry = jRequire.SpyRegistry(j$);
+ j$.SpyStrategy = jRequire.SpyStrategy(j$);
+ j$.StringMatching = jRequire.StringMatching(j$);
+ j$.StringContaining = jRequire.StringContaining(j$);
+ j$.UserContext = jRequire.UserContext(j$);
+ j$.Suite = jRequire.Suite(j$);
+ j$.SuiteBuilder = jRequire.SuiteBuilder(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$.MismatchTree = jRequire.MismatchTree(j$);
+ j$.GlobalErrors = jRequire.GlobalErrors(j$);
+
+ j$.Truthy = jRequire.Truthy(j$);
+ j$.Falsy = jRequire.Falsy(j$);
+ j$.Empty = jRequire.Empty(j$);
+ j$.NotEmpty = jRequire.NotEmpty(j$);
+ j$.Is = jRequire.Is(j$);
+
+ j$.matchers = jRequire.requireMatchers(jRequire, j$);
+ j$.asyncMatchers = jRequire.requireAsyncMatchers(jRequire, j$);
+
+ return j$;
+ };
+
+ return getJasmineRequire;
+})(this);
+
+getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
+ const availableMatchers = [
+ 'nothing',
+ 'toBe',
+ 'toBeCloseTo',
+ 'toBeDefined',
+ 'toBeInstanceOf',
+ 'toBeFalse',
+ 'toBeFalsy',
+ 'toBeGreaterThan',
+ 'toBeGreaterThanOrEqual',
+ 'toBeLessThan',
+ 'toBeLessThanOrEqual',
+ 'toBeNaN',
+ 'toBeNegativeInfinity',
+ 'toBeNull',
+ 'toBePositiveInfinity',
+ 'toBeTrue',
+ 'toBeTruthy',
+ 'toBeUndefined',
+ 'toContain',
+ 'toEqual',
+ 'toHaveSize',
+ 'toHaveBeenCalled',
+ 'toHaveBeenCalledBefore',
+ 'toHaveBeenCalledOnceWith',
+ 'toHaveBeenCalledTimes',
+ 'toHaveBeenCalledWith',
+ 'toHaveClass',
+ 'toHaveSpyInteractions',
+ 'toMatch',
+ 'toThrow',
+ 'toThrowError',
+ 'toThrowMatching'
+ ],
+ matchers = {};
+
+ for (const name of availableMatchers) {
+ matchers[name] = jRequire[name](j$);
+ }
+
+ return matchers;
+};
+
+getJasmineRequireObj().base = function(j$, jasmineGlobal) {
+ /**
+ * 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
+ * @default 8
+ * @since 1.3.0
+ */
+ 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
+ * @default 50
+ * @since 2.7.0
+ */
+ j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
+ /**
+ * Maximum number of characters to display when pretty printing objects.
+ * Characters past this number will be ellipised.
+ * @name jasmine.MAX_PRETTY_PRINT_CHARS
+ * @default 100
+ * @since 2.9.0
+ */
+ j$.MAX_PRETTY_PRINT_CHARS = 1000;
+ /**
+ * Default number of milliseconds Jasmine will wait for an asynchronous spec,
+ * before, or after function to complete. This can be overridden on a case by
+ * case basis by passing a time limit as the third argument to {@link it},
+ * {@link beforeEach}, {@link afterEach}, {@link beforeAll}, or
+ * {@link afterAll}. The value must be no greater than the largest number of
+ * milliseconds supported by setTimeout, which is usually 2147483647.
+ *
+ * While debugging tests, you may want to set this to a large number (or pass
+ * a large number to one of the functions mentioned above) so that Jasmine
+ * does not move on to after functions or the next spec while you're debugging.
+ * @name jasmine.DEFAULT_TIMEOUT_INTERVAL
+ * @default 5000
+ * @since 1.3.0
+ */
+ let DEFAULT_TIMEOUT_INTERVAL = 5000;
+ Object.defineProperty(j$, 'DEFAULT_TIMEOUT_INTERVAL', {
+ get: function() {
+ return DEFAULT_TIMEOUT_INTERVAL;
+ },
+ set: function(newValue) {
+ j$.util.validateTimeout(newValue, 'jasmine.DEFAULT_TIMEOUT_INTERVAL');
+ DEFAULT_TIMEOUT_INTERVAL = newValue;
+ }
+ });
+
+ j$.getGlobal = function() {
+ return jasmineGlobal;
+ };
+
+ /**
+ * Get the currently booted Jasmine Environment.
+ *
+ * @name jasmine.getEnv
+ * @since 1.3.0
+ * @function
+ * @return {Env}
+ */
+ j$.getEnv = function(options) {
+ const 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$.isGeneratorFunction_ = function(value) {
+ return j$.isA_('GeneratorFunction', 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$.isError_ = function(value) {
+ if (!value) {
+ return false;
+ }
+
+ if (value instanceof Error) {
+ return true;
+ }
+
+ return typeof value.stack === 'string' && typeof value.message === 'string';
+ };
+
+ j$.isAsymmetricEqualityTester_ = function(obj) {
+ return obj ? j$.isA_('Function', obj.asymmetricMatch) : false;
+ };
+
+ j$.getType_ = function(value) {
+ return Object.prototype.toString.apply(value);
+ };
+
+ j$.isDomNode = function(obj) {
+ // Node is a function, because constructors
+ return typeof jasmineGlobal.Node !== 'undefined'
+ ? obj instanceof jasmineGlobal.Node
+ : obj !== null &&
+ typeof obj === 'object' &&
+ typeof obj.nodeType === 'number' &&
+ typeof obj.nodeName === 'string';
+ // return obj.nodeType > 0;
+ };
+
+ j$.isMap = function(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === jasmineGlobal.Map
+ );
+ };
+
+ j$.isSet = function(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === jasmineGlobal.Set
+ );
+ };
+
+ j$.isWeakMap = function(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === jasmineGlobal.WeakMap
+ );
+ };
+
+ j$.isURL = function(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === jasmineGlobal.URL
+ );
+ };
+
+ j$.isIterable_ = function(value) {
+ return value && !!value[Symbol.iterator];
+ };
+
+ j$.isDataView = function(obj) {
+ return (
+ obj !== null &&
+ typeof obj !== 'undefined' &&
+ obj.constructor === jasmineGlobal.DataView
+ );
+ };
+
+ j$.isPromise = function(obj) {
+ return !!obj && obj.constructor === jasmineGlobal.Promise;
+ };
+
+ j$.isPromiseLike = function(obj) {
+ return !!obj && j$.isFunction_(obj.then);
+ };
+
+ j$.fnNameFor = function(func) {
+ if (func.name) {
+ return func.name;
+ }
+
+ const matches =
+ func.toString().match(/^\s*function\s*(\w+)\s*\(/) ||
+ func.toString().match(/^\s*\[object\s*(\w+)Constructor\]/);
+
+ return matches ? matches[1] : '';
+ };
+
+ j$.isPending_ = function(promise) {
+ const sentinel = {};
+ return Promise.race([promise, Promise.resolve(sentinel)]).then(
+ function(result) {
+ return result === sentinel;
+ },
+ function() {
+ return false;
+ }
+ );
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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
+ * @since 1.3.0
+ * @function
+ * @param {Constructor} clazz - The constructor to check against.
+ */
+ j$.any = function(clazz) {
+ return new j$.Any(clazz);
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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
+ * @since 2.2.0
+ * @function
+ */
+ j$.anything = function() {
+ return new j$.Anything();
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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 `true` or anything truthy.
+ * @name jasmine.truthy
+ * @since 3.1.0
+ * @function
+ */
+ j$.truthy = function() {
+ return new j$.Truthy();
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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 `null`, `undefined`, `0`, `false` or anything falsey.
+ * @name jasmine.falsy
+ * @since 3.1.0
+ * @function
+ */
+ j$.falsy = function() {
+ return new j$.Falsy();
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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 empty.
+ * @name jasmine.empty
+ * @since 3.1.0
+ * @function
+ */
+ j$.empty = function() {
+ return new j$.Empty();
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher}
+ * that passes if the actual value is the same as the sample as determined
+ * by the `===` operator.
+ * @name jasmine.is
+ * @function
+ * @param {Object} sample - The value to compare the actual to.
+ */
+ j$.is = function(sample) {
+ return new j$.Is(sample);
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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 empty.
+ * @name jasmine.notEmpty
+ * @since 3.1.0
+ * @function
+ */
+ j$.notEmpty = function() {
+ return new j$.NotEmpty();
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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
+ * @since 1.3.0
+ * @function
+ * @param {Object} sample - The subset of properties that _must_ be in the actual.
+ */
+ j$.objectContaining = function(sample) {
+ return new j$.ObjectContaining(sample);
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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
+ * @since 2.2.0
+ * @function
+ * @param {RegExp|String} expected
+ */
+ j$.stringMatching = function(expected) {
+ return new j$.StringMatching(expected);
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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 contains the specified `String`.
+ * @name jasmine.stringContaining
+ * @since 3.10.0
+ * @function
+ * @param {String} expected
+ */
+ j$.stringContaining = function(expected) {
+ return new j$.StringContaining(expected);
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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
+ * @since 2.2.0
+ * @function
+ * @param {Array} sample
+ */
+ j$.arrayContaining = function(sample) {
+ return new j$.ArrayContaining(sample);
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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
+ * @since 2.8.0
+ * @function
+ * @param {Array} sample
+ */
+ j$.arrayWithExactContents = function(sample) {
+ return new j$.ArrayWithExactContents(sample);
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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 every key/value pair in the sample passes the deep equality comparison
+ * with at least one key/value pair in the actual value being compared
+ * @name jasmine.mapContaining
+ * @since 3.5.0
+ * @function
+ * @param {Map} sample - The subset of items that _must_ be in the actual.
+ */
+ j$.mapContaining = function(sample) {
+ return new j$.MapContaining(sample);
+ };
+
+ /**
+ * Get an {@link AsymmetricEqualityTester}, 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 every item in the sample passes the deep equality comparison
+ * with at least one item in the actual value being compared
+ * @name jasmine.setContaining
+ * @since 3.5.0
+ * @function
+ * @param {Set} sample - The subset of items that _must_ be in the actual.
+ */
+ j$.setContaining = function(sample) {
+ return new j$.SetContaining(sample);
+ };
+
+ /**
+ * Determines whether the provided function is a Jasmine spy.
+ * @name jasmine.isSpy
+ * @since 2.0.0
+ * @function
+ * @param {Function} putativeSpy - The function to check.
+ * @return {Boolean}
+ */
+ j$.isSpy = function(putativeSpy) {
+ if (!putativeSpy) {
+ return false;
+ }
+ return (
+ putativeSpy.and instanceof j$.SpyStrategy &&
+ putativeSpy.calls instanceof j$.CallTracker
+ );
+ };
+
+ /**
+ * Logs a message for use in debugging. If the spec fails, trace messages
+ * will be included in the {@link SpecResult|result} passed to the
+ * reporter's specDone method.
+ *
+ * This method should be called only when a spec (including any associated
+ * beforeEach or afterEach functions) is running.
+ * @function
+ * @name jasmine.debugLog
+ * @since 4.0.0
+ * @param {String} msg - The message to log
+ */
+ j$.debugLog = function(msg) {
+ j$.getEnv().debugLog(msg);
+ };
+
+ /**
+ * Replaces Jasmine's global error handling with a spy. This prevents Jasmine
+ * from treating uncaught exceptions and unhandled promise rejections
+ * as spec failures and allows them to be inspected using the spy's
+ * {@link Spy#calls|calls property} and related matchers such as
+ * {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}.
+ *
+ * After installing the spy, spyOnGlobalErrorsAsync immediately calls its
+ * argument, which must be an async or promise-returning function. The spy
+ * will be passed as the first argument to that callback. Normal error
+ * handling will be restored when the promise returned from the callback is
+ * settled.
+ *
+ * Note: The JavaScript runtime may deliver uncaught error events and unhandled
+ * rejection events asynchronously, especially in browsers. If the event
+ * occurs after the promise returned from the callback is settled, it won't
+ * be routed to the spy even if the underlying error occurred previously.
+ * It's up to you to ensure that the returned promise isn't resolved until
+ * all of the error/rejection events that you want to handle have occurred.
+ *
+ * You must await the return value of spyOnGlobalErrorsAsync.
+ * @name jasmine.spyOnGlobalErrorsAsync
+ * @function
+ * @async
+ * @param {AsyncFunction} fn - A function to run, during which the global error spy will be effective
+ * @example
+ * it('demonstrates global error spies', async function() {
+ * await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
+ * setTimeout(function() {
+ * throw new Error('the expected error');
+ * });
+ * await new Promise(function(resolve) {
+ * setTimeout(resolve);
+ * });
+ * const expected = new Error('the expected error');
+ * expect(globalErrorSpy).toHaveBeenCalledWith(expected);
+ * });
+ * });
+ */
+ j$.spyOnGlobalErrorsAsync = async function(fn) {
+ await jasmine.getEnv().spyOnGlobalErrorsAsync(fn);
+ };
+};
+
+getJasmineRequireObj().util = function(j$) {
+ const util = {};
+
+ util.isUndefined = function(obj) {
+ return obj === void 0;
+ };
+
+ util.clone = function(obj) {
+ if (Object.prototype.toString.apply(obj) === '[object Array]') {
+ return obj.slice();
+ }
+
+ const cloned = {};
+ for (const prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ cloned[prop] = obj[prop];
+ }
+ }
+
+ return cloned;
+ };
+
+ util.cloneArgs = function(args) {
+ return Array.from(args).map(function(arg) {
+ const str = Object.prototype.toString.apply(arg),
+ primitives = /^\[object (Boolean|String|RegExp|Number)/;
+
+ // All falsey values are either primitives, `null`, or `undefined.
+ if (!arg || str.match(primitives)) {
+ return arg;
+ } else if (str === '[object Date]') {
+ return new Date(arg.valueOf());
+ } else {
+ return j$.util.clone(arg);
+ }
+ });
+ };
+
+ util.getPropertyDescriptor = function(obj, methodName) {
+ let descriptor,
+ proto = obj;
+
+ do {
+ descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
+ proto = Object.getPrototypeOf(proto);
+ } while (!descriptor && proto);
+
+ return descriptor;
+ };
+
+ util.has = function(obj, key) {
+ return Object.prototype.hasOwnProperty.call(obj, key);
+ };
+
+ util.errorWithStack = function errorWithStack() {
+ // Don't throw and catch. That makes it harder for users to debug their
+ // code with exception breakpoints, and it's unnecessary since all
+ // supported environments populate new Error().stack
+ return new Error();
+ };
+
+ function callerFile() {
+ const trace = new j$.StackTrace(util.errorWithStack());
+ return trace.frames[2].file;
+ }
+
+ util.jasmineFile = (function() {
+ let result;
+
+ return function() {
+ if (!result) {
+ result = callerFile();
+ }
+
+ return result;
+ };
+ })();
+
+ util.validateTimeout = function(timeout, msgPrefix) {
+ // Timeouts are implemented with setTimeout, which only supports a limited
+ // range of values. The limit is unspecified, as is the behavior when it's
+ // exceeded. But on all currently supported JS runtimes, setTimeout calls
+ // the callback immediately when the timeout is greater than 2147483647
+ // (the maximum value of a signed 32 bit integer).
+ const max = 2147483647;
+
+ if (timeout > max) {
+ throw new Error(
+ (msgPrefix || 'Timeout value') + ' cannot be greater than ' + max
+ );
+ }
+ };
+
+ return util;
+};
+
+getJasmineRequireObj().Spec = function(j$) {
+ function Spec(attrs) {
+ this.expectationFactory = attrs.expectationFactory;
+ this.asyncExpectationFactory = attrs.asyncExpectationFactory;
+ this.resultCallback = attrs.resultCallback || function() {};
+ this.id = attrs.id;
+ this.filename = attrs.filename;
+ this.parentSuiteId = attrs.parentSuiteId;
+ 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.autoCleanClosures =
+ attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures;
+ this.getSpecName =
+ attrs.getSpecName ||
+ function() {
+ return '';
+ };
+ this.onLateError = attrs.onLateError || function() {};
+ this.catchingExceptions =
+ attrs.catchingExceptions ||
+ function() {
+ return true;
+ };
+ this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
+ this.timer = attrs.timer || new j$.Timer();
+
+ if (!this.queueableFn.fn) {
+ this.exclude();
+ }
+
+ this.reset();
+ }
+
+ Spec.prototype.addExpectationResult = function(passed, data, isError) {
+ const expectationResult = j$.buildExpectationResult(data);
+
+ if (passed) {
+ this.result.passedExpectations.push(expectationResult);
+ } else {
+ if (this.reportedDone) {
+ this.onLateError(expectationResult);
+ } else {
+ this.result.failedExpectations.push(expectationResult);
+
+ // TODO: refactor so that we don't need to override cached status
+ if (this.result.status) {
+ this.result.status = 'failed';
+ }
+ }
+
+ if (this.throwOnExpectationFailure && !isError) {
+ throw new j$.errors.ExpectationFailed();
+ }
+ }
+ };
+
+ Spec.prototype.setSpecProperty = function(key, value) {
+ this.result.properties = this.result.properties || {};
+ this.result.properties[key] = value;
+ };
+
+ Spec.prototype.execute = function(
+ queueRunnerFactory,
+ onComplete,
+ excluded,
+ failSpecWithNoExp
+ ) {
+ const onStart = {
+ fn: done => {
+ this.timer.start();
+ this.onStart(this, done);
+ }
+ };
+
+ const complete = {
+ fn: done => {
+ if (this.autoCleanClosures) {
+ this.queueableFn.fn = null;
+ }
+ this.result.status = this.status(excluded, failSpecWithNoExp);
+ this.result.duration = this.timer.elapsed();
+
+ if (this.result.status !== 'failed') {
+ this.result.debugLogs = null;
+ }
+
+ this.resultCallback(this.result, done);
+ },
+ type: 'specCleanup'
+ };
+
+ const fns = this.beforeAndAfterFns();
+
+ const runnerConfig = {
+ isLeaf: true,
+ queueableFns: [...fns.befores, this.queueableFn, ...fns.afters],
+ onException: e => this.handleException(e),
+ onMultipleDone: () => {
+ // Issue a deprecation. Include the context ourselves and pass
+ // ignoreRunnable: true, since getting here always means that we've already
+ // moved on and the current runnable isn't the one that caused the problem.
+ this.onLateError(
+ new Error(
+ 'An asynchronous spec, beforeEach, or afterEach function called its ' +
+ "'done' callback more than once.\n(in spec: " +
+ this.getFullName() +
+ ')'
+ )
+ );
+ },
+ onComplete: () => {
+ if (this.result.status === 'failed') {
+ onComplete(new j$.StopExecutionError('spec failed'));
+ } else {
+ onComplete();
+ }
+ },
+ userContext: this.userContext(),
+ runnableName: this.getFullName.bind(this)
+ };
+
+ if (this.markedPending || excluded === true) {
+ runnerConfig.queueableFns = [];
+ }
+
+ runnerConfig.queueableFns.unshift(onStart);
+ runnerConfig.queueableFns.push(complete);
+
+ queueRunnerFactory(runnerConfig);
+ };
+
+ Spec.prototype.reset = function() {
+ /**
+ * @typedef SpecResult
+ * @property {String} 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 {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
+ * @property {String} filename - The name of the file the spec was defined in.
+ * @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.
+ * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
+ * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty}
+ * @property {DebugLogEntry[]|null} debugLogs - Messages, if any, that were logged using {@link jasmine.debugLog} during a failing spec.
+ * @since 2.0.0
+ */
+ this.result = {
+ id: this.id,
+ description: this.description,
+ fullName: this.getFullName(),
+ parentSuiteId: this.parentSuiteId,
+ filename: this.filename,
+ failedExpectations: [],
+ passedExpectations: [],
+ deprecationWarnings: [],
+ pendingReason: this.excludeMessage || '',
+ duration: null,
+ properties: null,
+ debugLogs: null
+ };
+ this.markedPending = this.markedExcluding;
+ this.reportedDone = false;
+ };
+
+ Spec.prototype.handleException = function handleException(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
+ );
+ };
+
+ /*
+ * Marks state as pending
+ * @param {string} [message] An optional reason message
+ */
+ Spec.prototype.pend = function(message) {
+ this.markedPending = true;
+ if (message) {
+ this.result.pendingReason = message;
+ }
+ };
+
+ /*
+ * Like {@link Spec#pend}, but pending state will survive {@link Spec#reset}
+ * Useful for fit, xit, where pending state remains.
+ * @param {string} [message] An optional reason message
+ */
+ Spec.prototype.exclude = function(message) {
+ this.markedExcluding = true;
+ if (this.message) {
+ this.excludeMessage = message;
+ }
+ this.pend(message);
+ };
+
+ Spec.prototype.getResult = function() {
+ this.result.status = this.status();
+ return this.result;
+ };
+
+ Spec.prototype.status = function(excluded, failSpecWithNoExpectations) {
+ if (excluded === true) {
+ return 'excluded';
+ }
+
+ if (this.markedPending) {
+ return 'pending';
+ }
+
+ if (
+ this.result.failedExpectations.length > 0 ||
+ (failSpecWithNoExpectations &&
+ this.result.failedExpectations.length +
+ this.result.passedExpectations.length ===
+ 0)
+ ) {
+ return 'failed';
+ }
+
+ return 'passed';
+ };
+
+ Spec.prototype.getFullName = function() {
+ return this.getSpecName(this);
+ };
+
+ Spec.prototype.addDeprecationWarning = function(deprecation) {
+ if (typeof deprecation === 'string') {
+ deprecation = { message: deprecation };
+ }
+ this.result.deprecationWarnings.push(
+ j$.buildExpectationResult(deprecation)
+ );
+ };
+
+ Spec.prototype.debugLog = function(msg) {
+ if (!this.result.debugLogs) {
+ this.result.debugLogs = [];
+ }
+
+ /**
+ * @typedef DebugLogEntry
+ * @property {String} message - The message that was passed to {@link jasmine.debugLog}.
+ * @property {number} timestamp - The time when the entry was added, in
+ * milliseconds from the spec's start time
+ */
+ this.result.debugLogs.push({
+ message: msg,
+ timestamp: this.timer.elapsed()
+ });
+ };
+
+ const extractCustomPendingMessage = function(e) {
+ const fullMessage = e.toString(),
+ boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),
+ boilerplateEnd =
+ boilerplateStart + Spec.pendingSpecExceptionMessage.length;
+
+ return fullMessage.slice(boilerplateEnd);
+ };
+
+ Spec.pendingSpecExceptionMessage = '=> marked Pending';
+
+ Spec.isPendingSpecException = function(e) {
+ return !!(
+ e &&
+ e.toString &&
+ e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1
+ );
+ };
+
+ /**
+ * @interface Spec
+ * @see Configuration#specFilter
+ * @since 2.0.0
+ */
+ Object.defineProperty(Spec.prototype, 'metadata', {
+ get: function() {
+ if (!this.metadata_) {
+ this.metadata_ = {
+ /**
+ * The unique ID of this spec.
+ * @name Spec#id
+ * @readonly
+ * @type {string}
+ * @since 2.0.0
+ */
+ id: this.id,
+
+ /**
+ * The description passed to the {@link it} that created this spec.
+ * @name Spec#description
+ * @readonly
+ * @type {string}
+ * @since 2.0.0
+ */
+ description: this.description,
+
+ /**
+ * The full description including all ancestors of this spec.
+ * @name Spec#getFullName
+ * @function
+ * @returns {string}
+ * @since 2.0.0
+ */
+ getFullName: this.getFullName.bind(this)
+ };
+ }
+
+ return this.metadata_;
+ }
+ });
+
+ return Spec;
+};
+
+getJasmineRequireObj().Order = function() {
+ function Order(options) {
+ this.random = 'random' in options ? options.random : true;
+ const seed = (this.seed = options.seed || generateSeed());
+ this.sort = this.random ? randomOrder : naturalOrder;
+
+ function naturalOrder(items) {
+ return items;
+ }
+
+ function randomOrder(items) {
+ const 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 slightly.
+ // We use your return to sort the children randomly in a consistent way when
+ // used in conjunction with a seed
+
+ function jenkinsHash(key) {
+ let 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$) {
+ /**
+ * @class Env
+ * @since 2.0.0
+ * @classdesc The Jasmine environment.
+ * _Note:_ Do not construct this directly. You can obtain the Env instance by
+ * calling {@link jasmine.getEnv}.
+ * @hideconstructor
+ */
+ function Env(options) {
+ options = options || {};
+
+ const self = this;
+ const global = options.global || j$.getGlobal();
+
+ const realSetTimeout = global.setTimeout;
+ const realClearTimeout = global.clearTimeout;
+ const clearStack = j$.getClearStack(global);
+ this.clock = new j$.Clock(
+ global,
+ function() {
+ return new j$.DelayedFunctionScheduler();
+ },
+ new j$.MockDate(global)
+ );
+
+ const globalErrors = new j$.GlobalErrors();
+ const installGlobalErrors = (function() {
+ let installed = false;
+ return function() {
+ if (!installed) {
+ globalErrors.install();
+ installed = true;
+ }
+ };
+ })();
+
+ const runableResources = new j$.RunableResources({
+ getCurrentRunableId: function() {
+ const r = runner.currentRunable();
+ return r ? r.id : null;
+ },
+ globalErrors
+ });
+
+ let reporter;
+ let topSuite;
+ let runner;
+ let parallelLoadingState = null; // 'specs', 'helpers', or null for non-parallel
+
+ /**
+ * This represents the available options to configure Jasmine.
+ * Options that are not provided will use their default values.
+ * @see Env#configure
+ * @interface Configuration
+ * @since 3.3.0
+ */
+ const config = {
+ /**
+ * Whether to randomize spec execution order
+ * @name Configuration#random
+ * @since 3.3.0
+ * @type Boolean
+ * @default true
+ */
+ random: true,
+ /**
+ * Seed to use as the basis of randomization.
+ * Null causes the seed to be determined randomly at the start of execution.
+ * @name Configuration#seed
+ * @since 3.3.0
+ * @type (number|string)
+ * @default null
+ */
+ seed: null,
+ /**
+ * Whether to stop execution of the suite after the first spec failure
+ *
+ *
In parallel mode, `stopOnSpecFailure` works on a "best effort"
+ * basis. Jasmine will stop execution as soon as practical after a failure
+ * but it might not be immediate.