Repository: udacity/frontend-grading-engine Branch: master Commit: 7642062f0b43 Files: 74 Total size: 438.3 KB Directory structure: gitextract_tfrp3au2/ ├── .gitignore ├── .jscsrc ├── .jshintrc ├── README.md ├── chromium/ │ ├── README.md │ ├── browser_action/ │ │ ├── intro.js │ │ └── outro.js │ ├── inject/ │ │ ├── intro.js │ │ └── outro.js │ ├── manifest.json │ └── options/ │ ├── intro.js │ └── outro.js ├── firefox/ │ ├── README.md │ ├── background.js │ ├── browser_action/ │ │ ├── intro.js │ │ └── outro.js │ ├── inject/ │ │ ├── intro.js │ │ └── outro.js │ ├── manifest.json │ └── options/ │ ├── intro.js │ └── outro.js ├── gulpfile.js ├── lib/ │ └── components.js ├── license ├── package.json ├── safari/ │ ├── Info.plist │ ├── README.md │ ├── background/ │ │ ├── REAMDE.md │ │ ├── adapter.js │ │ ├── adapterListener.js │ │ ├── background.html │ │ ├── background.js │ │ ├── helpers.js │ │ └── registry.js │ ├── browser_action/ │ │ ├── intro.js │ │ └── outro.js │ ├── inject/ │ │ ├── intro.js │ │ └── outro.js │ └── options/ │ ├── intro.js │ └── outro.js ├── sample/ │ ├── index.html │ ├── test.json │ └── unit-tests.js └── src/ ├── app/ │ ├── README.md │ ├── browser_action/ │ │ ├── browser_action.html │ │ └── browser_action.js │ ├── css/ │ │ ├── common.css │ │ ├── fonts/ │ │ │ └── OFL.txt │ │ ├── fonts.css │ │ ├── options.css │ │ └── ui.css │ ├── js/ │ │ ├── inject/ │ │ │ ├── StateManager.js │ │ │ ├── helpers.js │ │ │ └── inject.js │ │ └── libs/ │ │ └── jsgrader.js │ ├── options/ │ │ ├── index.html │ │ └── options.js │ └── test_widget/ │ ├── active_test.js │ ├── font.js │ ├── test_results.js │ ├── test_suite.js │ └── test_widget.js └── js/ ├── ActiveTest.js ├── GradeBook.js ├── Queue.js ├── README.md ├── Suite.js ├── TACollectors.js ├── TAReporters.js ├── Target.js ├── helpers.js ├── intro.js ├── outro.js └── registrar.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ build/ .DS_STORE node_modules/ ext.zip TODO GE.min.js GE.js .dir-locals.el \#*\# GTAGS GRTAGS GPATH experiments/ .tern-port .tern-project log.md build.zip global.js ================================================ FILE: .jscsrc ================================================ { "preset": "google", "disallowSpacesInAnonymousFunctionExpression": null, "excludeFiles": ["node_modules/**"] } ================================================ FILE: .jshintrc ================================================ { "node": true, "browser": true, "bitwise": true, "camelcase": true, "curly": true, "eqeqeq": true, "immed": true, "indent": 2, "latedef": true, "noarg": true, "quotmark": "single", "undef": true, "unused": true, "newcap": false, "globals": { "Polymer": true, "Platform": true, "Promise": true, "MathAndPhysics": true, "CookieManager": true, "Model": true, "window": true, "document": true } } ================================================ FILE: README.md ================================================ # Udacity Feedback Chrome Extension Immediate, visual feedback about any website's HTML, CSS and JavaScript. * Not sure what this is? Try the [walkthrough](http://labs.udacity.com/udacity-feedback-extension/). * Just want to install? Visit the [Chrome Web Store](https://chrome.google.com/webstore/detail/udacity-front-end-feedbac/melpgahbngpgnbhhccnopmlmpbmdaeoi). ## Installing from Source 1. Clone this repo 2. `npm install` - install dependencies 3. `gulp watch` or just `gulp` - build the grading engine 4. [Load in Chrome](https://developer.chrome.com/extensions/getstarted#unpacked) * Open the Extensions window (`chrome://extensions`) * Check 'Developer Mode' * Click 'Load unpacked extension...' * Select `ext/` [**More on development**](#how-udacity-feedback-works) ## Loading Tests ### On sites you own Add the following meta tag: ```html ``` There are two optional attributes: `libraries` and `unit-tests`. `libraries` is always optional and `unit-tests` is only necessary for JS quizzes. More on JS tests [here](#js-tests). ### On sites you don't own Click on the Udacity browser action. Choose 'Load tests' and navigate to a JSON. ## API ### JSON Typical structure is an array of: suite |_name |_code |_tests |_description |_definition | |_nodes | |_collector | |_reporter | |_[flags] Example: ```javascript [{ "name": "Learning Udacity Feedback", "code": "This can be an encouraging message", "tests": [ { "description": "Test 1 has correct bg color", "definition": { "nodes": ".test1", "cssProperty": "backgroundColor", "equals": "rgb(204, 204, 255)" } } ] }, { "name": "More 'dacity Feedback", "code": "Some message", "tests": [ { "description": "Test 2 says 'Hello, world!'", "definition": { "nodes": ".test2", "get": "innerHTML", "hasSubstring": "^Hello, world!$" } }, { "description": "Test 3 has two columns", "definition": { "nodes": ".test4", "get": "count", "equals": 2 } }, { "description": "Test 4 has been dispatched", "definition": { "waitForEvent": "ud-test", "exists": true }, "flags": { "noRepeat": true } } ] }] ``` *Note that the feedback JSON must be an array of objects* * `"name"`: the name of the suite. The word "Test" or "Tests" gets appended when this name shows up in the widget as a heading for its child tests. * `"code"`: a message to display when all tests in the suite pass. Why is it called a code? It's sometimes the code I make students copy and paste into a quiz on the Udacity site to prove they finished the quiz. * `"tests"`: an array of test objects * `"description"`: shows up in the test widget. Try to keep titles short, as long titles don't wrap well in the current version. * `"definition"`: an object with collector and reporter properties. More on this below. * `"flags"`: optional flags to alter the way a test is run. The most common is `noRepeat`, which ensures that a test runs only once rather than repeatedly. ### How to write a `"definition"` Think about this sentence as you write tests: > I want the nodes of [selector] to have [some property] that [compares to some value]. #### 1) Start with `"nodes"`. Most* tests against the DOM need some nodes to examine. This is the start of a "collector". ```javascript "definition": { "nodes": "selector", ... } ``` **Exceptions: collecting a user-agent string, device pixel ratio, or in conjunction with `"waitForEvent"`.* #### 2) Decide what value you want to collect and test. **CSS:** ```javascript "definition": { "nodes": ".anything" "cssProperty": "backgroundColor", ... } ``` The `"cssProperty"` can be the camelCase version of [any CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Properties_Reference). `"cssProperty"` takes advantage of `window.getComputedStyle()`. * Colors will be returned in the form of `"rgb(255, 255, 255)"`. Note the spaces. * All `width`, `margin`, etc measurements are returned as pixel values, not percentages. **Attribute:** ```javascript "definition": { "nodes": "input" "attribute": "for", ... } ``` Any attribute works. **Absolute Position:** ```javascript "definition": { "nodes": ".left-nav" "absolutePosition": "side", ... } ``` Side must be one of: `top`, `left`, `bottom`, or `right`. Currently, the position returned is relative to the **viewport**. **Count, innerHTML, ChildPosition, UAString (user-agent string), DPR (device pixel ratio):** ```javascript "definition": { "nodes": ".box" "get": "count", ... } ``` These tests (`"count"`, `"innerHTML"`, `"childPositions"`, `"UAString"`, `"DPR"`) use `"get"` and they are the only tests that use `"get"`. Remember the asterix from earlier about the necessity of `"nodes"`? Device pixel ratios and user-agent strings are exceptions - you can `"get": "UAString"` or `"get": "DPR"` without `"nodes"`. "Child position? I haven't seen anything about children." - a question you might be asking yourself. Let me answer it. **Children** ```javascript "definition": { "nodes": ".flex-container", "children": "div", "absolutePosition": "side", ... } ``` `"children"` is a deep children selector. In this example, it was used to select all the divs inside a flex container. Now, reporters will run tests against all of the child divs, not the parent flex container. #### 3) Decide how you want to grade the values you just collected. This is a "reporter". **Equals** ```javascript "definition": { "nodes": ".flex", "get": "count", "equals": 4 } ``` or ```javascript "definition": { "nodes": "input.billing-address", "attribute": "for", "equals": "billing-address" } ``` or ```javascript "definition": { "nodes": ".inline", "cssProperty": "display", "equals": [ "inline", "inline-block" ] } ``` Set the `"equals"` value to a string, a number, or an array of strings and numbers. This test looks for a strict equality match of either the value or one of the values in the array. In the first example, the test passes when the count of nodes returned by the selector equals four. In the second, the `for` attribute of `` must be set to `"billing-address"`. In the third example, the test passes if `display` is either `inline` or `inline-block`. If you want to compare strings and would prefer to use regex, try `"hasSubstring"`. **Exists** ```javascript "definition": { "nodes": "input.billing-address", "attribute": "for", "exists": true } ``` In this example, rather than looking for a specific `for`, I'm just checking to see that it exists at all. The value doesn't matter. If `"exists": false`, then the test will only pass if the attribute does not exist. **Comparison** ```javascript "definition": { "nodes": ".flex", "get": "count", "isLessThan": 4 } ``` `"isLessThan"` and `"isGreaterThan"` share identical behavior. ```javascript "definition": { "nodes": ".flex", "get": "count", "isInRange": { "lower": 4, "upper": 10 } } ``` Set an `"upper"` and a `"lower"` value for `"isInRange"`. **Substrings** ```javascript "definition": { "nodes": ".text", "get": "innerHTML", "hasSubstring": "([A-Z])\w+" } ``` Run regex tests against strings with `"hasSubstring"`. If one or more match groups are returned, the test passes. **NOTE**: you must escape `\`s! eg. `\wHello` will break, but `\\wHello` will work. You can pass an array to `"hasSubstring"` if you want to match one regex out of many. ```javascript "definition": { "nodes": ".text", "get": "innerHTML", "hasSubstring": ["([A-Z])\w+", "([a-z])\w+"] } ``` There is an alternate syntax with optional configs for `"hasSubstring"`. ```javascript "definition": { "nodes": ".text", "get": "innerHTML", "hasSubstring": { "expected": [ "([A-Z])\\w+", "$another^" ], "minValues": 1, "maxValues": 2 } } ``` This test checks that either one or both of the expected values are found. If you set `"hasSubstring"` to an object with an array of `"expected"` regexes, you can optionally use `"minValues"` and `"maxValues"` to determine how many of the expected values need to match in order for the test to pass. Unless otherwise specified, only one value from the `"expected"` array will need to be matched in order for the test to pass. **Utility Properties - `not`, `limit`** ```javascript "definition": { "nodes": ".text", "get": "innerHTML", "not": true, "hasSubstring": "([A-Z])\\w+" } ``` Switch behavior with `"not"`. A failing test will now pass and vice versa. ```javascript "definition": { "nodes": ".title", "cssProperty": "marginTop", "limit": 1, "equals": 10 } ``` Currently, the values supported by `"limit"` are any number >= 1, `"all"` (default), and `"some"`. Remember, by default every node collected by `"nodes"` or `"children"` must pass the test specified. To change that, use `"limit"`. If it is any number, `0 < numberCorrect <= limit` values must pass in order for the test to pass. If more than one value passes, the test fails. In the case of `"some"`, one or more values must pass in order for the test to pass. **Flags** ```javascript "definition": { "nodes": ".small", "cssProperty": "borderLeft", "equals": 10 }, "flags": { "noRepeat": true } ``` Options here currently include `"noRepeat"` and `"alwaysRun"`. By default, a test runs every 1000ms until it either passes or encounters an error. If `"noRepeat"` is set, the test only runs once when the widget loads and does not rerun every 1000ms. If `"alwaysRun"`, the test continues to run even after it passes. ### JavaScript Tests ```javascript "definition": { "waitForEvent": "custom-event", "exists": true } ``` For security reasons, you can only run JavaScript tests against pages that you control. You can trigger tests by dispatching custom events from inside your application or from a script linked in the `unit-tests` attribute of the meta tag. Set `"waitForEvent"` to a custom event. As soon as the custom event is detected, the test passes. Example of a custom event: ```javascript window.dispatchEvent(new CustomEvent('ud-test', {'detail': 'passed'})); ``` I like to use the [jsgrader library](https://github.com/udacity/js-grader) for writing JS tests because it supports grading checkpoints (logic to say "stop grading if this test fails"). You can use it too by setting `libraries="jsgrader"` in the meta tag.]. ### Test States and Debugging ![wrong answer, right answer, error](images/wrong-right-error.png) Green tests with ✓ have passed, red tests with ✗ have failed and yellow tests with ?? have some kind of error. If there is an error, run `UdacityFEGradingEngine.debug();` from the console to see why the yellow tests are erring. You can find an options page in chrome://extensions. Use the options page to see and modify the list of domains on which the extension will run. ## How Udacity Feedback Works At the core of Udacity Feedback is the grading engine. The grading engine performs two tasks: collecting information from the DOM and reporting on it. Each test creates its own instance of the grading engine which queries the DOM once a second (unless otherwise specified). ### Overview of the source code: * **TA** (Teaching Assistant). The TA orchestrates the DOM querying and comparison logic of the grading engine. There is a collection aspect (src/js/TACollectors.js) and a reporting aspect (src/js/TAReporters.js). Collectors pull info from the DOM. Reporters are responsible for the logic of evaluating the information. The TA executes tests as a series of async methods pulled from a Queue. * **Gradebook**. Every TA has an instance of a Gradebook, which determines the pass/fail state of a test. Some tests have multiple parts (eg. examining every element of some class to ensure that all have a blue background - each element is a part of the test). The Gradebook compares the parts to the comparison functions as set by the TA and decides if the test has passed or failed. * **Target**. A Target represents a single piece of information pulled from the DOM. *Almost* every Target has an associated `element` and some `value`. Targets may include child Targets. Tests that result in multiple pieces of information create a tree of Targets (sometimes called a 'Bullseye' in comments). * **Suite** and **ActiveTest**. An individual test (ie. one line in the widget) is an instance of an ActiveTest. ActiveTests are organized into Suites. Each Suite comes with its own name, which is displayed above its set of tests in the widget. * **Registrar**. This file contains the logic for creating new tests when the Feedback is turned on and removing tests when the Feedback is turned off. * The `` and everything inside of it were built as custom elements with HTML imports. ### Development Workflow 1. Run `gulp watch` from `/` 2. Make changes. 3. Open `/sample/index.html` to run regression testing. 4. If you're adding a new feature: * Add new passing and failing tests to `/sample/tests.json` (and modify `/sample/index.html` if necessary). * Update this README to reflect changes (include examples!). 5. Submit a pull request! Did you read this far? You're awesome :) # Archival Note This repository is deprecated; therefore, we are going to archive it. However, learners will be able to fork it to their personal Github account but cannot submit PRs to this repository. If you have any issues or suggestions to make, feel free to: - Utilize the https://knowledge.udacity.com/ forum to seek help on content-specific issues. - Submit a support ticket along with the link to your forked repository if (learners are) blocked for other reasons. Here are the links for the [retail consumers](https://udacity.zendesk.com/hc/en-us/requests/new) and [enterprise learners](https://udacityenterprise.zendesk.com/hc/en-us/requests/new?ticket_form_id=360000279131). ================================================ FILE: chromium/README.md ================================================ ## Chromium interface ### Description This directory contains files needed to build the extension for Chromium based browsers (Google Chrome). ### Prerequisites Chrome natively support the WebExtensions API. Really old versions may even be supported. ### License This directory and the whole project is subject to the [GPLv3 License](../license). ================================================ FILE: chromium/browser_action/intro.js ================================================ /** * @fileOverview This file contains the Chromium opening statements for the browser action script prepended to the main file. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ // intro.js ends here ================================================ FILE: chromium/browser_action/outro.js ================================================ /** * @fileOverview This file contains the Chromium closing statements for the browser action script appended to the main file. * @name outro.js * @author Etienne Prud’homme * @license GPLv3 */ // outro.js ends here // browser_action.js ends here ================================================ FILE: chromium/inject/intro.js ================================================ /** * @fileOverview This file contains the Chromium opening statements for the content script prepended to the main file. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ // intro.js ends here ================================================ FILE: chromium/inject/outro.js ================================================ /** * @fileOverview This file contains the Chromium closing statements for the content script appended to the main file. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ // outro.js ends here // inject.js ends here ================================================ FILE: chromium/manifest.json ================================================ { "name": "Udacity Front End Feedback", "short_name": "Udacity Feedback", "version": "0.3.0", "manifest_version": 2, "description": "Immediate, visual feedback about any website's HTML, CSS and JavaScript", "homepage_url": "http://github.com/udacity/frontend-grading-engine", "icons": { "16": "icons/icon.png", "32": "icons/Icon-32.png", "48": "icons/Icon-48.png", "64": "icons/Icon-64.png", "128": "icons/Icon-128.png" }, "options_page": "app/options/index.html", "browser_action": { "default_icon": "icons/Icon-48.png", "default_title": "Udacity Feedback", "default_popup": "app/browser_action/browser_action.html" }, "permissions": [ "tabs", "storage" ], "content_scripts": [ { "matches": [ "http://*/*", "https://*/*", "file://*/*" ], "js": [ "app/js/inject.js" ] } ], "web_accessible_resources": [ "app/js/*.js", "app/js/libs/GE.js", "app/js/libs/jsgrader.js", "app/templates/templates.js", "lib/components.js" ] } ================================================ FILE: chromium/options/intro.js ================================================ /** * @fileOverview This file contains the Chromium opening statements for the options page script prepended to the main file. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ var browserName = 'Chrome'; // intro.js ends here ================================================ FILE: chromium/options/outro.js ================================================ /** * @fileOverview This file contains the Chromium closing statements for the options page script appended to the main file. * @name outro.js * @author Etienne Prud’homme * @license GPLv3 */ // outro.js ends here // options.js ends here ================================================ FILE: firefox/README.md ================================================ ## Firefox interface ### Description This directory contains files needed to build the extension for Firefox based browsers (may include IceWeasel or IceCat). While the WebExtensions API is well supported in Chromium, Firefox needs to have specific quirks. ### Incompatibilities Because Firefox doesn’t yet support some features and that backward compatibility was preferred, here are some issues: * Firefox doesn’t support the `sync` `StorageArea` (i.e. `chrome.storage.sync.*`). A wrapper was made to instead `local` `StorageArea`. - Before version 48, Firefox didn’t support the `chrome.storage` API in _content scripts_. The above wrapper is replaced with a message channel between the _event page_ (background page) and the _content script_. * Before version 48, Firefox didn’t support the _options page_ (or `options\_ui`). An icon is added in the _action page_ to access a page to modify the settings. That’s currently the only way to access the options prior to version 48. * Firefox and Chromium don’t seem to handle promises the same way. For example, Firefox couldn’t load the JSON tests before the execution of unit tests. ### Prerequisites Firefox 45 or higher is needed to support WebExtensions. ### Building * TODO ## License This directory and the whole project is subject to the [GPLv3 License](../license). ================================================ FILE: firefox/background.js ================================================ /*global chrome */ /** * @fileOverview This file adds support for the {@link chrome.storage.local} API in Firefox. This API isn’t implemented until Firefox version 48 for content-scripts. * @name background.js * @author Etienne Prud’homme * @license GPLv3 */ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { // debugger; // console.group(); // console.log("sendResponse = ", sendResponse.toString()); // console.log("sender = ", sender); // console.log("message = ", message); // console.groupEnd(); if(!message) { Promise.reject(); } switch(message.type) { case 'chrome.storage.local.get': chrome.storage.local.get(message.data, function(response) { // debugger; sendResponse(response); }); break; case 'chrome.storage.local.set': chrome.storage.local.set(message.data, function(response) { // debugger; response = chrome.runtime.lastError ? {status: 1, error: chrome.runtime.lastError.message} : {status: 0}; sendResponse(response); }); break; }; return true; }); // background.js ends here ================================================ FILE: firefox/browser_action/intro.js ================================================ /*global chrome */ /** * @fileOverview This file contains the Firefox opening statements for the browser action script prepended to the main file. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ chrome.runtime.openOptionsPage = function() { chrome.tabs.create({url: chrome.extension.getURL('app/options/index.html')}); }; // intro.js ends here ================================================ FILE: firefox/browser_action/outro.js ================================================ /** * @fileOverview This file contains the Firefox closing statements for the content script appended to the main file. * @name outro.js * @author Etienne Prud’homme * @license GPLv3 */ // outro.js ends here // browser_action.js ends here ================================================ FILE: firefox/inject/intro.js ================================================ /*global chrome */ /** * @fileOverview This file contains the Firefox opening statements for the content script prepended to the main file. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ // chrome = browser; chrome.storage = { sync: { /** * Gets one or more items from storage. * @param {string|string[]|object} [keys] - A single key to get, list of keys to get, or a dictionary specifying default values (see description of the object). An empty list or object will return an empty result object. Pass in null to get the entire contents of storage * @param {function} callback - Callback with storage items, or on failure (in which case runtime.lastError will be set). */ get: function(keys, callback) { // debugger; // console.log(callback); // console.log(callback.toString()); var message = {}; message.data = keys; message.type = 'chrome.storage.local.get'; chrome.runtime.sendMessage(null, message, {}, localHandleGet); function localHandleGet(response) { // debugger; // console.log('localHandleGet'); callback(response); } }, set: function(object, callback) { // debugger; // console.log("chrome.storage.sync.set object = ", object); var message = {}; message.type = 'chrome.storage.local.set'; message.data = object; chrome.runtime.sendMessage(null, message, {}, localHandleSet); function localHandleSet(response) { // debugger; // console.log('localHandleSet'); if(response.status) { throw new Error('Error: ' + response.message); } callback(); } } } }; // intro.js ends here ================================================ FILE: firefox/inject/outro.js ================================================ /** * @fileOverview This file contains the Firefox closing statements for the content script appended to the main file. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ // outro.js ends here // inject.js ends here ================================================ FILE: firefox/manifest.json ================================================ { "name": "Udacity Front End Feedback", "version": "0.3.0", "applications": { "gecko": { "id": "udacityfeedback@udacity.com", "strict_min_version": "45.0" } }, "manifest_version": 2, "description": "Immediate, visual feedback about any website's HTML, CSS and JavaScript", "homepage_url": "http://github.com/udacity/frontend-grading-engine", "icons": { "16": "icons/icon.png", "32": "icons/Icon-32.png", "48": "icons/Icon-48.png", "64": "icons/Icon-64.png", "128": "icons/Icon-128.png" }, "options_ui": { "page": "app/options/index.html" }, "browser_action": { "default_icon": "icons/Icon-48.png", "default_title": "Udacity Feedback", "default_popup": "app/browser_action/browser_action.html" }, "background": { "scripts": ["background.js"] }, "permissions": [ "tabs", "storage" ], "content_scripts": [ { "matches": [ "http://*/*", "https://*/*", "file://*/*" ], "js": [ "app/js/inject.js" ] } ], "web_accessible_resources": [ "app/css/common.css", "app/css/fonts/fontawesome-webfont.ttf", "app/js/libs/GE.js", "app/js/libs/jsgrader.js", "app/templates/templates.js", "lib/components.js" ] } ================================================ FILE: firefox/options/intro.js ================================================ /*global chrome, browser */ /** * @fileOverview This file contains the Firefox opening statements for the options page script prepended to the main file. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ var browserName = 'Firefox'; chrome = browser; chrome.storage = { sync: { /** * Gets one or more items from storage. * @param {string|string[]|object} [keys] - A single key to get, list of keys to get, or a dictionary specifying default values (see description of the object). An empty list or object will return an empty result object. Pass in null to get the entire contents of storage * @param {function} callback - Callback with storage items, or on failure (in which case runtime.lastError will be set). * @returns {} */ get: function(keys, callback) { // debugger; // console.log(callback); // console.log(callback.toString()); var message = {}; message.data = keys; message.type = 'chrome.storage.local.get'; chrome.runtime.sendMessage(null, message, {}, localHandleGet); function localHandleGet(response) { // debugger; // console.log('localHandleGet'); callback(response); } }, set: function(object, callback) { // debugger; // console.log("chrome.storage.sync.set object = ", object); var message = {}; message.type = 'chrome.storage.local.set'; message.data = object; chrome.runtime.sendMessage(null, message, {}, localHandleSet); function localHandleSet(response) { // debugger; // console.log('localHandleSet'); if(response.status) { throw new Error('Error: ' + response.message); } callback(); } } } }; // intro.js ends here ================================================ FILE: firefox/options/outro.js ================================================ /** * @fileOverview This file contains the Firefox closing statements for the options page script appended to the main file. * @name outro.js * @author Etienne Prud’homme * @license GPLv3 */ // outro.js ends here // options.js ends here ================================================ FILE: gulpfile.js ================================================ var gulp = require('gulp'); var gulpsync = require('gulp-sync')(gulp); var watch = require('gulp-watch'); var concat = require('gulp-concat'); var debug = require('gulp-debug'); var batch = require('gulp-batch'); // var uglify = require('gulp-uglify'); var clean = require('gulp-clean'); var mv = require('mv'); var currentBrowser; var build = './build/%target%/ext/'; var log = function(message) { console.log('\x1b[37;46m#### ' + message + '\x1b[0;m'); }; function setBrowser(browser) { currentBrowser = browser; return log('Set ' + currentBrowser + ' as the current browser'); } var pageFiles = { gradingEngine: { src: [ 'src/js/intro.js', 'src/js/helpers.js', 'src/js/Queue.js', 'src/js/Target.js', 'src/js/GradeBook.js', 'src/js/TACollectors.js', 'src/js/TAReporters.js', 'src/js/ActiveTest.js', 'src/js/Suite.js', 'src/js/registrar.js', 'src/js/outro.js' ], libraries: { src: 'src/app/js/libs/*.js', dest: build + 'app/js/libs/' }, concat: 'GE.js', dest: build + 'app/js/libs/' }, libraries: { src: 'lib/*', dest: build + 'lib/' }, background: { js: { src: [ '%target%/background.js' ], concat: 'background.js' }, dest: build }, inject: { src: [ '%target%/inject/intro.js', 'src/app/js/inject/helpers.js', 'src/app/js/inject/StateManager.js', 'src/app/js/inject/inject.js', '%target%/inject/outro.js' ], concat: 'inject.js', dest: build + 'app/js/' }, templates: { src: [ 'src/app/test_widget/font.js', 'src/app/test_widget/test_suite.js', 'src/app/test_widget/test_results.js', 'src/app/test_widget/active_test.js', 'src/app/test_widget/test_widget.js' ], concat: 'templates.js', dest: build + 'app/templates/' }, // Safari background script globalPage: { js: { src: [ '%target%/background/helpers.js', '%target%/background/registry.js', '%target%/background/adapter.js', '%target%/background/adapterListener.js', '%target%/background/background.js' ], concat: 'background.js' }, html: { src: [ '%target%/background/background.html' ], concat: 'background.html' }, dest: build } }; var gradingEngine = pageFiles.gradingEngine; // Third-party libraries var libraries = pageFiles.libraries; var geLibs = gradingEngine.libraries; var background = pageFiles.background; var global = pageFiles.globalPage; var inject = pageFiles.inject; var templates = pageFiles.templates; var browserPageFiles = { pageAction: { html: 'src/app/browser_action/browser_action.html', js: { src: [ '%target%/browser_action/intro.js', 'src/app/browser_action/browser_action.js', '%target%/browser_action/outro.js' ], concat: 'browser_action.js' }, dest: build + 'app/browser_action/' }, pageOptions: { html: 'src/app/options/index.html', js: { src: [ '%target%/options/intro.js', 'src/app/options/options.js', '%target%/options/outro.js' ], concat: 'options.js' }, dest: build + 'app/options/' } }; var pageAction = browserPageFiles.pageAction; var pageOptions = browserPageFiles.pageOptions; var iconFiles = { src: [ 'src/icons/icon.png', 'src/icons/Icon-32.png', 'src/icons/Icon-48.png', 'src/icons/Icon-64.png', 'src/icons/Icon-128.png' ], dest: build + 'icons/' }; var styleFiles = { src: [ 'src/app/css/common.css', 'src/app/css/fonts.css', 'src/app/css/ui.css', 'src/app/css/options.css' ], dest: build + 'app/css/' }; var fontFiles = { src: 'src/app/css/fonts/fontawesome-webfont.ttf', dest: build + 'app/css/fonts/' }; // Files to watch var allFiles = gradingEngine.src.concat(templates.src, inject.src, background.js.src, global.js.src); // "GE" = Build the GradingEngine library. gulp.task('GE', function() { return gulp.src(gradingEngine.src) .pipe(concat(gradingEngine.concat)) .pipe(gulp.dest(gradingEngine.dest)) .pipe(debug({title: 'built the grading engine:'})); }); // "GE_libs" = Copy libraries of the Grading Engine. gulp.task('GE_libs', function() { return gulp.src(geLibs.src) .pipe(gulp.dest(geLibs.dest)) .pipe(debug({title: 'copied grading engine libraries:'})); }); // "libraries" = Copy third-party libraries. gulp.task('libraries', function() { return gulp.src(libraries.src) .pipe(gulp.dest(libraries.dest)) .pipe(debug({title: 'copied libraries:'})); }); // "templates" = Generate the native templates. There were // previously Web Templates. gulp.task('templates', function() { return gulp.src(templates.src) .pipe(concat(templates.concat)) .pipe(gulp.dest(templates.dest)) .pipe(debug({title: 'built templates: '})); }); // "inject" = Generate the inject script for the current browser and copy. gulp.task('inject', function() { var files = inject.src.map(function(x) { return x.replace('%target%', currentBrowser); }); return gulp.src(files) .pipe(concat(inject.concat)) .pipe(gulp.dest(inject.dest)) .pipe(debug({title: 'built inject.js:'})); }); /*** PAGEACTION ***/ // "_pageAction_html" = Copy HTML options page. gulp.task('_pageAction_html', function() { return gulp.src(pageAction.html) .pipe(gulp.dest(pageAction.dest)) .pipe(debug({title: 'copied action page:'})); }); // "_pageAction_js" = Generate the pageAction script for the current browser and copy. gulp.task('_pageAction_js', function() { var files = pageAction.js.src.map(function(x) { return x.replace('%target%', currentBrowser); }); return gulp.src(files) .pipe(concat(pageAction.js.concat)) .pipe(gulp.dest(pageAction.dest)) .pipe(debug({title: 'built action page script:'})); }); // "pageAction" = Copy the `browser_action` files. gulp.task('pageAction', ['_pageAction_html', '_pageAction_js']); /*** PAGEACTION ends here ***/ /*** PAGEOPTIONS ***/ // "_pageOptions_html" = Copy HTML options page. gulp.task('_pageOptions_html', function() { return gulp.src(pageOptions.html) .pipe(gulp.dest(pageOptions.dest)) .pipe(debug({title: 'copied options page:'})); }); // "_pageOptions_js" = Generate the pageAction script for the current browser and copy. gulp.task('_pageOptions_js', function() { var files = pageOptions.js.src.map(function(x) { return x.replace('%target%', currentBrowser); }); return gulp.src(files) .pipe(concat(pageOptions.js.concat)) .pipe(gulp.dest(pageOptions.dest)) .pipe(debug({title: 'built options page script:'})); }); // "pageOptions" = Copy the options page. gulp.task('pageOptions', ['_pageOptions_html', '_pageOptions_js']); /*** PAGEOPTIONS ends here ***/ // "icons" = Copy icons. gulp.task('icons', function() { if(currentBrowser === 'safari') { iconFiles.src.push('safari/toolbar_icon.png'); iconFiles.dest = build; } return gulp.src(iconFiles.src) .pipe(gulp.dest(iconFiles.dest)) .pipe(debug({title: 'copied icons:'})); }); // "styles" = Copy styles. gulp.task('styles', function() { return gulp.src(styleFiles.src) .pipe(gulp.dest(styleFiles.dest)) .pipe(debug({title: 'copied styles:'})); }); // "fonts" = Copy fonts. gulp.task('fonts', function() { return gulp.src(fontFiles.src) .pipe(gulp.dest(fontFiles.dest)) .pipe(debug({title: 'copied fonts:'})); }); // "assets" = Executes tasks for static assets. gulp.task('assets', ['icons', 'styles', 'fonts']); // "app" = Executes tasks for the app (view). gulp.task('app', ['templates', 'inject', 'pageAction', 'pageOptions', 'assets']); // "extension" = Executes tasks that are mostly not browser specific. gulp.task('extension', ['app', 'GE', 'GE_libs', 'libraries']); // "background-script" = Copy the background script for the // `currentBrowser` (if any). gulp.task('background-script', function() { var _background = currentBrowser === 'safari' ? global : background; _background.js.src = _background.js.src.map(function(x) { return x.replace('%target%', currentBrowser); }); log(_background); return gulp.src(_background.js.src) .pipe(concat(_background.js.concat)) .pipe(gulp.dest(_background.dest)) .pipe(debug({title: 'copied ' + currentBrowser + '’s background script:'})); }); // "background-page" = Copy the background page for the // `currentBrowser` (if any). gulp.task('background-page', function() { var _background = currentBrowser === 'safari' ? global : background; _background.html.src = _background.html.src.map(function(x) { return x.replace('%target%', currentBrowser); }); return gulp.src(_background.html.src) .pipe(concat(_background.html.concat)) .pipe(gulp.dest(_background.dest)) .pipe(debug({title: 'copied ' + currentBrowser + '’s background page:'})); }); // "manifest" = Copy the manifest for the current browser gulp.task('manifest', function() { // Safari doesn’t have a `manifest.json`, but an `Info.plist` var manifest = currentBrowser === 'safari' ? 'Info.plist' : 'manifest.json'; return gulp.src(currentBrowser + '/' + manifest) .pipe(gulp.dest(build)) .pipe(debug({title: 'copied ' + currentBrowser +'’s manifest:'})); }); // "_chromium" = Sets currentBrowser to chromium. gulp.task('_chromium', function() { return setBrowser('chromium'); }); // "_firefox" = Sets currentBrowser to firefox gulp.task('_firefox', function() { return setBrowser('firefox'); }); // "_safari" = Sets currentBrowser to safari gulp.task('_safari', function() { return setBrowser('safari'); }); // "move-build" = Move build files to its target directory. gulp.task('move-build', function() { var browserBuild = build.replace('%target%/ext/', currentBrowser + '/'); mv(build.replace('ext/', ''), browserBuild, {mkdirp: true}, function(err) { console.log(err); }); return log('Moved ' + currentBrowser + ' files to: ' + browserBuild); }); // "chromium" = Run chromim dependencies to build the extension. gulp.task('chromium', gulpsync.sync(['_chromium', ['manifest', 'extension'], 'move-build'])); // "firefox" = Run Firefox dependencies to build the extension. gulp.task('firefox', gulpsync.sync(['_firefox', ['manifest', 'background-script', 'extension'], 'move-build'])); // "safari" = Run Safari dependencies to build the extension. gulp.task('safari', gulpsync.sync(['_safari', ['manifest', 'background-script', 'background-page', 'extension'], 'move-build'])); // "clean" = Clean the build directory. Otherwise `mv` would throw an error. gulp.task('clean', function() { log('Cleaned the build directory'); return gulp.src('./build/', {read: false}) .pipe(clean()) .pipe(debug({title: 'cleaned ' + build})); }); gulp.task('default', gulpsync.sync(['clean', 'firefox', 'chromium', 'safari'])); gulp.task('watch', function() { gulp.start('default'); watch(allFiles, batch(function(events, done) { gulp.start('default', done); })); }); ================================================ FILE: lib/components.js ================================================ /*global MutationObserver */ /** * @fileOverview This file contains the /components/ module for emulating Web Components behavior. * @name components.js * @author Etienne Prud’homme * @version 1.0.0 * @link https://github.com/notetiene/components * @license GPLv3 */ var components=function(){var e={},t=document.createRange();t.selectNode(document.body);var r=function(t,r,n){if(t.constructor!==String||""===t)throw new Error("Cannot register the component. The name must be a String.");if(r.constructor!==String||""===r)throw new Error("Cannot register "+t+" component. The template must be a String.");if(void 0!==e[t]&&e.hasOwnProperty(t))throw new Error(t+" is an already registered component.");var o=n||{};Object.defineProperty(e,t,{enumerable:!1,configurable:!1,writable:!1,value:{template:r,proto:o}})},n=function(r){if(!e.hasOwnProperty(r))throw new Error("“"+r+"” is not a registered component");for(var n=e[r],o=t.createContextualFragment(n.template),a=null,i=0,c=o.childNodes.length;i Builder Version 11601.7.7 CFBundleDisplayName Udacity Feedback CFBundleIdentifier com.udacity.frontend-grading-engine CFBundleInfoDictionaryVersion 6.0 CFBundleShortVersionString 0.3.0 CFBundleVersion 0.3.0 Update From Gallery Chrome Global Page background.html Popovers Filename app/browser_action/browser_action.html Identifier browserActionPage Toolbar Items Identifier actionPageButton Image toolbar_icon.png Include By Default Label Udacity Feedback Popover browserActionPage Tool Tip Udacity Feedback Content Scripts End app/js/inject.js DeveloperIdentifier AT7S4C746C ExtensionInfoDictionaryVersion 1.0 Permissions Website Access Include Secure Pages Level All ================================================ FILE: safari/README.md ================================================ ## Safari Interface ### Description This directory contains files needed to build the extension for Safari. The goal is to make a WebExtension [adapter](https://en.wikipedia.org/wiki/Adapter_pattern) to reduce modification of the current code base. ### Architecture #### Execution Context ##### Injected Scripts The extension API of Safari differs substantially from the WebExtension API. The extension architecture is similar to other browsers in that it allows scripts (injected script) to be injected with a limited API access. In that matter, it could be compared to _content scripts_. There’s one script instance per tab (depending on injection condition). Only injected scripts can have access to the DOM while getting a different global execution context other than the `window` object. ##### Global Page The extension allows to have an execution context with full access to the safari API (global page). However, this global execution context doesn’t have access to a webpage content (which is injected scripts’ role). The role of a _global page_ is to share its access of the API on demand. Injected scripts have to send a serialized message to the global page to trigger a custom action. Because it’s a message passing system, passed functions won’t be executed in their canonical way (not in their String representation). #### User Interface Components Safari has UI components that are similar to what WebExtension provides (e.g. _browser action_), but outside of the _browser action_ component, they differ significantly in their behaviour. Popovers have the same behaviour as _browser action_ page would. The global page _global executing context_ can be accessed with the `safari.extension.globalPage.contentWindow` namespace. To avoid making two adapters, the _global page_ adapter will be used. #### Safari Incompatibilities ##### Storage Safari doesn’t support extension storage. Instead, we need to use the `safari.extension.settings` property to set an inner object representing the storage object to use. ##### Tabs and Windows Safari doesn’t provide a method to uniquely identify a window or a tab. The adapter adds a module called `registry` that assign an ID to each window or tab. It also provides several functions to retrieve a list of tabs or windows. ### License This directory and the whole project is subject to the [GPLv3 License](../license). ================================================ FILE: safari/background/REAMDE.md ================================================ ## Safari Global Page The files in this directory get concatenated into `global.js`. It is somehow similar to what the WebExtensions background page does. Because the Safari uses its own extension API, most of the work to port this extension to Safari is in providing a WebExtensions adapter. ================================================ FILE: safari/background/adapter.js ================================================ /*global registry, safari, extensionLog */ /** * @fileOverview This file contains the adaptee (Adapter inner working) for emulating the WebExtension API. * @name adapter.js * @author Etienne Prud’homme * @license GPLv3 * * Injected Scripts don’t have access to the `chrome.*` API with the exception * of: * * `extension` (`getURL`, `inIncognitoContext`, `lastError`, `onRequest`, * `sendRequest`) * * `i18n` * * `runtime` (`connect`, `getManifest`, `getURL`, `id`, `onConnect`, * `onMessage`, `sendMessage`) * * `storage` * * This is wĥy this background script is created. */ /** * Adaptee that translates chrome method behavior to safari. * @namespace * @property {error} wrapper.runtime.lastError - Set for the lifetime of a callback if an ansychronous extension api has resulted in an error. If no error has occured lastError will be undefined. */ var wrapper = { storage: { sync: { /** * Emulates the chrome storage behavior (getter) by using the {@link safari.extension.settings} mechanism. * @param {string|string[]|object} keys - A single key to get, list of keys to get, or a dictionary specifying default values (see description of the object). An empty list or object will return an empty result object. Pass in null to get the entire contents of storage. * @todo transform to a Promise * @returns {object} Object with items in their key-value mappings. * @throws {error} Error in the {@link keys} argument and sets {@link wrapper.runtime.lastError}. */ get: function(keys) { var i, len, key, items = {}; try { if(!keys) { if(keys === null) { items = safari.extension.settings; } else { // Only `null` can return values, otherwise it’s an empty Object items = {}; } } else if(keys instanceof String || typeof keys === 'string') { items[keys] = safari.extension.settings[keys]; } else if(keys instanceof Array && keys.length > 0) { items = {}; for(i=0, len=keys.length; i ends here ================================================ FILE: safari/background/adapterListener.js ================================================ /*global wrapper, safari */ /** * @fileOverview This file contains the adapter listener (i.e. message * passing part) for injected scripts since most of the adaptee * methods need higher priviledge (but allowed from a global page). * @name adapterListener.js * @author Etienne Prud’homme * @license GPLv3 */ // Listens to the client adapter safari.application.addEventListener('message', function(event) { var status = -1; var message = JSON.parse(event.message); // Safari uses ev.name for the name of the event while using // /message/ for communication between scripts. switch(event.name) { case 'wrapper.storage.sync.get': // Returns -1 on error otherwise the response status = wrapper.storage.sync.get(message.keys); respondBack('injected.storage.sync.get', status); break; case 'wrapper.storage.sync.set': // Returns -1 on error otherwise the response status = wrapper.storage.sync.set(message.keys); respondBack('injected.storage.sync.set', status); break; case 'wrapper.runtime.sendMessage': // TODO // Returns -1 on error otherwise the response status = wrapper.runtime.sendMessage(); respondBack('injected.runtime.sendMessage', status); break; case 'wrapper.tabs.query': // Returns -1 on error otherwise the responsenn status = wrapper.tabs.query(message.query); // Note: The docs don’t officially specify throwing lastError respondBack('injected.tabs.query', status); break; } /** * Function that sends back the result of the request and also take * cares of status codes. * @param {string} channel - The name of the request receiver. * @param {int|Object} status - The response of a query. On error, * it should be `-1`. */ function respondBack(channel, status) { var response; if(status === -1) { response = {name: 'error', response: wrapper.runtime.lastError.message}; } else { response = {name: 'ok', response: status}; } event.target.page.dispatchMessage(channel, JSON.stringify(response)); } // Since its lifetime is for a callback wrapper.runtime.lastError = undefined; }, false); // adapterListener.js ends here ================================================ FILE: safari/background/background.html ================================================ Background Page ================================================ FILE: safari/background/background.js ================================================ /*global safari, SafariBrowserTab, SafariBrowserWindow, wrapper, extensionLog */ /** * @fileOverview This file adds support for the Chrome API in the global page * script context. * @name background.js * @author Etienne Prud’homme * @license GPLv3 */ // Initializes the logs if not created safari.extension.settings.logs = safari.extension.settings.logs || []; /** * Chrome adapter module for the global page context. * @returns {object} The chrome namespace. * @throws {Error} TO FIX. We should set `lastError` instead. */ var global = (function() { var exports = { tabs: { /** * Sends a single message to the content script(s) in the specified tab, * with an optional callback to run when a response is sent back. The * {@link global.runtime.onMessage} event is fired in each content script * running in the specified tab for the current extension. * @param {int} tabId - The tab to send the message to. * @param {*} message - Any object that can be serialized. * @param {object} [options] * @param {int} [options.frameId] - Send a message to a specific frame * identified by {@link frameId} instead of all frames in the tabn. * @param {global.tabs.sendMessage~responseCallback} [responseCallback] - * Function called when there’s a response. Note: The response can be any * object. */ sendMessage: function(tabId, message, options, responseCallback) { var channel = Math.floor(Math.random() * 100000000); wrapper.tabs.sendMessage(tabId, message, options, channel) .then(function(response) { if(typeof(responseCallback) === typeof(Function)) { responseCallback(response); } }).catch(function(reason) { extensionLog(reason); }); }, /** * @namespace * @property {int} [id] - The ID of the tab. Tab IDs are unique within a * browser session. Under some circumstances a Tab may not be assigned an * ID, for example when querying foreign tabs using the sessions API, in * which case a session ID may be present. * @property {int} index - The zero-based index of the tab within its * window. * @property {int} windowId - The ID of the window the tab is contained * within. * @property {int} [openerTabId] - The ID of the tab that opened this tab, * if any. This property is only present if the opener tab still exists. * @property {bool} highlighted - Whether the tab is highlighted. * @property {bool} active - Whether the tab is active in its * window. (Does not necessarily mean the window is focused.) * @property {bool} pinned - Whether the tab is pinned. * @property {string} [url] - The URL the tab is displaying. This property * is only present if the extension’s manifest includes the “tabs” * permission. * @property {string} [title] - The title of the tab. This property is * only present if the extension’s manifest includes the “tabs” * permission. * @property {string} [favIconUrl] - The URL of the tab's favicon. This * property is only present if the extension's manifest includes the * "tabs" permission. It may also be an empty string if the tab is * loading. * @property {string} [status] - Either loading or complete. * @property {bool} incognito - Whether the tab is in an incognito window. * @property {int} width - The width of the tab in pixels. * @property {int} height - The height of the tab in pixels. * @property {string} sessionId - The session ID used to uniquely identify * a Tab obtained from the sessions API. */ Tab: { id: null, index: null, windowId: null, openerTabId: null, highlighted: null, active: null, pinned: null, url: null, title: null, favIconUrl: null, status: null, incognito: null, width: null, height: null, sessionId: null }, /** * Whether the tabs have completed loading. * @readonly * @enum {string}n */ tabStatus: { loading: 'loading', complete: 'complete' }, /** * The type of window. * @readonly * @enum {string} */ windowType: { normal: 'normal', popup: 'popup', panel: 'panel', app: 'app', devtool: 'devtool' }, /** * Gets all tabs that have the specified properties, or all tabs if no * properties are specified. * @param {object} queryInfo * @param {bool} [queryInfo.active] - Whether the tabs are active in their * windows. * @todo @param {bool} [queryInfo.pinned] - Whether the tabs are pinned. * @todo @param {bool} [queryInfo.highlighted] - Whether the tabs are * highlighted. * @param {bool} [queryInfo.currentWindow] - Whether the tabs are in the * /current window/. * @todo @param {bool} [queryInfo.lastFocusedWindow] - Whether the tabs * are in the last focused window. * @todo @param {tabStatus} [queryInfo.status] - Whether the tabs have * completed loading. * @todo @param {string} [queryInfo.title] - Match page titles against a * pattern. * @todo @param {string|string[]} [queryInfo.url] - Match tabs against one * or more /URL patterns/. Note that fragment identifiers are not matched. * @param {int} [queryInfo.windowId] - The ID of the parent window, or * {@link global.windows.WINDOW_ID_CURRENT} for the current window. * @todo @param {windowType} [queryInfo.windowType] - The type of window * the tabs are in. * @todo @param {int} [queryInfo.index] - The position of the tabs within * their windows. * @param {global.tabs.query~callback} callback - Threats returned tabs. */ query: function(queryInfo, callback) { try { var values = wrapper.tabs.query(queryInfo); if(typeof(callback) === typeof(Function)) { callback(values); } else { console.warn('No callback function is provided'); } } catch(e) { throw e; } } }, runtime: { /** * Get keys from the `Info.plist` file. Only `version` is currently supported. * @returns {Object} Object containing the manifest properties. */ getManifest: function() { return { version: safari.extension.displayVersion }; }, lastError: null, openOptionsPage: function() { // Find the active popover var popovers = safari.extension.popovers; // TODO: Find the last active popover for(var i=popovers.length; --i >= 0;) { // If none is found to be visible, te index 0 is taken if(popovers[i].visible === true || i === 0) { // Note: contentWindow is referring to the popover window itself popovers[i].contentWindow.location.href = safari.extension.baseURI + 'app/options/index.html'; } } } }, storage: { sync: { /** * Gets one or more items from storage. * @param {string|string[]|object} [keys] - A single key to get, list * of keys to get, or a dictionary specifying default values (see * description of the object). An empty list or object will return an * empty result object. Pass in null to get the entire contents of * storage. * @param {injected.storage.sync.get~callback} callback - Callback * with storage items, or on failure (in which case * {@link injected.runtime.lastError} will be set). * @returns {object} Object with items in their key-value mappings. */ get: function(keys, callback) { var values = wrapper.storage.sync.get(keys); if(typeof (callback) === typeof(Function)) { callback(values); } }, /** * Sets multiple items. * @param {object} keys - An object which gives each key/value pair to * update storage with. Any other key/value pairs in storage will not * be affected. * * Primitive values such as numbers will serialize as expected. Values * with a typeof `object` and `function` will typically serialize to * `{}`, with the exception of `Array` (serializes as expected), Date, * and Regex (serialize using their `String` representation). * @param {injected.storage.sync.set~callback} [callback] - Callback * on success, or on failure (in which case * {@link injected.runtime.lastError} will be set). */ set: function(keys, callback) { wrapper.storage.sync.set(keys); if(typeof(callback) === typeof(Function)) { callback(); } } } } }; // The module was intialized exports.initialized = true; return exports; })(); var chrome = global; // background.js ================================================ FILE: safari/background/helpers.js ================================================ /*global safari */ /** * @fileOverview This file adds utility functions for the Safari global page. * @name helpers.js * @author Etienne Prud’homme * @license GPL */ /** * Store logging informations in the extension settings. * @param {string|error} message - The message to log as a String or an Error. * @throws {Error} Error in the arguments of the function (not a String nor an * Error). */ function extensionLog(log) { // Cache logs to append a single log var logs = safari.extension.settings.logs; var stack, logMessage; if(log instanceof Error) { logMessage = log.message; stack = log.stack; } else if (logMessage instanceof String || typeof logMessage === 'string') { logMessage = log; stack = new Error().stack; } else { // Log error of itself extensionLog('Invalid log type: ' + log.toString()); throw new Error('Extension logging error'); } // Adding the new log logs.push({ message: logMessage, stack: stack, timestamp: Date.now() / 1000 }); // Record the new logs safari.extension.settings.logs = logs; // This should be in the Background script and shouldn’t conflict with page // scripts console.warn(log); // Actually throw that error if(log instanceof Error) { throw log; } } // helpers.js ends here ================================================ FILE: safari/background/registry.js ================================================ /** * @fileOverview This adds a module to record windows and tabs in * Safari. Otherwise, there’s no way to select a tab (or window) with an ID. * @name registry.js * @author Etienne Prud’homme * @license GPLv3 */ /** * Registers Tabs and Windows. */ var registry = (function() { var _windows = { activeWindow: null, lastFocusedWindow: null }; var _tabs = {}; var exports = {}; /** * Returns registered windows from {@link _windows}. * @returns {SafariBrowserWindow[]} Registered windows. */ exports.getWindows = function() { return _windows; }; /** * Returns registered tabs from {@link _tabs}. * @returns {SafariBrowserTab[]} Registered tabs. */ exports.getTabs = function() { return _tabs; }; /** * Returns the window registered as `active`. It may not conform to the Chrome * specs. * @returns {SafariBrowserWindow} The active window. */ exports.getActiveWindow = function() { return _windows.activeWindow; }; /** * Returns the last window that had focus (activated from Safari * specifications). * @returns {SafariBrowserWindow} The last window that had focus. */ exports.getLastFocused = function() { return _windows.lastFocusedWindow; }; /** * Returns the {@link SafariBrowserTab} corresponding to a given ID. * @param {string|int} id - The ID of the registered tab. * @returns {SafariBrowserTab} The tab that has the given ID or -1 on error. */ exports.getTabById = function(id) { var tab; try { if(_tabs.hasOwnProperty(id)) { tab = _tabs[id]; } else { extensionLog('Invalid tab id: ' + id); } } catch(e) { return -1; } return tab; }; /** * Returns a random property that isn’t found in an Object. * @param {object} obj - Object to find uniqueness of a property name. * @param {object} [options] - Options for generating the property. * @param {int} [options.precision=100000000] - Number that will be multiplied * to a random number between 0 and 1. * @param {int|string} [options.prefix=0] - Number or string that will add the * property to itself. It may add the number vlaue or concatenate the String. * @returns {int} Unique Identifier. */ function getUniqueProperty(obj, options) { var prop, _options = options || {}, precision = _options.precision || 100000000, prefix = _options.prefix || 0; do { prop = prefix + Math.floor(Math.random() * precision); } while(obj.hasOwnProperty(prop) === true); return prop; } // Windows /** * Register a given window by assigning a new random id. When the window is * closed, it removes the id from available windows. * @todo Check if tabs from the registry are also removed when the window is * closed. * @param {SafariBrowserWindow} _window - The new window to register. */ function registerWindow(_window) { var id = ''; if(_window.id === undefined) { id = getUniqueProperty(_windows); // Registered windows _windows[id] = _window; _window.id = id; // _window.addEventListener('close', function handler() { // _window.removeEventListener('close', handler, false); // delete _windows[id]; // }, false); } } /** * Removes the given {@link SafariBrowserWindow} from the registered windows * in {@link _windows}. * @param {SafariBrowserWindow} _window - The window to remove. */ function removeWindow(_window) { var id = _window.id; delete _windows[id]; } /** * Register all available windows with a new random unique id. Its purpose is * to be called on the extension startup. */ function registerWindows() { var browserWindows = safari.application.browserWindows; var id, activeWindow; for(var i=0, len=browserWindows.length; i ends here ================================================ FILE: safari/browser_action/intro.js ================================================ /** * @fileOverview This file contains the opening statements of * `browser_action.js` for the Safari Browser. With this file, a function will * wrap the original `browser_action.js`. It prevents executing the code until * the `chrome` namespace is fully loaded. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ var chrome; /** * Blocks execution until the Chrome namespace is fully loaded. */ /* jshint ignore:start */ function waitChromeNS() { /* jshint ignore:end */ // intro.js ends here ================================================ FILE: safari/browser_action/outro.js ================================================ /*global waitChromeNS, chrome, safari, checkSiteStatus */ /** * @fileOverview This file contains the Safari closing statements for the * browser action page appended to the main file. This file contains a function * executed each 100ms to check if the `chrome` module/namespace is fully * loaded. If it’s already initialized, it assign the _globalPage_ namespace as * `chrome`, otherwise it initializes it. * @name outro.js * @author Etienne Prud’homme * @license GPLv3 */ var main = document.getElementById('main'); main.style.width = '400px'; var label = document.getElementById('ud-label-loader'); label.remove(); safari.application.addEventListener('popover', function() { checkSiteStatus(); }); /* jshint ignore:start */ } /* jshint ignore:end */ var handler = window.setInterval(function() { try { // If the module isn’t initialized, intialize it if(typeof(safari.extension.globalPage.contentWindow.chrome) === typeof(Function)) { chrome = safari.extension.globalPage.contentWindow.chrome(); window.clearInterval(handler); waitChromeNS(); } else { // If the module is initialized, assign the module if(safari.extension.globalPage.contentWindow.chrome.initialized === true) { chrome = safari.extension.globalPage.contentWindow.chrome; window.clearInterval(handler); waitChromeNS(); } else { return; } } } catch(e) { return; } }, 100); // outro.js ends here // browser_action.js ends here ================================================ FILE: safari/inject/intro.js ================================================ /*global safari */ /** * @fileOverview This file contains the opening statements of `inject.js` for * Safari. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ /* jshint ignore:start */ // Injected scripts in Safari get also injected in iFrames if (window.top === window) { /* jshint ignore: end*/ var injected = (function(){ var pageListener = []; /** * @namespace * @property {object} injected.runtime.lastError - This will be defined * during an API method callback if there was an error * @property {string} [injected.runtime.lastError.message] - Details about * the error which occurred. */ var exports = { runtime: { /** * Sends a single message to event listeners within the extension/app or * a different extension/app. Similar to * {@link injected.runtime.onMessage} but only sends a single message, * with an optional response. If sending to your extension, the * {@link injected.runtime.onMessage} event will be fired in each page, * or {@link injected.runtime.onMessageExternal}, if a different * extension. Note that extensions cannot send messages to content * scripts using this method. To send messages to content scripts, use * {@link injected.tabs.sendMessage.} * @param {string} [extensionId] - The ID of the extension to send the * message to. If `undefined` or `null`, the current extension is used. * @param {*} message - The message to sent. * @param {object} [options] * @todo @param {bool} [options.includeTlsChannelId] - Whether the TLS * channel ID will be passed into onMessageExternal for processes that * are listening for the connection event. * @param {injected.runtime.sendMessage~callback} [callback] - Function * called when there’s a response. Note: The response can be any object. */ sendMessage: function(extensionId, message, options, callback) { }, lastError: null, /** * An object containing information about the script context that sent a * message or request. * @namespace * @property {injected.tabs.Tab} [tab] - The {@link injected.tabs.Tab} * which opened the connection, if any. This property will only be * present when the connection was opened from a tab (including content * scripts), and only if the receiver is an extension, not an app. */ MessageSender: { tab: null, frameId: null // id: null, // url: null, // tlsChannelId: null }, onMessage: { /** * Fired when a message is sent from either an extension process or a * content script. * @param {injected.runtime.onMessage.addListener~callback} callback - */ addListener: function(callback) { pageListener.push(callback); } } }, extension: { /** * Converts a relative path within an extension install directory to a * fully-qualified URL. * @param {string} path - A path to a resource within an extension * expressed relative to its install directory. * @returns {string} The fully-qualified URL. */ getURL: function(url) { return safari.extension.baseURI + url; } }, storage: { sync: { /** * Gets one or more items from storage. * @param {string|string[]|object} [keys] - A single key to get, list * of keys to get, or a dictionary specifying default values (see * description of the object). An empty list or object will return an * empty result object. Pass in null to get the entire contents of * storage. * @param {injected.storage.sync.get~callback} callback - Callback * with storage items, or on failure (in which case * {@link injected.runtime.lastError} will be set). * @returns {object} Object with items in their key-value mappings. */ get: function(keys, callback) { askAdapter('wrapper.storage.sync.get', {keys: keys}) .then(function(values) { if(callback instanceof Function) { console.log('In `injected.storage.sync.get` returning: ' + values.toString()); callback(values); } }).catch(function(error) { throw new Error(error); }); }, /** * Sets multiple items. * @param {object} keys - An object which gives each key/value pair to * update storage with. Any other key/value pairs in storage will not * be affected. * * Primitive values such as numbers will serialize as expected. Values * with a typeof `object` and `function` will typically serialize to * `{}`, with the exception of `Array` (serializes as expected), Date, * and Regex (serialize using their `String` representation). * @param {injected.storage.sync.set~callback} [callback] - Callback * on success, or on failure (in which case * {@link injected.runtime.lastError} will be set). */ set: function(keys, callback) { // Send the request askAdapter('wrapper.storage.sync.set', {keys: keys}) .then(function() { if(callback instanceof Function) { callback(); } }).catch(function(error) { throw new Error(error); }); } } } }; /** * Serialize an Object to be supported by Safari when sent as JSON. * @param {object} obj - Any object that will be converted to JSON. It * supports RegExp and Date. * @returns {string} The JSON string. */ function serialize(obj) { // var topObject = true; return JSON.stringify(obj, function(key, value) { // if(topObject) { // topObject = false; // return value; // } if (value instanceof String || value instanceof RegExp || value instanceof Date) { return value.toString(); } else if(value instanceof Array) { return value; } // else if(value instanceof Object && !topObject) { // return {}; // } return value; }); } /** * Sends a message to the adapter function and return a Promise that * resolves when the response is received. * @param {} channel * @param {} message * @returns {Promise} A Promise that resolves when the response is received. */ function askAdapter(channel, message) { return new Promise(function(resolve, reject) { // Register the response receiver before sending the message (else it // won’t be fired) safari.self.addEventListener('message', function responseHandler(ev) { var data = JSON.parse(ev.message); channel = channel.replace('wrapper.', 'injected.'); // Remove self since just ask --> response safari.self.removeEventListener('message', responseHandler); if(ev.name === channel) { if(data.name === 'ok') { resolve(data.response); } else if(data.name === 'error') { // runtime.lastError reject(data.response); } else { reject('The Global Page sent an invalid response'); } } }, false); sendMessageToAdapter(channel, message); }); } function sendMessageToAdapter(channel, message) { var JSONmessage = serialize(message); safari.self.tab.dispatchMessage(channel, JSONmessage); } // The injected script receives messages safari.self.addEventListener('message', function handler(event) { var data = JSON.parse(event.message); // To prevent listening to the same event. It may be useless, but Safari // always have weird behavior. var channel = 0 - parseInt(data.channel); /** * Set to true when a listener call {@link sendResponse}. The Chrome * specs only allow a call to that function. */ var activeResponse = false; // The injected script receives messages from a sendMessage method if(event.name === 'injected.runtime.onMessage' && pageListener.length > 0) { // For each listener, pass the message for(var i=0, len=pageListener.length; i ends here ================================================ FILE: safari/inject/outro.js ================================================ /** * @fileOverview This file contains the closing statements of `inject.js` for * Safari. * @name outro.js * @author Etienne Prud’homme * @license GPLv3 */ /* jshint ignore:start */ } /* jshint ignore:end */ // outro.js ends here // inject.js ends here ================================================ FILE: safari/options/intro.js ================================================ /** * @fileOverview This file contains the Firefox opening statements for the options page script prepended to the main file. * @name intro.js * @author Etienne Prud’homme * @license GPLv3 */ var chrome; var browserName = 'Safari'; /** * Blocks execution until the Chrome namespace is fully loaded. */ /* jshint ignore:start */ function waitChromeNS() { /* jshint ignore:end */ // intro.js ends here ================================================ FILE: safari/options/outro.js ================================================ /*global waitChromeNS, chrome, safari */ /** * @fileOverview This file contains the Firefox closing statements for the options page script appended to the main file. * @name outro.js * @author Etienne Prud’homme * @license GPLv3 */ var backButton = document.getElementById('back-button'); backButton.style.display = 'block'; backButton.addEventListener('click', function handler(event) { window.history.back(); }); // When the popover is closed (it actually loses focus, but it’s still there) window.addEventListener('blur', function() { window.location.reload(); }); /* jshint ignore:start */ } /* jshint ignore:end */ var handler = window.setInterval(function() { try { // If the module isn’t initialized, intialize it if(typeof(safari.extension.globalPage.contentWindow.chrome) === typeof(Function)) { chrome = safari.extension.globalPage.contentWindow.chrome(); window.clearInterval(handler); waitChromeNS(); } else { // If the module is initialized, assign the module if(safari.extension.globalPage.contentWindow.chrome.initialized === true) { chrome = safari.extension.globalPage.contentWindow.chrome; window.clearInterval(handler); waitChromeNS(); } else { return; } } } catch(e) { return; } }, 100); // outro.js ends here // options.js ends here ================================================ FILE: sample/index.html ================================================ Sample Tests

Grading Engine Test!

udacity
75% width
b
this is the correct innerHTML
d
has test attr
f
looking at this one’s abs pos
h
i
j
center

Hello, I’m a p tag.

This box is not the last child
Last child of this container
INIT
================================================ FILE: sample/test.json ================================================ [{ "name": "Meta Info", "code": "Got the meta stuff", "tests": [ { "description": "<meta> has name set to udacity-grader", "definition": { "nodes": "meta", "limit": 1, "attribute": "name", "equals": "udacity-grader" } }, { "description": "<meta> has a content tag with a link to json", "definition": { "nodes": "meta", "limit": 1, "attribute": "content", "hasSubstring": ".json" }, "flags": { "optional": true } } ] }, { "name": "These should pass", "code": "you should see this", "tests": [ { "description": "There are 19 divs", "definition": { "nodes": "div", "get": "count", "equals": 19 } }, { "description": "Width check - 75% of page width is between 1 and 10000 px", "definition": { "nodes": ".three-quarters", "cssProperty": "width", "isInRange": { "lower": 1, "upper": 10000 } } }, { "description": "There is a Udacity logo", "definition": { "nodes": "img#udacity", "exists": true } }, { "description": "One div has test attr", "definition": { "nodes": "div", "limit": 1, "attribute": "test", "exists": true } }, { "description": "The innerHTML div has correct innerHTML", "definition": { "nodes": "div.innerHTML", "get": "innerHTML", "equals": "this is the correct innerHTML" } }, { "description": "The UA string has Mozilla in it", "definition": { "get": "UAString", "hasSubstring": "Mozilla" } }, { "description": "page body is bigger than 400px", "definition": { "nodes": "body", "cssProperty": "width", "isGreaterThan": 400 } }, { "description": "the random div is in the right spot", "definition": { "nodes": ".abs", "absolutePosition": "top", "equals": 30 } }, { "description": "the random div has absolute position left of 0", "definition": { "nodes": ".abs", "absolutePosition": "left", "equals": 0 } }, { "description": "the right div is on the far right", "definition": { "nodes": ".box4", "absolutePosition": "right", "equals": "max" } }, { "description": "the box with just a b in it has a b in it", "definition": { "nodes": ".box2", "get": "innerHTML", "equals": ["b", "d"] } }, { "description": "listening to events", "definition": { "waitForEvent": "ud-test", "exists": true }, "flags": { "noRepeat": true } }, { "description": "DPR is equal to 2 (optional)", "definition": { "get": "DPR", "equals": 2 }, "flags": { "optional": true } }, { "description": "All divs have class box OR flex", "definition": { "nodes": "div", "attribute": "class", "hasSubstring": { "expected": [".*flex.*", ".*box.*"] } } }, { "description": "Some divs have class box", "definition": { "nodes": "div", "limit": "some", "attribute": "class", "hasSubstring": ".*box.*" } }, { "description": "The output box is showing events resulting from tests passing", "definition": { "nodes": ".output", "get": "innerHTML", "exists": true } }, { "description": "The center box is on the middle", "definition": { "nodes": ".center", "cssProperty": "marginLeft", "equals": "100px" } }, { "description": "The center box doesn’t have a margin at bottom", "definition": { "nodes": ".center", "cssProperty": "marginBottom", "equals": "0px" } }, { "description": "The green box is the last child of “.flex-container”", "definition": { "nodes": ".flex-container", "children": ".flex:last-child", "attribute": "class", "hasSubstring": "flex5" } }, { "description": "The magenta box is not the last child of “.flex-container”", "definition": { "nodes": ".flex-container", "children": ".flex:last-child", "attribute": "class", "not": true, "hasSubstring": "flex4" } }, { "description": "The number of “.flex-container:last-child” is 0", "definition": { "nodes": ".flex-container", "children": ".flex-4:last-child", "get": "count", "equals": 0 } } ] }, { "name": "These should fail", "code": "it’s bad if you see this", "tests": [ { "description": "There are 15 divs (just delete one)", "definition": { "nodes": "div", "get": "count", "equals": 15 } }, { "description": "Width check - 75% of page width is between 900 and 1000 px (just resize)", "definition": { "nodes": ".three-quarters", "cssProperty": "width", "isInRange": { "lower": 800, "upper": 900 } } }, { "description": "No Udacity logo (delete the Udacity logo)", "definition": { "nodes": "img#udacity", "exists": false } }, { "description": "No divs have test attr", "definition": { "nodes": "div", "limit": 1, "attribute": "test", "exists": false } }, { "description": "The innerHTML div has incorrect innerHTML", "definition": { "nodes": "div.innerHTML", "get": "innerHTML", "not": true, "equals": "this is the correct innerHTML" } }, { "description": "The UA string has iPad in it", "definition": { "get": "UAString", "hasSubstring": "iPad" } }, { "description": "page body is less than 400px", "definition": { "nodes": "body", "cssProperty": "width", "isLessThan": 400 } }, { "description": "the random div is in the wrong spot", "definition": { "nodes": ".abs", "absolutePosition": "left", "equals": 401 } }, { "description": "the box with just a b in it doesn’t have a c or a p in it", "definition": { "nodes": ".box2", "get": "innerHTML", "equals": ["c", "p"] } }, { "description": "the random div has absolute position left greater than 1", "definition": { "nodes": ".abs", "absolutePosition": "left", "isGreaterThan": 1 } }, { "description": "DPR is equal to 0.5", "definition": { "get": "DPR", "equals": 0.5 }, "flags": { "optional": true } }, { "description": "All divs have class box AND flex", "definition": { "nodes": "div", "attribute": "class", "hasSubstring": { "expected": [".*flex.*", ".*box.*"], "minValues": 2 } } }, { "description": "The output box is not showing events resulting from tests passing", "definition": { "nodes": ".output", "get": "innerHTML", "hasSubstring": "$^" } }, { "description": "The magenta box is the last child of “.flex-container”", "definition": { "nodes": ".flex-container", "children": ".flex:last-child", "attribute": "class", "hasSubstring": "flex4" } } ] }, { "name": "These tests should err", "code": "ERROR ERROR", "tests": [ { "description": "absolute positions", "definition": { "nodes": "body", "absolutePositions": "left", "equals": 1 } }, { "description": "bad counts", "definition": { "nodes": "body", "get": "counts", "equals": 1 } } ] }, { "name": "This should err", "code": "ERROR ERROR", "tests": [ { "description": "absolute positionsss", "definitions": { "nodes": "body", "absolutePositions": "left", "equals": 1 } } ] }, { "name": "Just one", "code": "thing", "tests": [ { "description": "There is a body?", "definition": { "nodes": "body", "get": "count", "equals": 1 } } ] }] ================================================ FILE: sample/unit-tests.js ================================================ /** * @fileOverview This file contains unit tests to be loaded. * @name unit-tests.js * @author Cameron Pittman * @license GPLv3 */ console.log('dispatch event'); window.dispatchEvent(new CustomEvent('ud-test', {'detail': 'passed'})); // unit-test.js ends here ================================================ FILE: src/app/README.md ================================================ # User interface (view) ## Description This directory contains files needed to implements the user-interface. It doesn’t contain grading logic (it’s what we can call the Front-End interface). ## License This directory and the whole project is subject to the [GPLv3 License](../license). ================================================ FILE: src/app/browser_action/browser_action.html ================================================

Udacity Feedback Settings

Want to write tests? Here’s the API.
================================================ FILE: src/app/browser_action/browser_action.js ================================================ /*global FileReader, chrome */ /** * @fileOverview This file contains the browser_action logic. * @name browser_action.js * @author Cameron Pittman * @author Etienne Prud’homme * @license GPLv3 */ // http://html5rocks.com/en/tutorials/file/dndfiles/ /** * This function DOESN’T WORK because the browser action closes when the window looses focus. Handle the Drag-and-drop of custom JSON files. * @param {DragEvent} evt - The Drag-and-drop event. */ function handleFileSelect(evt) { var files = evt.target.files; var file = files[0]; var reader = new FileReader(); var alert = document.querySelector('.alert'); alert.style.display = 'block'; reader.onload = function (file) { sendDataToTab(file.target.result, 'json'); }; reader.onerror = function (e) { alert.style.display = 'block'; alert.textContent = 'Error. Cannot load file.'; console.log(e); }; if (file.type && (file.type.match('application/json') || file.type.match('text/json'))) { alert.textContent = 'JSON found!'; reader.readAsText(file); } else { alert.textContent = 'File found'; alert.style.color = '#a48700'; reader.readAsText(file); } } /** * Custom function for sending messages to the current tab. * @param {*} data - Any message or data that can be serialized * @param {string} type - The type of the message. * @param {function} [callback] - The function that will receive the response. */ function sendDataToTab(data, type, callback) { // debugger; // get the current tab then send data to it chrome.tabs.query({active: true, currentWindow: true}, fireOffData); // actually post data to a tab /** * Sends the message to the current tab. * @param {chrome.tabs.Tab[]} arrayOfTabs - An array of tabs. */ function fireOffData (arrayOfTabs) { var activeTab = arrayOfTabs[0]; var activeTabId = activeTab.id; var message = {'data': data, 'type': type}; chrome.tabs.sendMessage(activeTabId, message, {}, function (response) { if (callback) { callback(response); } }); } } var allowFeedback = document.querySelector('#allow-feedback'); allowFeedback.onchange = function () { if (!this.checked) { sendDataToTab('off', 'on-off'); } else if (this.checked) { sendDataToTab('on', 'on-off'); } }; document.querySelector('#ud-file-loader').addEventListener('change', handleFileSelect, false); /** * Adds a custom warning message and disable the checkbox. * @param {string} message - The custom message. * @param {string} type - The type of warning. * @param {object} options - Object containing options. * @param {bool} options.enableCheckbox - When using the `checkbox`, * {@link type}, it enables toggling the checkbox. Otherwise it does nothing. * @param {bool} options.checked - When using the `checkbox` {@link type}, it * checks the checkbox. Otherwise it does nothing. * @param {bool} options.removeFileInput - When using the `fileInput` * {@link type}, it removes the file input. * @param {bool} options.disableFileInput - When using the `fileInput`, * {@link type}, it disables the file input. */ function addWarning(message, type, options) { options = options || {}; var fileInput, label; var form = document.getElementsByClassName('autorun')[0]; document.getElementById('warning-text').textContent = message; document.getElementsByClassName('warning-block')[0].style.display = 'block'; if(type === 'disable') { document.getElementsByClassName('loader')[0].remove(); } else if(type === 'checkbox') { if(options.enableCheckbox !== true) { form.classList.add('disabled'); allowFeedback.disabled = true; } if(options.checked === true) { allowFeedback.checked = true; } } else if(type === 'fileInput') { fileInput = document.getElementById('ud-file-loader'); if(options.removeFileInput === true) { label = document.getElementById('ud-label-loader'); label.remove(); } else if(options.disableFileInput === true) { fileInput.disabled = false; } else { label = document.getElementById('ud-label-loader'); label.classList.add('disabled'); fileInput.disabled = true; } } } /** * Makes checkbox `checked` if the website is allowed. */ function checkSiteStatus () { // talk to background script sendDataToTab(true, 'background-wake', function (response) { switch(response) { case true: allowFeedback.checked = true; break; case false: allowFeedback.checked = false; break; case 'chrome_local_exception': addWarning('Chrome doesn’t support loading local files automatically', 'checkbox', {enableCheckbox: false, checked: false}); break; case 'unknown_protocol': addWarning('Unsupported protocol. Supported protocols are: http, https and (local) file', 'checkbox', {enableCheckbox: false, checked: false}); break; case 'invalid_origin': addWarning('The linked JSON page isn’t at the same origin and directory as the document', 'checkbox', {enableCheckbox: false, checked: false}); break; case undefined: // response is undefined if there’s no content-script active (so it’s an unsupported URL scheme) addWarning('Unsupported URL scheme. Supported URL schemes are: http://, https://, or file://', 'disable', {}); break; default: break; } }); } /** * Adds the gear EventListener for opening configurations. */ function initDisplay() { var configs = document.getElementById('configs'); configs.addEventListener('click', function handler() { chrome.runtime.openOptionsPage(); }); } // Firefox dev edition seems to load a browser action script asynchronously (while having the async property set to false). Pretending it’s not a bug, that may be a workaround for future Firefox releases. window.addEventListener('DOMContentLoaded', function(event) { checkSiteStatus(); initDisplay(); }); // browser_action.js ends here ================================================ FILE: src/app/css/common.css ================================================ /** * This file was taken in part from uBlock Origin. It contains styles common * to the extension. */ * { box-sizing: border-box; } body { background-color: #fafbfc; color: #4f4f4f; font: 14px/1.3 sans-serif; } a { color: #02b3e4; text-decoration: none; font-weight: 600; } code { background-color: #f9f2f4; border-radius: 4px; color: #c7254e; font-family: Lucida Console,Monaco,Courier,monospace; } /* common.css ends here */ ================================================ FILE: src/app/css/fonts/OFL.txt ================================================ Copyright (c) , (), with Reserved Font Name . Copyright (c) , (), with Reserved Font Name . Copyright (c) , (). This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL ----------------------------------------------------------- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ----------------------------------------------------------- PREAMBLE The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. DEFINITIONS "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. "Reserved Font Name" refers to any names specified as such after the copyright statement(s). "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). "Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. PERMISSION & CONDITIONS Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. TERMINATION This license becomes null and void if any of the above conditions are not met. DISCLAIMER THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. ================================================ FILE: src/app/css/fonts.css ================================================ /** * This file contains custom fonts for the extension. */ @font-face { font-family: 'FontAwesome'; font-weight: normal; font-style: normal; src: url('fonts/fontawesome-webfont.ttf') format('truetype'); } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url('fonts/SourceSansPro-Regular.ttf') format('truetype'); } /* fonts.css ends here */ ================================================ FILE: src/app/css/options.css ================================================ /** * This file contains styles for the options page. */ table { border: 3px solid #2c3b48; border-spacing: 0; color: #444; line-height: 37px; margin: 0 auto; width: 100%; max-width: 620px; } .whitelist-title { background-color: #2c3b48; border: none; color: #fff; } tbody tr:hover { background-color: #cce2e9; } .whitelist-type th { background-color: #7d97ad; /* border-bottom: 3px solid #ccc; */ color: #2c3b48; padding-left: 1em; text-align: left; } .whitelist-row td { border-bottom: 1px solid #00b4e4; } .whitelist-placeholder { text-align: center; } .whitelist-placeholder:hover { background: none; } .chromium-message { text-align: left; padding: 1em 1em 0 1em; line-height: 1em; } tbody .whitelist-row:last-child td { border-bottom: none; } .entry { padding-left: 0.5em; } #add-entry input { width: 100%; height: 100%; } .remove { text-align: right; } .hiddenFileInput { height: 0; visibility: hidden; width: 0; } #back-button { display: none; left: .5em; position: absolute; top: .5em; } main, footer { border: 3px solid #2c3b48; border-spacing: 0; color: #444; line-height: 37px; margin-left: auto; margin-right: auto; margin-top: 2em; width: 100%; max-width: 620px; } .title { background-color: #2c3b48; border: none; color: #fff; font-weight: 700; margin: 0; text-align: center; } .description { background-color: #7d97ad; color: #2c3b48; font-weight: 700; padding-left: 1em; margin: 0; text-align: left; } .description a { color: #2c3b48; } .about { line-height: 2em; padding: 0 1em; text-align: left; } /* options.css ends here */ ================================================ FILE: src/app/css/ui.css ================================================ /** * This file contains the User Interface styles of the extension. */ button.custom { padding: 0.6em 1em; border: 1px solid transparent; border-color: #ccc #ccc #bbb #bbb; border-radius: 3px; background-color: hsl(216, 0%, 75%); background-image: linear-gradient(#f2f2f2, #dddddd); background-repeat: repeat-x; color: #000; opacity: 0.8; } button.custom.disabled, button.custom[disabled] { border-color: #ddd #ddd hsl(36, 0%, 85%); background-color: hsl(36, 0%, 72%); background-image: linear-gradient(#f2f2f2, #dddddd); color: #666; opacity: 0.6; pointer-events: none; } button.custom:hover { opacity: 1.0; } button.important { padding: 0.6em 1em; border: 1px solid transparent; border-color: #ffcc7f #ffcc7f hsl(36, 100%, 73%); border-radius: 3px; background-color: hsl(36, 100%, 75%); background-image: linear-gradient(#ffdca8, #ffcc7f); background-repeat: repeat-x; color: #222; opacity: 0.8; } button.important:hover { opacity: 1.0; } /* Not to be confused with button */ .button { border: none; box-sizing: border-box; cursor: pointer; display: inline-block; font-size: 150%; margin: 0; padding: 8px; } .fa { display: inline-block; font-family: FontAwesome; font-style: normal; font-weight: normal; line-height: 1; vertical-align: middle; } /* ui.css ends here */ ================================================ FILE: src/app/js/inject/StateManager.js ================================================ /*global removeFileNameFromPath, importFeedbackWidget, injectGradingEngine, loadLibraries, loadJSONTestsFromFile, registerTestSuites, turnOn, waitForTestRegistrations, loadUnitTests, chrome, injectedElementsOnPage, injectIntoDocument, importComponentsLibrary, removeInjectedFromDocument, removeFromDocument */ /** * @fileOverview This file contains the StateManager Class. * @name StateManager.js * @author Cameron Pittman * @author Etienne Prud’homme * @license GPLv3 * @todo Add a warning if the widget fails to initialize. */ /** * State of the current Document. * @returns {Promise} * @throws {Error} An error coming from a Promise. */ function StateManager() { this.whitelist = {remote: [], local: []}; this.hostIsAllowed = false; this.host = window.location.origin; this.isChromium = window.navigator.vendor.toLocaleLowerCase().indexOf('google') !== -1; if(this.host.search(/^(?:https?:)\/\/[^\s\.]/) !== -1) { this.type = 'remote'; } else if(this.host === 'null' || this.host.search('file://') !== -1) { if(window.location.protocol === 'file:') { this.host = removeFileNameFromPath(window.location.pathname); this.type = 'local'; } else { throw new Error('Unknown URL formatting error'); } } else { throw new Error('Unknown URL formatting error'); } this.geInjected = false; var currentlyInjecting = false; /** * Run a sequence of Promises to activate the Grading Engine. * @returns {Promise} * @throws {Error} An error coming from a Promise. */ function runLoadSequence() { var self = this; if (!currentlyInjecting || self.geInjected) { currentlyInjecting = true; return importComponentsLibrary() .then(importFeedbackWidget()) .then(injectGradingEngine) .then(loadLibraries) .then(loadJSONTestsFromFile) .then(registerTestSuites) .then(turnOn) // This is to prevent UnitTests and other things in the page to execute before all tests are registered .then(waitForTestRegistrations) .then(loadUnitTests) .then(function() { self.geInjected = true; currentlyInjecting = false; return Promise.resolve(); }, function(e) { // debugger; console.log(e); throw new Error('Something went wrong loading Udacity Feedback. Please reload.'); }); } else { return Promise.resolve(); } } /** * Checks if the host is allowed to execute the Grading Engine (and arbitrary tests). * @returns {Promise} */ this.isSiteOnWhitelist = function() { var self = this; self.isAllowed = false; return new Promise(function(resolve, reject) { var type = self.type; chrome.storage.sync.get('whitelist', function(response) { self.whitelist = response.whitelist || {remote: [], local: []}; // console.log(self.whitelist); if (!(self.whitelist[type] instanceof Array)) { self.whitelist[type] = [self.whitelist[type]]; } if (self.whitelist[type].indexOf(self.host) > -1) { self.isAllowed = true; } else { self.isAllowed = false; } resolve(self.isAllowed); }); }); }; /** * Adds the current Document host to the whitelist (local storage). * @returns {Promise} */ this.addSiteToWhitelist = function() { var self = this; return new Promise(function(resolve, reject) { var type = self.type; if(!type) { reject(); } var index = self.whitelist[type].indexOf(self.host); if (index === -1) { self.whitelist[type].push(self.host); } self.isAllowed = true; var data = {whitelist: self.whitelist}; chrome.storage.sync.set(data, function() { // debugger; resolve(); }); }); }; /** * Removes the current document host from the whitelist (local storage). * @param {string} site - unused * @returns {Promise} */ this.removeSiteFromWhitelist = function(site) { var self = this; return new Promise(function(resolve, reject) { var type = self.type; var index = self.whitelist[type].indexOf(self.host); if (index > -1) { self.whitelist[type].splice(index, 1); } self.isAllowed = false; var data = {whitelist: self.whitelist}; chrome.storage.sync.set(data, function() { // debugger; resolve(); }); }); }; /** * Getter for {@link isAllowed} property. This property shows if the website is on the whitelist. * @returns {boolean} The {@link isAllowed} property. } */ this.getIsAllowed = function() { if(this.isChromium && this.type === 'local') { return 'chrome_local_exception'; } return this.isAllowed; }; /** * Method that activates the {@link runLoadSequence}. * @returns {Promise} */ this.turnOn = function() { var self = this; var g = document.querySelector('#ud-grader-options'); if (g) { document.head.removeChild(g); } if (!self.geInjected) { return runLoadSequence().then(function() { Promise.resolve(true); }); } else { return Promise.resolve(true); } }; /** * Method that desactivates the `test-widget`. * @returns {Promise} * @throws {it’s cool} do nothing */ this.turnOff = function() { var self = this; removeFromDocument('ud-grader-options'); return injectIntoDocument('script', { id: 'ud-grader-options', // Reviewer: This is safe to pass. innerHTML: 'UdacityFEGradingEngine.turnOff();' + 'delete window.UdacityFEGradingEngine;' + 'window.addEventListener("killUdacityFEGradingEngine", function handler() {' + ' window.removeEventListener("killUdacityFEGradingEngine", handler, false);' + ' window.dispatchEvent(new Event("killedGradingEngine"));' + '}, false);' }, 'head') .then(function() { return new Promise(function(resolve, reject) { window.addEventListener('killedGradingEngine', function handler() { window.removeEventListener('killedGradingEngine', handler, false); resolve(); }, false); window.dispatchEvent(new Event('killUdacityFEGradingEngine')); }); }) .then(function() { removeInjectedFromDocument(); // wish I could unregister , but it doesn’t look like it’s possible at the moment self.geInjected = false; }) .catch(function(e) { throw e; }); }; } // StateManager.js ends here ================================================ FILE: src/app/js/inject/helpers.js ================================================ /*global injectedElementsOnPage */ /** * @fileOverview This file contains various functions that aren’t specific to the current extension. * @name helpers.js * @author Cameron Pittman * @author Etienne Prud’homme * @license GPLv3 */ /** * Adds elements to the main page. * @param {String} tag Type of element * @param {Object} data Key/value pairs you want to be assigned to as newTag[key] = value * @param {Object} [location] Set to “head” if you want the element to end up there. Default is body * @return {Promise} */ function injectIntoDocument(tag, data, location) { // debugger; location = location || 'body'; return new Promise(function(resolve, reject) { var newTag = document.createElement(tag); // Firefox fix because it considers dynamically injected scripts as async if(tag === 'script') { newTag.async = false; newTag.setAttribute('charset', 'utf-8'); } if (data) { for (var prop in data) { newTag[prop] = data[prop]; } } if (!newTag.id) { newTag.id = 'ud-' + Math.floor(Math.random() * 100000000).toString(); } // for later removal injectedElementsOnPage.push(newTag.id); newTag.onload = function(e) { resolve(e); }; newTag.onerror = function(e) { reject(e); }; if (tag === 'script' && !newTag.src && (newTag.text || newTag.innerHTML)) { resolve(); } if (location === 'head') { document.head.appendChild(newTag); } else { document.body.appendChild(newTag); } }); } /** * Removes all injected elements from the document. */ function removeInjectedFromDocument() { injectedElementsOnPage.forEach(function(item) { var element = document.getElementById(item); var parent; if(element !== null) { parent = element.parentNode; parent.removeChild(element); } }); injectedElementsOnPage = []; } /** * Removes a single resource from {@link injectedElementsOnPage}. * @param {String} id - The ID of the element. */ function removeFromDocument(id) { var element = document.getElementById(id); var parent; injectedElementsOnPage.splice(injectedElementsOnPage.indexOf(id), 1); if(element !== null) { parent = element.parentNode; parent.removeChild(element); } } /** * Removes a file name from a given path. It return the basename. * @param {string} path - The file path. * @returns {string} The basename of the path. */ function removeFileNameFromPath(path) { path = path.substr(0, path.lastIndexOf('/') + 1); // If there’s a hashtag present, it can simulate a path if(path.indexOf('#') !== -1) { // Remove another URL part until there’s no hashtags path = removeFileNameFromPath(path); } return path; } // helpers.js ends here ================================================ FILE: src/app/js/inject/inject.js ================================================ /*global removeFileNameFromPath, injectIntoDocument, chrome, StateManager */ /** * @fileoverview This file manages the injection of several JavaScript files. It contains most procedure for injecting those files, but doesn’t handle the conditional injection part. * @name inject.js * @author Cameron Pittman * @author Etienne Prud’homme * @license GPLv3 */ /** * List of items id that were injected in the page. It is used to later remove them. * @type {string[]} */ var injectedElementsOnPage = []; var runtimeError = null; /** * The meta tag that is used to load and activate a file of tests. * @type {Element} */ var metaTag = document.querySelector('meta[name="udacity-grader"]'); function importComponentsLibrary() { var cScript = document.querySelector('script#components-lib'); if(!cScript) { return injectIntoDocument('script', { src: chrome.extension.getURL('lib/components.js'), id: 'components-lib' }, 'head'); } else { return Promise.resolve(); } } /** * Finds Web Components templates. * @returns {Promise} */ function importFeedbackWidget() { var twScript = document.querySelector('script#udacity-test-widget'); if (!twScript) { return injectIntoDocument('script', { src: chrome.extension.getURL('app/templates/templates.js'), id: 'udacity-test-widget' }, 'head'); } else { return Promise.resolve(); } } /** * Inject the Grading Engine inside the current Document. * @returns {Promise} */ function injectGradingEngine() { return injectIntoDocument('script', { src: chrome.extension.getURL('app/js/libs/GE.js'), id: 'udacity-front-end-feedback' }, 'head'); } /** * Load custom libraries for the Grading Engine (i.e. jsgrader.js). Currently only `jsgrader.js` is supported and allowed in the manifest. * @returns {Promise} */ function loadLibraries() { if (metaTag) { var libraries = metaTag.getAttribute('libraries'); } if (libraries) { libraries = libraries.split(' '); } else { return Promise.resolve(); } var loadedLibs = 0; return Promise.all( libraries.map(function(lib) { return injectIntoDocument('script', {src: chrome.extension.getURL('app/js/libs/' + lib + '.js')}, 'head'); }) ); } /** * Adds a unique GET ID in order to make the browser ignore the cache. * @param {String} url - A valid absolute URL. * @returns {String} The absolute URL and a unique GET ID. */ function appendIDToURL(url) { var _url = new URL(url); var searchParams = _url.searchParams; var paramName = 'udacityNoCache'; while(searchParams.has(paramName)) { paramName += Math.floor(Math.random() * 10).toString(); } searchParams.set(paramName, Math.floor(Math.random() * 100000000000).toString()); _url.searchParams = searchParams.toString; return _url.toString(); } /** * Loads asynchronously the JSON file containing the tests. * @returns {Promise} */ function loadJSONTestsFromFile() { if (metaTag) { return new Promise(function(resolve, reject) { // http://stackoverflow.com/a/14274828 var xmlhttp = new XMLHttpRequest(); // The complete path to the document excluding the file name (http://example.com/mydir/ for http://example.com/mydir/file.html) var documentBase = removeFileNameFromPath(document.URL); var url = metaTag.content; var fileBase = ''; // If it’s not an absolute URL if(url.search(/^(?:https?|file):\/\//) === -1) { // If it’s protocol relative URL (i.e. //example.com) if(url.search(/^\/\//) !== -1) { // The window must at least use one of those protocols switch(window.location.protocol) { case 'http:': case 'https:': case 'file:': url = window.location.protocol + url; break; default: runtimeError = 'unknown_protocol'; console.warn('Unknown URL protocol. Supported protocols are: http, https and (local) file'); reject(false); } } else { // it’s probably a relative path (may be garbage) url = documentBase + url; } } url = appendIDToURL(url); // Extract the file path (http://example.com/mydir/ for http://example.com/mydir/file.html) fileBase = url.substr(0, url.lastIndexOf('/') + 1); if(fileBase !== documentBase) { runtimeError = 'invalid_origin'; console.warn('Invalid JSON file origin'); reject(false); } xmlhttp.onreadystatechange = function() { if (xmlhttp.status === 200 && xmlhttp.readyState === 4) { // DANGER! Checks if that it wasn’t a redirection if(xmlhttp.responseURL !== url) { runtimeError = 'redirection'; console.warn('The JSON request received a redirection. Possible cross-origin request attempt'); reject(false); } resolve(xmlhttp.responseText); } else if (xmlhttp.status >= 400) { reject(false); } }; xmlhttp.open('GET', url, true); xmlhttp.send(); }); } else { return Promise.resolve(false); } } // You don’t have access to the GE here, but you can inject a script into the document that does. /** * Register test suites from the JSON data. * @param {string} json - JSON containing tests for the Grading Engine. * @returns {Promise} * @throws {Error} Errors about the JSON file. */ function registerTestSuites(json) { if (!json) { return Promise.resolve(); } var errorMsg = null; // validating the JSON try { if (json.length > 0) { JSON.parse(json); } } catch (e) { if (json.indexOf('\\') > -1) { errorMsg = 'Are you trying to use “\\” in a RegEx? Try using \\\\ instead.'; } else { errorMsg = 'Invalid JSON file format.'; } } try { json = JSON.stringify(json); } catch (e) { errorMsg = 'Invalid JSON format.'; } if (errorMsg) { alert(errorMsg); throw new Error(errorMsg); } else { return injectIntoDocument('script', {text: 'UdacityFEGradingEngine.registerSuites(' + json + ');'}, 'head'); } } /** * Checks and injects custom Unit Tests. * @returns {Promise} */ function loadUnitTests() { var unitTests = null; if (metaTag) { unitTests = metaTag.getAttribute('unit-tests'); } if (!unitTests) { return Promise.resolve(); } return injectIntoDocument('script', {src: unitTests, defer: 'defer'}); } /** * Activates the Grading Engine by injecting itself in the Document. Not to be confused with {@link StateManager.turnOn}. This method is called from {@link StateManager~runLoadSequence}. * @returns {Promise} */ function turnOn() { // console.log('Turned on from turnOn()'); return injectIntoDocument('script', { id: 'ud-grader-options', // Reviewer: Because we need to access the window script context, it’s // necessary to inject the script that way. A content-script doesn’t have // access to the window scripting context. innerHTML: 'UdacityFEGradingEngine.turnOn();' }, 'head'); } /** * Stops {@link StateManager~runLoadSequence} until all tests are loaded. This is necessary because the Grading Engine is activated thought the page context. It isn’t a content script like this file. * @todo Add a timeout. If (for some reason) the event is never fired, it would probably block the widget. * @returns {Promise} A `Promise` that fulfills when all tests are loaded */ function waitForTestRegistrations() { return new Promise(function(resolve, reject) { window.addEventListener('tests-registered', function(data) { // console.log('tests-registered received'); return resolve(); }); }); } // StateManager() was here var stateManager = new StateManager(); /** * Wait for messages from browser action. * @param {Object} message - Object containing a `data` and a `type` property. * @param {MessageSender} sender - Information about the Script context. * @param {function} sendResponse - Function to call when a response is received. */ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { switch (message.type) { case 'json': // A JSON test file was passed to the action page registerTestSuites(message.data); break; case 'on-off': // The action page checkbox was toggled if (message.data === 'on') { stateManager.addSiteToWhitelist() .then(stateManager.turnOn); } else if (message.data === 'off') { stateManager.removeSiteFromWhitelist() .then(stateManager.turnOff); } break; case 'background-wake': if(runtimeError) { sendResponse(runtimeError); } // The action page is requesting infos about the current host sendResponse(stateManager.getIsAllowed()); break; default: // Just in case of future bad implementation console.warn('invalid message type for: %s from %s', message, sender); break; } }); /** * for first load */ window.addEventListener('GE-on', function() { if (stateManager.isAllowed) { stateManager.turnOn(); } }); // Check if the site is on the Whitelist on page load stateManager.isSiteOnWhitelist() .then(function(isAllowed) { if (isAllowed) { stateManager.turnOn(); } }); // inject.js ends here ================================================ FILE: src/app/js/libs/jsgrader.js ================================================ /** * @fileOverview This file contains the JSGrader library to test the JavaScript context. * @name jsgrader.js * @author Cameron Pittman * @license GPLv3 */ var Grader = (function() { // http://stackoverflow.com/questions/1068834/object-comparison-in-javascript?lq=1 function deepCompare () { var i, l, leftChain, rightChain; function compare2Objects (x, y) { var p; // remember that NaN === NaN returns false // and isNaN(undefined) returns true if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') { return true; } // Compare primitives and functions. // Check if both arguments link to the same object. // Especially useful on step when comparing prototypes if (x === y) { return true; } // Works in case when functions are created in constructor. // Comparing dates is a common scenario. Another built-ins? // We can even handle functions passed across iframes if ((typeof x === 'function' && typeof y === 'function') || (x instanceof Date && y instanceof Date) || (x instanceof RegExp && y instanceof RegExp) || (x instanceof String && y instanceof String) || (x instanceof Number && y instanceof Number)) { return x.toString() === y.toString(); } // At last checking prototypes as good a we can if (!(x instanceof Object && y instanceof Object)) { return false; } if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) { return false; } if (x.constructor !== y.constructor) { return false; } if (x.prototype !== y.prototype) { return false; } // Check for infinitive linking loops if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) { return false; } // Quick checking of one object beeing a subset of another. // todo: cache the structure of arguments[0] for performance for (p in y) { if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { return false; } else if (typeof y[p] !== typeof x[p]) { return false; } } for (p in x) { if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { return false; } else if (typeof y[p] !== typeof x[p]) { return false; } switch (typeof (x[p])) { case 'object': case 'function': leftChain.push(x); rightChain.push(y); if (!compare2Objects (x[p], y[p])) { return false; } leftChain.pop(); rightChain.pop(); break; default: if (x[p] !== y[p]) { return false; } break; } } return true; } if (arguments.length < 1) { return true; //Die silently? Don’t know how to handle such case, please help... // throw "Need two or more arguments to compare"; } for (i = 1, l = arguments.length; i < l; i++) { leftChain = []; //Todo: this can be cached rightChain = []; if (!compare2Objects(arguments[0], arguments[i])) { return false; } } return true; } function Queue (grader) { this.grader = grader; this.gradingSteps = []; this.flushing = false; this.alwaysGo = false; }; Queue.prototype = { add: function(callback, messages, keepGoing) { if (keepGoing !== false) { keepGoing = true; } if (!callback) { throw new Error("Every test added to the queue must have a valid function."); } this.gradingSteps.push({ callback: callback, isCorrect: false, wrongMessage: messages.wrongMessage || null, comment: messages.comment || null, category: messages.category || null, keepGoing: keepGoing }); }, _flush: function () { if (!this.flushing) { this.flushing = true; } this.step(); }, clear: function () { this.flushing = false; this.gradingSteps = []; this.grader.endTests(); }, step: function () { var self = this; if (this.gradingSteps.length === 0) { this.clear(); } function executeInPromise (fn) { return new Promise(function (resolve, reject) { if (fn) { try { var result = fn(); } catch (e) { self.clear(); console.log(e); } } resolve(result); }); }; function takeNextStep (test, result) { test.isCorrect = result; self.registerResults(test); if (test.isCorrect || test.keepGoing || self.alwaysGo) { self.step(); } else { self.clear(); } }; if (this.flushing) { var test = this.gradingSteps.shift(); if (this.grader.async) { executeInPromise(test.callback).then(function (resolve) { takeNextStep(test, resolve); }); } else if (!this.grader.async) { try { var result = test.callback(); } catch (e) { console.log(e); throw new Error(); } takeNextStep(test, result); } } }, registerResults: function (test) { this.grader.registerResults(test); } }; function Grader (type, categoryMessages) { var self = this; this.specificFeedback = []; this.comments = []; this.isCorrect = false; this.correctHasChanged = false; this.queue = new Queue(self); this.async = false; this.categoryMessages = null; this.generalFeedback = []; this.onresult = function () {}; for (n in arguments) { switch (typeof arguments[n]) { case 'string': if (arguments[n] === 'async') { this.async = true; } else if (arguments[n] === 'sync') { this.async = false; } else { throw new Error("Invalid type argument in Grader constructor"); } break; case 'object': this.categoryMessages = arguments[n]; break; default: throw new TypeError("Invalid argument in Grader constructor"); break; } } }; Grader.prototype = { addTest: function (callback, messages, keepGoing) { this.queue.add(callback, messages, keepGoing); }, runTests: function (options) { if (options) { this.queue.alwaysGo = options.ignoreCheckpoints || false; } this.queue._flush(); }, endTests: function () { if (this.queue.flushing) { this.queue.clear(); } else { var results = this.gatherResults(); this.onresult(results); } }, registerResults: function (test) { this.generateSpecificFeedback(test); this.generateGeneralFeedback(test); this.setCorrect(test); }, generateSpecificFeedback: function (test) { if (!test.isCorrect && test.wrongMessage) { this.addSpecificFeedback(test.wrongMessage); } else if (test.isCorrect && test.comment) { this.addComment(test.comment); } }, generateGeneralFeedback: function (test) { if (!test.isCorrect && test.category) { if (this.generalFeedback.indexOf(this.categoryMessages[test.category]) === -1) { this.generalFeedback.push(this.categoryMessages[test.category]); } } }, setCorrect: function (test) { if (this.correctHasChanged) { this.isCorrect = this.isCorrect && test.isCorrect; } else { this.correctHasChanged = true; this.isCorrect = test.isCorrect; } }, addSpecificFeedback: function (feedback) { this.specificFeedback.push(feedback); }, addComment: function (feedback) { this.comments.push(feedback); }, gatherResults: function () { var self = this; return { isCorrect: self.isCorrect, testFeedback: self.specificFeedback.concat(self.generalFeedback), testComments: self.comments }; }, getFormattedWrongMessages: function (separator) { var allMessages, message; allMessages = this.specificFeedback.concat(this.generalFeedback); message = allMessages.join(separator); return message; }, getFormattedComments: function (separator) { return this.comments.join(separator); }, isType: function (value, expectedType) { var isCorrect = false; if (typeof value !== expectedType) { if (typeof value === 'function') { value = value.name; }; isCorrect = false; } else if (typeof value === expectedType){ isCorrect = true; } return isCorrect; }, isInstance: function (value, expectedInstance) { var isCorrect = false; if (value instanceof expectedInstance !== true) { isCorrect = false; } else if (value instanceof expectedInstance === true){ isCorrect = true; } return isCorrect; }, isValue: function (value1, value2) { var isCorrect = false; if (!deepCompare(value1, value2)) { isCorrect = false; } else if (deepCompare(value1, value2)) { isCorrect = true; } return isCorrect; }, isInRange: function (value, lower, upper) { var isCorrect = false; if (typeof value !== 'number' || isNaN(value)) { isCorrect = false; } else if (value > upper || value < lower) { isCorrect = false; } else if (value < upper || value > lower) { isCorrect = true; } return isCorrect; }, isSet: function (value) { var isCorrect = false; if (value === undefined) { isCorrect = false; } else { isCorrect = true; } return isCorrect; }, isjQuery: function (elem) { // could use obj.jquery, which will only return true if it is a jquery object var isjQ = false; if (elem instanceof $) { isjQ = true; } return isjQ; }, hasCorrectTag: function (elem, tag) { if (!this.isjQuery(elem)) { elem = $(elem); } var hasTag = false; if (elem.is(tag)) { hasTag = true; } return hasTag; }, hasCorrectClass: function (elem, className) { if (!this.isjQuery(elem)) { elem = $(elem); } var hasClass = false; if (elem.hasClass(className)) { hasClass = true; } return hasClass; }, hasCorrectId: function (elem, id) { if (!this.isjQuery(elem)) { elem = $(elem); } if (elem.is('#' + id)) return true; return false; }, hasCorrectText: function (elem, text) { if (!this.isjQuery(elem)) { elem = $(elem); } var hasText = false; var re = new RegExp(text); if (elem.text().match(re)) { hasText = true; } return hasText; }, hasAttr: function (elem, attrName, correctAttr) { var isCorrect = false; if (!this.isjQuery(elem)) { elem = $(elem); } if (correctAttr && elem.attr(attrName) === correctAttr) { isCorrect = true; } else if (!correctAttr && elem.attr(attrName)) { isCorrect = true; } return isCorrect; }, hasCorrectLength: function (elems, _length) { if (!this.isjQuery(elems)) { elems = $(elems); } var correctLength = false; var cLength = elems.length; if (cLength === _length) { correctLength = true; } return correctLength; }, isCorrectElem: function (elem, correctElem) { if (!this.isjQuery(elem)) { elem = $(elem); } var is = false; if (elem.is(correctElem)) { is = true; } return is; }, isCorrectCollection: function (collection, correctCollection) { if (!this.isjQuery(elem)) { elem = $(elem); } var is = false; if (collection.is(correctCollection)) { is = true; } return is; }, hasCorrectStyle: function (elem, cssProperty, _correctStyle) { if (!this.isjQuery(elem)) { elem = $(elem); } var hasCorrectStyle = false; var currentStyle = elem.css(cssProperty); if (currentStyle === _correctStyle) { hasCorrectStyle = true; } return hasCorrectStyle; }, doesExistInParent: function (elem, parentElem) { if (!this.isjQuery(elem)) { elem = $(elem); } if (!this.isjQuery(parentElem)) { parentElem = $(parentElem); } var inParent = false; if (parentElem.find(elem).length > 0) { inParent = true; } return inParent; }, elemDoesExist: function (elem) { if (!this.isjQuery(elem)) { elem = $(elem); } var exists = false; if (elem.length > 0) { exists = true; } return exists; }, areSiblings: function (elem1, elem2) { if (!this.isjQuery(elem1)) { elem1 = $(elem1); } if (!this.isjQuery(elem2)) { elem2 = $(elem2); } var siblingLove = false; if (elem1.siblings(elem2).length > 0) { siblingLove = true; } return siblingLove; }, isImmediateChild: function (elem, parentElem) { var isCorrect = false; if (this.isjQuery(elem)) { throw new Error("elem needs to be a string for Grader.isImmediateChild()"); } if (!this.isjQuery(parentElem)) { parentElem = $(parentElem); } if (parentElem.children(elem).length > 0) { isCorrect = true; } return isCorrect; }, hasParent: function (elem, parentElem) { var isCorrect = false; if (this.isjQuery(parentElem)) { throw new Error("parentElem needs to be a string for Grader.hasParent()"); } if (!this.isjQuery(elem)) { elem = $(elem); } if (elem.closest(parentElem).length > 0) { isCorrect = true; } return isCorrect; }, sendResultsToExecutor: function () { var output = { isCorrect: false, test_feedback: "", test_comments: "", congrats: "" }; for (arg in arguments) { var thisIsCorrect = arguments[arg].isCorrect; var thisTestFeedback = arguments[arg].getFormattedWrongMessages(); var thisTestComment = arguments[arg].getFormattedComments(); if (typeof thisIsCorrect !== 'boolean') { thisIsCorrect = false; } switch (arg) { case '0': output.congrats = arguments[arg]; case '1': output.isCorrect = thisIsCorrect; output.test_feedback = thisTestFeedback; output.test_comments = thisTestComment; break; default: output.isCorrect = thisIsCorrect && output.isCorrect; if (output.test_feedback !== "") { output.test_feedback = [output.test_feedback, thisTestFeedback].join('\n'); } else { output.test_feedback = thisTestFeedback; } if (output.test_comments !== "") { output.test_comments = [output.test_comments, thisTestFeedback].join('\n'); } else { output.test_comments = thisTestComment; } break; } } output = JSON.stringify(output); console.info("UDACITY_RESULT:" + output); } }; return Grader; })(); // jsgrader.js ends here ================================================ FILE: src/app/options/index.html ================================================ Udacity Feedback
Whitelist
Remote hosts
host
Nothing to show here
Local directories
Nothing to show here

Help

Usage

Not sure what how to make it work? Try the walkthrough.

Reporting bugs

Because this extension tries to supports multiple browsers, it’s not unusual to find bugs when a new browser version rolls out. For any suggestions or bug reports, please make a new issue on the GitHub platform. Make sure to include your browser version and the currently installed version of the extension.

Contact

You can contact us at udacityfeedback@udacity.com.

================================================ FILE: src/app/options/options.js ================================================ /*global chrome, browserName */ /** * @fileOverview This file contains the option page for adding/removing websites from the whitelist. * @name options.js * @author Cameron Pittman * @author Etienne Prud’homme * @license GPLv3 * @todo remove trailing / from URLs */ var remoteWhitelist = document.querySelector('#remote-whitelist'); var localWhitelist = document.querySelector('#local-whitelist'); var isChromium = window.navigator.vendor.toLocaleLowerCase().indexOf('google') !== -1; function StateManager() { this.whitelist = {remote: [], local: []}; }; StateManager.prototype = { /** * Get the whitelist from the storage. * @returns {Promise} A promise that resolves when the data is received. */ getWhitelist: function() { var self = this; return new Promise(function (resolve, reject) { chrome.storage.sync.get('whitelist', function (response) { self.whitelist = response.whitelist || {remote: [], local: []}; if (!(self.whitelist.remote instanceof Array || Object.prototype.toString.call(self.whitelist.remote) === '[object Array]')) { self.whitelist.remote = [self.whitelist.remote]; } if (!(self.whitelist.local instanceof Array || Object.prototype.toString.call(self.whitelist.remote) === '[object Array]')) { self.whitelist.local = [self.whitelist.local]; } resolve(self.whitelist); }); }); }, /** * Add a given site to the stored whitelist and the {@link StateManager.whitelist}. * @param {string} site - A URL to add to the whitelist. * @param {string} type - The type of site. It either be: `remote` or `local`. * @returns {Promise} A promise that resolves when the data is set. */ addSiteToWhitelist: function(site, type) { var self = this; return new Promise(function (resolve, reject) { if(type === 'remote') { if(site.search(/^(?:https?:)\/\/[^\s\.]/) === -1) { reject('The site is not a valid URL. The URL must at least contains the http:// or https:// scheme'); } resolve(); } else if(type === 'local') { if(site.search(/^file:\/\/\/?[^\s\.]/) === -1) { reject('The site is not a valid local URL. The URL must at least contains the file:// scheme'); } resolve(); } else { reject('type'); }}).then(function() { var index = self.whitelist[type].indexOf(site); if (index === -1) { self.whitelist[type].push(site); } self.isAllowed = true; var data = {whitelist: {remote: self.whitelist.remote, local: self.whitelist.local}}; chrome.storage.sync.set(data, function () { Promise.resolve(); }); }); }, /** * Remove a given site from the stored whitelist and the {@link StateManager.whitelist}. * @param {string} site - A URL to remove from the whitelist. * @param {string} type - The type of site. It either be: `remote` or `local`. * @returns {Promise} A promise when the data is set. */ removeSiteFromWhitelist: function(site, type) { var self = this; return new Promise(function (resolve, reject) { if(type !== 'remote' && type !== 'local') { reject('type'); } var index = self.whitelist[type].indexOf(site); if (index > -1) { self.whitelist[type].splice(index, 1); } self.isAllowed = false; var data = {whitelist: {remote: self.whitelist.remote, local: self.whitelist.local}}; chrome.storage.sync.set(data, function () { resolve(); }); }); } }; /** * Adds buttons to add entries. */ function initDisplay() { var manifest = chrome.runtime.getManifest(); var extensionVersion = document.getElementById('extension-version'); extensionVersion.textContent = manifest.version; document.getElementById('browser-name').textContent = browserName; var remoteAdd = document.getElementById('remote-add'); remoteAdd.addEventListener('click', function handler(event) { newInputEntry('remote'); }); var localAdd = document.getElementById('local-add'); if(localAdd !== null) { localAdd.addEventListener('click', function handler(event) { newInputEntry('local'); }); } } /** * Removes entries from the whitelist table. */ function cleanDisplay() { var entryCollection = document.getElementsByClassName('whitelist-row'); var entries = [], i, len; // An HTMLCollection would remove its item if we used // `entryCollection[i].remove()` thus decreasing the lenght. That’s why we // convert the collection to an Array for(i=0, len=entryCollection.length; i ends here ================================================ FILE: src/app/test_widget/active_test.js ================================================ /*global components */ /** * @fileOverview This file registers the `active-test` component. This file doesn’t depend on other components. * @name active_test.js * @author Etienne Prud’homme * @license MIT */ /** * Registers the `active-test` component. */ (function() { 'use strict'; var self = null; var proto = {}; var template = '
' + '
' + '
' + '
' + '
' + ''; /** * Function to mark a test as `Passed`. * @param {HTMLElement} markRightOrWrong - The element containing the mark. * @private */ function _testHasPassed(markRightOrWrong) { markRightOrWrong.classList.remove('incorrect'); markRightOrWrong.classList.remove('error'); markRightOrWrong.classList.add('correct'); } /** * Function to mark a test as `Failed`. * @param {HTMLElement} markRightOrWrong - The element containing the mark. * @private */ function _testHasFailed(markRightOrWrong) { markRightOrWrong.classList.add('incorrect'); markRightOrWrong.classList.remove('correct'); markRightOrWrong.classList.remove('error'); } /** * Function to mark a test as `Erred` (is not valid). * @param {HTMLElement} markRightOrWrong - The element containing the mark. * @private */ function _testHasErred(markRightOrWrong) { markRightOrWrong.classList.remove('correct'); markRightOrWrong.classList.remove('incorrect'); markRightOrWrong.classList.add('error'); } /** * Main function for updating member elements. */ function updateView() { var testPassed, testDescription; try { testDescription = self.dataset.description; testPassed = self.dataset.testPassed; } catch (e) { console.warn(e); } var markRightOrWrong = self.querySelector('.mark'); var descriptionDisplay = self.querySelector('.test-desc'); // Simple fix for backward compatibility descriptionDisplay.textContent = testDescription.replace(/<|>/g, function(match) { return {'<': '<', '>': '>'}[match]; }); if (testPassed === 'true') { _testHasPassed(markRightOrWrong); } else if (testPassed === 'false') { _testHasFailed(markRightOrWrong); } else if (testPassed === 'error') { _testHasErred(markRightOrWrong); } } /** * Called when the element gets attached to the document */ proto.attachedCallback = function() { self = this; self.dataset.testPassed = false; updateView(); }; /** * Called when any attribute on the element changes */ proto.attributeChangedCallback = function () { self = this; updateView(); }; components.registerElement('active-test', template, proto); })(); // active_test.js ends here ================================================ FILE: src/app/test_widget/font.js ================================================ /** * @fileOverview This file contains the "Source Sans Pro" font as base64. Because the `template.js` file is an injected script, it doesn’t have access to the extension path. Furthermore, sharing the path could be dangerous. * @name font.js * @author Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. This Font Software is licensed under the SIL Open Font License, Version 1.1. * @license GPLv3 */ var sourceSansProFont = 'AAEAAAATAQAABAAwQkFTRYsZlLEAAilAAAAAOkRTSUexF+HqAAIpfAAAIFhHREVGWIRZ9wABwEAAAAEoR1BPUw6dvuMAAcFoAABMKkdTVUJ+lJvfAAINlAAAG6xPUy8yWrSUWwAAAbgAAABgY21hcG4XREUAABOEAAAKKGN2dCANmQD6AAAfbAAAAChmcGdtBlmcNwAAHawAAAFzZ2FzcP//AAMAAcA4AAAACGdseWbpcaFDAAAoTAABMtRoZWFk/hSz4gAAATwAAAA2aGhlYQejBwsAAAF0AAAAJGhtdHi/qKz/AAACGAAAEWxsb2NhuTYHZgAAH5QAAAi4bWF4cAZ1AkAAAAGYAAAAIG5hbWWdGO0SAAFbIAAAPLJwb3N03+u9sAABl9QAAChicHJlcJYE+usAAB8gAAAASwABAAAAAQzMpu0hD18PPPUACQPoAAAAAM2XgKUAAAAAzZfjFv9A/r0EiAO4AAAACQACAAAAAAAAAAEAAAPY/u8AAASq/0D/FgSIAAEAAAAAAAAAAAAAAAAAAARbAAEAAARbAFoABwBxAAUAAQAAAAAACgAAAgABcwADAAEAAwHHAZAABQAAAooCWAAAAEsCigJYAAABXgAyASAAAAILBQMDBAMCAgQgAAAHAAAAAQAAAAAAAAAAQURCRQBAAAD+/wLu/wYAAAPYAREgAAGTAAAAAAHgApQAAAAgAAMCjQBZAAAAAADKAAAAygAAAiAAAwJMAFoCOwA0AmcAWgIPAFoB7gBaAmkANAKMAFoBBwBaAeAAHwJDAFoB5gBaAtcAWgKHAFoCmAA0AkAAWgKYADQCRQBaAhYAKgIYABwChQBXAgMAAAMSABcCAQAPAdz//wIbAC0CAAA6AisAUgHIAC4CKwAvAfAALgEkAB4B+AAtAiAAUgD2AEMA9//YAe8AUgD/AFIDPQBSAiMAUgIeAC4CKwBSAiYALwFbAFIBowAcAVIAGAIgAEsB0wAMAs4AGAG+AA4B0wAMAakAHwIgAAMCIAADAiAAAwIgAAMCIAADAiAAAwIgAAMCIAADAiAAAwIgAAMCIAADAiAAAwIgAAMCIAADAiAAAwIgAAMCIAADAiAAAwIgAAMCIAADAiAAAwIgAAMDNgAIAjsANAI7ADQCOwA0AjsANAI7ADQCZwBaAmcAWgJnAFoCfgAhAg8AWgIPAFoCDwBaAg8AWgIPAFoCDwBaAg8AWgIPAFoCDwBaAg8AWgIPAFoCDwBaAg8AWgIPAFoCDwBaAg8AWgIPAFoCaQA0AmkANAJpADQCaQA0AmkANAJpADQCaQA0AowAWgKMAFoCjABaAq8AIAEHAAABBwBQAQf/+wEH//IBB//8AQcABwEHAEoBB//7AQcAQwEHAE4BBwArAeAAHwJDAFoB5gBTAeYAWgHmAFoB5gBaAeYAWgHmAAoB5gBaAekADQLXAFoChwBaAocAWgKHAFoChwBaAocAWgKHAFoChwBaApgANAKYADQCmAA0ApgANAKYADQCmAA0ApgANAKYADQCmAA0ApgANAKYADQCmAA0ApgANAKYADQCmAA0ApgAMgNPADQCmAA2ApgANgKYADYCmAA2ApgANgKYADYCmAA0AkUAWgJFAFoCRQBaAkUAWgJFAFoCRQBaAhYAKgIWACoCFgAqAhYAKgIWACoCFgAqAhYAKgKbAFsCGAAcAhgAHAIYABwCGAAcAhgAHAKFAFcChQBXAoUAVwKFAFcChQBXAoUAVwKFAFcChQBXAoUAVwKFAFcChQBXAoUAVwKFAFcChQBXAoUAVwKFAFcChQBXApMAVwKTAFcCkwBXApMAVwKTAFcCkwBXAxIAFwMSABcDEgAXAxIAFwHc//8B3P//Adz//wHc//8B3P//Adz//wHc//8B3P//AhsALQIbAC0CGwAtAhsALQJ+ACECRwBaApMAOgIAADoCAAA6AgAAOgIAADoCAAA6AgAAOgIAADoCAAA6AgAAOgIAADoCAAA6AgAAOgIAADoCAAA6AgAAOgIAADoCAAA6AgAAOgIAADoCAAA6AgAAOgIAADoDEQA6AcgALgHIAC4ByAAuAcgALgHIAC4CPQAvAisALwIrAC8CKwAvAfAALgHwAC4B8AAuAfAALgHwAC4B8AAuAfAALgHwAC4B8AAuAfAALgHwAC4B8AAuAfAALgHwAC4B8AAuAfAALgHwAC4B+AAtAfgALQH4AC0B+AAtAfgALQH4AC0B+AAtAiD/9AIgAFICIABSAiAACAD2AAwA9gA6APb/+gD2//AA9v/0APYAAAD2//oA9gA7APYAQwD2ACYA9gAmAPYAUgD3/9gB7wBSAe8AUgD/AEQBCABSAWoAUgD/AFIA/wBSAP///wD/AC4BBgAXAz0AUgIjAFICIwBSAiMAUgIjAFICIwBSAiMAUgIjAFIDBwA/Ah4ALgIeAC4CHgAuAh4ALgIeAC4CHgAuAh4ALgIeAC4CHgAuAh4ALgIeAC4CHgAuAh4ALgIeAC4CHgAuAh4ALgNHAC4CHgAuAh4ALgIeAC4CHgAuAh4ALgIeAC4CHgAuAVsAUgFbACQBWwBSAVsAQwFbAEMBW//9AaMAHAGjABwBowAcAaMAHAGjABwBowAcAaMAHAJAAFIBUgAYAVIAGAFSABgBUgAYAVIAGAFSAAkCIABLAiAASwIgAEsCIABLAiAASwIgAEsCIABLAiAASwIgAEsCIABLAiAASwIgAEsCIABLAiAASwIgAEsCIABLAiAASwIgAEsCIABLAiAASwIgAEsCIABLAiAASwLOABgCzgAYAs4AGALOABgB0wAMAdMADAHTAAwB0wAMAdMADAHTAAwB0wAMAdMADAGpAB8BqQAfAakAHwGpAB8CIQA1AisAUgD3/9gCKwAvAfAAJQIvADICPgAeAiwAHgIjAB4CUgAeAVgALgFYACkBWAAuAVgAJAFYABsBWAAlAVgALgFYAC4BWAAkAVgALgFYAC4BWAAuAisALwIrAC8CKwAvAisALwIrAC8CKwAvAisALwIrAC8CKwAvAisALwIrAC8CKwAvAisALwIrAC8CKwAvAisALwIrAC8CKwAvAisALwIrAC8CKwAvAisALwIrAC8CLwAyAi8AMgIvADICLwAyAi8AMgIvADICLwAyAi8AMgD2AFIA9gBFAQgAUgFqAFIA9gAmAPYARQD2AAAA9v//AQEAFwIsAB4CYQAgAfEALAHxAE8B8QAkAfEAGgHxABEB8QAZAfEAMAHxACwB8QApAfEAKAIaADcBcQAyAfUAJQHxABoCBwAiAfEAGQINAD0B6wAsAg0ANwINADQB8QAsAfEATwHxACQB8QAaAfEAEQHxABkB8QAxAfEALAHxACkB8QAeAgYANAFxADIB8QApAfEAGgIGABkB8QAZAgYAOQHpACwCBwAxAgYAJgD5AEEA+QAvAPkAQQD5AC8DtABeASEAVQEhAFUBqQAmAakAMAD5AFABqQBQAPkAOQD5AD8BqQA5AakAPwD5AD8BqQA/AQ8ALQEPADYBrQAtAa0ANgE3ACkBNwApAeAAKQMgACkB8QApAyAAKQD5AEEBMAAoAfQADAEvAFIBLwAmAS8AXgEvAB8BLwAiAS8AHwFeAAoA8QBcAV4ADgDxAFwBogA6AcYANgHGADYB8QAtAjAAKQLoADEC5wAxAacAFwJ9AAMCfQAbA08AMwMOADMB8QAjAW8AIwFvAFcBbwAoAW8AIwFvACoBbwAjAW8ALQFvADIBbwAtAW8AJwDtAEEA7QAnALEAKwCxACEBbwAjAW8AVwFvACgBbwAjAW8AKgFvACMBbwAtAW8AMgFvAC0BbwAnAO0AQQDtACcAsQArALEAIQFvACMBbwBXAW8AKAFvACMBbwAqAW8AIwFvAC0BbwAyAW8ALQFvACcA7QBBAO0AJwCxACsAsQAhAW8AIwFvAFcBbwAoAW8AIwFvACoBbwAjAW8ALQFvADIBbwAtAW8AJwDtAEEA7QAnALEAKwCxACEBWQAlAXYAIQFtAB4BWQAlAXYANAEyAB4BdgAhAVAAHADJABMBVwAeAW4ANACmACoAqf/mAVEANACuADQCLwA0AXEANAFtAB4BdgA0AXYAIQDwADQBGwATAOgAEAFyADIBQQAIAecAEAEzAAgBPwAIASIAFQFQABwBUAAcAVAAGQF2ACEBeQAiAKYANAFLACkB8QAaAfEANAHxADUB8QAXAfEAFwHxAD0B8QASAfEAPQHxADUB8QALAfEACgHxAEQB8QAKAfEALwHxAD0B8QBIAfEAFwBW/1kAVv9ZAFb/WQM4ACMEqgAjAw0AQAMoAEADHAAjAyQAQAM1ACkDJABAAzUAIwM1ACMDIQAfAfEAIgHxACIB8QAyAfEAIgH2ALwB8QAiAfEAIgHxACIB8QAiAfEAIgHxACIB8QA8AfEAIgHxACQB8QAkAfEAIgIxABgDDgAoAiYAUgIQACgBTAA0Ai0AKQJQAB4CrgArAfgAFgKhAFkBmQAVAyAALgJrABoCawAqAmsAJwJrACoBMgA2ATIADAG8ACkBeAA2AjsAFwI7ABcCOwA5AjsAOQI7ABcCOwAXAjsAEgI7ABIDHwBKAx8ASgJkAAAB9wAdAgUAOAD5AFEBqgBRAPkAOQD5AD8AlgAeAKIAFAIeAKACHgDOAh4AjgIeAI4AcgAWARUAEADhAC4A4QAAAHIAFgIeAIQCHgCIAh4AlAIeAJECHgCyAh4ArQIeANkCHgDAAh4AzQAA/5EAAP99AAD/vwAA/80AAP9/AAD/eAAA/3UAAP9v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AaIB4AIWAnQCsALQAwIDSgNwA9QEJAR4BMAFMgWGBfQGIAZmBqIHGAd0B7IH6AheCNoJKgmiCgQKUgsCC1ALhAvMDBQMRgzGDRwNcA3sDmIOqg8WD2APtg/yEGgQwhEYEU4RWhFmEXIRfhGKEZYRohGuEboRxhHSEd4R6hH2EgISEhIeEioSNhJCElISxhMqEzYTQhNOE1oTZhNyE34TihOSE54TqhO2E8ITzhPaE+YT8hP+FAoUFhQiFC4UOhRGFFYUuhTGFNIU3hTqFPYVAhUOFRoVJhUyFZoVphWyFb4VyhXWFeIV7hX6FgYWEhZcFmgWdBaAFowWmBakFrAWwBbMFwwXGBckFzAXPBdIF1QXYBdsF3gXhBeQF5wXqBe0F8AXzBfYF+QX8Bf8GAgYFBgkGLAZBhl2GYIZjhmaGaYZshoyGj4aShpWGmIachp+GooalhqiGq4auhrGGtIbPBtIG1QbYBtsG3gbhBuQG5wbqBu0G8AbzBvYG+Qb8Bv8HAgcFBwgHCwcOByqHQodFh0iHS4dOh1GHVIdXh1qHXYdgh2OHZodph2yHb4dyh3WHeId7h36HgYeXh6iHwIfDh8aHyYfMh8+H0ofVh9iH24feh+GH5Ifnh+qH7Yfxh/SH94f6h/2IAYgkiFIIVQhYCFsIXghhCGQIZwhqCIgIiwiOCJEIlAiXCJoInQigCKMIpgipCKwIrwiyCLUIuQjZiNyI34jiiOWI6IjriO6I8Yj0iPeJDYkQiROJFokZiRyJH4kiiSWJKIk9iU2JVYlYiVuJbIlviXKJdYl4iXuJf4mCiZYJmQmcCZ8JogmlCagJqwmuCbEJtAm3CboJvQnACcMJxgnJCcwJzwnSCdUJ2AnbCd8J+gogCjwKPwpCCkUKSApLCmmKbIpvinKKdYp5inyKf4qCioWKiIqLio6KkYqxCrQKtwq6Cr0KwArDCsYKyQrMCs8K0grVCtgK2wreCuEK5ArnCuoK7QrwCvMLDIsliyiLK4suizGLNIs3izqLPYtAi0OLRotJi0yLT4tSi1WLWItbi16LYYtki4ULnourC8IL2gv2jBSMF4wajDsMSIxLjE6MUYxUjFeMWoxdjGCMY4xmjH4MgAyDDIYMiQyMDI8MkgyVDJgMmwyeDKEMpAynDKoMrQyxDLQMtwy6DL0MwQzfjOGM5IznjOqM7YzwjPO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AAEECQABAB4UMgADAAEECQACAA4UUAADAAEECQADAEwUXgADAAEECQAEAB4UMgADAAEECQAFAIIUqgADAAEECQAGACoVLAADAAEECQAHAMAVVgADAAEECQAIADQWFgADAAEECQAJABgWSgADAAEECQALADIWYgADAAEECQANI7YWlAADAAEECQAOAEg6SgADAAEECQEAABg6kgADAAEECQEBABQ6qgADAAEECQECABY6vgADAAEECQEDABY61AADAAEECQEEABI66kNvcHlyaWdodCAyMDEwLCAyMDEyIEFkb2JlIFN5c3RlbXMgSW5jb3Jwb3JhdGVkLiBBbGwgUmlnaHRzIFJlc2VydmVkLlNvdXJjZSBTYW5zIFByb1JlZ3VsYXIxLjA1MDtBREJFO1NvdXJjZVNhbnNQcm8tUmVndWxhcjtBRE9CRVZlcnNpb24gMS4wNTA7UFMgVmVyc2lvbiAxLjAwMDtob3Rjb252IDEuMC43MDttYWtlb3RmLmxpYjIuNS41OTAwU291cmNlU2Fuc1Byby1SZWd1bGFyU291cmNlIGlzIGEgdHJhZGVtYXJrIG9mIEFkb2JlIFN5c3RlbXMgSW5jb3Jwb3JhdGVkIGluIHRoZSBVbml0ZWQgU3RhdGVzIGFuZC9vciBvdGhlciBjb3VudHJpZXMuQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWRQYXVsIEQuIEh1bnRodHRwOi8vd3d3LmFkb2JlLmNvbS90eXBlQ29weXJpZ2h0IDIwMTAsIDIwMTIgQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQgKGh0dHA6Ly93d3cuYWRvYmUuY29tLyksIHdpdGggUmVzZXJ2ZWQgRm9udCBOYW1lICdTb3VyY2UnLiBBbGwgUmlnaHRzIFJlc2VydmVkLiBTb3VyY2UgaXMgYSB0cmFkZW1hcmsgb2YgQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQgaW4gdGhlIFVuaXRlZCBTdGF0ZXMgYW5kL29yIG90aGVyIGNvdW50cmllcy4NCg0KVGhpcyBGb250IFNvZnR3YXJlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBTSUwgT3BlbiBGb250IExpY2Vuc2UsIFZlcnNpb24gMS4xLg0KDQpUaGlzIGxpY2Vuc2UgaXMgY29waWVkIGJlbG93LCBhbmQgaXMgYWxzbyBhdmFpbGFibGUgd2l0aCBhIEZBUSBhdDogaHR0cDovL3NjcmlwdHMuc2lsLm9yZy9PRkwNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NClNJTCBPUEVOIEZPTlQgTElDRU5TRSBWZXJzaW9uIDEuMSAtIDI2IEZlYnJ1YXJ5IDIwMDcNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNClBSRUFNQkxFDQpUaGUgZ29hbHMgb2YgdGhlIE9wZW4gRm9udCBMaWNlbnNlIChPRkwpIGFyZSB0byBzdGltdWxhdGUgd29ybGR3aWRlIGRldmVsb3BtZW50IG9mIGNvbGxhYm9yYXRpdmUgZm9udCBwcm9qZWN0cywgdG8gc3VwcG9ydCB0aGUgZm9udCBjcmVhdGlvbiBlZmZvcnRzIG9mIGFjYWRlbWljIGFuZCBsaW5ndWlzdGljIGNvbW11bml0aWVzLCBhbmQgdG8gcHJvdmlkZSBhIGZyZWUgYW5kIG9wZW4gZnJhbWV3b3JrIGluIHdoaWNoIGZvbnRzIG1heSBiZSBzaGFyZWQgYW5kIGltcHJvdmVkIGluIHBhcnRuZXJzaGlwIHdpdGggb3RoZXJzLg0KDQpUaGUgT0ZMIGFsbG93cyB0aGUgbGljZW5zZWQgZm9udHMgdG8gYmUgdXNlZCwgc3R1ZGllZCwgbW9kaWZpZWQgYW5kIHJlZGlzdHJpYnV0ZWQgZnJlZWx5IGFzIGxvbmcgYXMgdGhleSBhcmUgbm90IHNvbGQgYnkgdGhlbXNlbHZlcy4gVGhlIGZvbnRzLCBpbmNsdWRpbmcgYW55IGRlcml2YXRpdmUgd29ya3MsIGNhbiBiZSBidW5kbGVkLCBlbWJlZGRlZCwgcmVkaXN0cmlidXRlZCBhbmQvb3Igc29sZCB3aXRoIGFueSBzb2Z0d2FyZSBwcm92aWRlZCB0aGF0IGFueSByZXNlcnZlZCBuYW1lcyBhcmUgbm90IHVzZWQgYnkgZGVyaXZhdGl2ZSB3b3Jrcy4gVGhlIGZvbnRzIGFuZCBkZXJpdmF0aXZlcywgaG93ZXZlciwgY2Fubm90IGJlIHJlbGVhc2VkIHVuZGVyIGFueSBvdGhlciB0eXBlIG9mIGxpY2Vuc2UuIFRoZSByZXF1aXJlbWVudCBmb3IgZm9udHMgdG8gcmVtYWluIHVuZGVyIHRoaXMgbGljZW5zZSBkb2VzIG5vdCBhcHBseSB0byBhbnkgZG9jdW1lbnQgY3JlYXRlZCB1c2luZyB0aGUgZm9udHMgb3IgdGhlaXIgZGVyaXZhdGl2ZXMuDQoNCkRFRklOSVRJT05TDQoiRm9udCBTb2Z0d2FyZSIgcmVmZXJzIHRvIHRoZSBzZXQgb2YgZmlsZXMgcmVsZWFzZWQgYnkgdGhlIENvcHlyaWdodCBIb2xkZXIocykgdW5kZXIgdGhpcyBsaWNlbnNlIGFuZCBjbGVhcmx5IG1hcmtlZCBhcyBzdWNoLiBUaGlzIG1heSBpbmNsdWRlIHNvdXJjZSBmaWxlcywgYnVpbGQgc2NyaXB0cyBhbmQgZG9jdW1lbnRhdGlvbi4NCg0KIlJlc2VydmVkIEZvbnQgTmFtZSIgcmVmZXJzIHRvIGFueSBuYW1lcyBzcGVjaWZpZWQgYXMgc3VjaCBhZnRlciB0aGUgY29weXJpZ2h0IHN0YXRlbWVudChzKS4NCg0KIk9yaWdpbmFsIFZlcnNpb24iIHJlZmVycyB0byB0aGUgY29sbGVjdGlvbiBvZiBGb250IFNvZnR3YXJlIGNvbXBvbmVudHMgYXMgZGlzdHJpYnV0ZWQgYnkgdGhlIENvcHlyaWdodCBIb2xkZXIocykuDQoNCiJNb2RpZmllZCBWZXJzaW9uIiByZWZlcnMgdG8gYW55IGRlcml2YXRpdmUgbWFkZSBieSBhZGRpbmcgdG8sIGRlbGV0aW5nLCBvciBzdWJzdGl0dXRpbmcgLS0gaW4gcGFydCBvciBpbiB3aG9sZSAtLSBhbnkgb2YgdGhlIGNvbXBvbmVudHMgb2YgdGhlIE9yaWdpbmFsIFZlcnNpb24sIGJ5IGNoYW5naW5nIGZvcm1hdHMgb3IgYnkgcG9ydGluZyB0aGUgRm9udCBTb2Z0d2FyZSB0byBhIG5ldyBlbnZpcm9ubWVudC4NCg0KIkF1dGhvciIgcmVmZXJzIHRvIGFueSBkZXNpZ25lciwgZW5naW5lZXIsIHByb2dyYW1tZXIsIHRlY2huaWNhbCB3cml0ZXIgb3Igb3RoZXIgcGVyc29uIHdobyBjb250cmlidXRlZCB0byB0aGUgRm9udCBTb2Z0d2FyZS4NCg0KUEVSTUlTU0lPTiAmIENPTkRJVElPTlMNClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhlIEZvbnQgU29mdHdhcmUsIHRvIHVzZSwgc3R1ZHksIGNvcHksIG1lcmdlLCBlbWJlZCwgbW9kaWZ5LCByZWRpc3RyaWJ1dGUsIGFuZCBzZWxsIG1vZGlmaWVkIGFuZCB1bm1vZGlmaWVkIGNvcGllcyBvZiB0aGUgRm9udCBTb2Z0d2FyZSwgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6DQoNCjEpIE5laXRoZXIgdGhlIEZvbnQgU29mdHdhcmUgbm9yIGFueSBvZiBpdHMgaW5kaXZpZHVhbCBjb21wb25lbnRzLCBpbiBPcmlnaW5hbCBvciBNb2RpZmllZCBWZXJzaW9ucywgbWF5IGJlIHNvbGQgYnkgaXRzZWxmLg0KDQoyKSBPcmlnaW5hbCBvciBNb2RpZmllZCBWZXJzaW9ucyBvZiB0aGUgRm9udCBTb2Z0d2FyZSBtYXkgYmUgYnVuZGxlZCwgcmVkaXN0cmlidXRlZCBhbmQvb3Igc29sZCB3aXRoIGFueSBzb2Z0d2FyZSwgcHJvdmlkZWQgdGhhdCBlYWNoIGNvcHkgY29udGFpbnMgdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgbGljZW5zZS4gVGhlc2UgY2FuIGJlIGluY2x1ZGVkIGVpdGhlciBhcyBzdGFuZC1hbG9uZSB0ZXh0IGZpbGVzLCBodW1hbi1yZWFkYWJsZSBoZWFkZXJzIG9yIGluIHRoZSBhcHByb3ByaWF0ZSBtYWNoaW5lLXJlYWRhYmxlIG1ldGFkYXRhIGZpZWxkcyB3aXRoaW4gdGV4dCBvciBiaW5hcnkgZmlsZXMgYXMgbG9uZyBhcyB0aG9zZSBmaWVsZHMgY2FuIGJlIGVhc2lseSB2aWV3ZWQgYnkgdGhlIHVzZXIuDQoNCjMpIE5vIE1vZGlmaWVkIFZlcnNpb24gb2YgdGhlIEZvbnQgU29mdHdhcmUgbWF5IHVzZSB0aGUgUmVzZXJ2ZWQgRm9udCBOYW1lKHMpIHVubGVzcyBleHBsaWNpdCB3cml0dGVuIHBlcm1pc3Npb24gaXMgZ3JhbnRlZCBieSB0aGUgY29ycmVzcG9uZGluZyBDb3B5cmlnaHQgSG9sZGVyLiBUaGlzIHJlc3RyaWN0aW9uIG9ubHkgYXBwbGllcyB0byB0aGUgcHJpbWFyeSBmb250IG5hbWUgYXMgcHJlc2VudGVkIHRvIHRoZSB1c2Vycy4NCg0KNCkgVGhlIG5hbWUocykgb2YgdGhlIENvcHlyaWdodCBIb2xkZXIocykgb3IgdGhlIEF1dGhvcihzKSBvZiB0aGUgRm9udCBTb2Z0d2FyZSBzaGFsbCBub3QgYmUgdXNlZCB0byBwcm9tb3RlLCBlbmRvcnNlIG9yIGFkdmVydGlzZSBhbnkgTW9kaWZpZWQgVmVyc2lvbiwgZXhjZXB0IHRvIGFja25vd2xlZGdlIHRoZSBjb250cmlidXRpb24ocykgb2YgdGhlIENvcHlyaWdodCBIb2xkZXIocykgYW5kIHRoZSBBdXRob3Iocykgb3Igd2l0aCB0aGVpciBleHBsaWNpdCB3cml0dGVuIHBlcm1pc3Npb24uDQoNCjUpIFRoZSBGb250IFNvZnR3YXJlLCBtb2RpZmllZCBvciB1bm1vZGlmaWVkLCBpbiBwYXJ0IG9yIGluIHdob2xlLCBtdXN0IGJlIGRpc3RyaWJ1dGVkIGVudGlyZWx5IHVuZGVyIHRoaXMgbGljZW5zZSwgYW5kIG11c3Qgbm90IGJlIGRpc3RyaWJ1dGVkIHVuZGVyIGFueSBvdGhlciBsaWNlbnNlLiBUaGUgcmVxdWlyZW1lbnQgZm9yIGZvbnRzIHRvIHJlbWFpbiB1bmRlciB0aGlzIGxpY2Vuc2UgZG9lcyBub3QgYXBwbHkgdG8gYW55IGRvY3VtZW50IGNyZWF0ZWQgdXNpbmcgdGhlIEZvbnQgU29mdHdhcmUuDQoNClRFUk1JTkFUSU9ODQpUaGlzIGxpY2Vuc2UgYmVjb21lcyBudWxsIGFuZCB2b2lkIGlmIGFueSBvZiB0aGUgYWJvdmUgY29uZGl0aW9ucyBhcmUgbm90IG1ldC4NCg0KRElTQ0xBSU1FUg0KVEhFIEZPTlQgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIEFOWSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVCBPRiBDT1BZUklHSFQsIFBBVEVOVCwgVFJBREVNQVJLLCBPUiBPVEhFUiBSSUdIVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVCBIT0xERVIgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBJTkNMVURJTkcgQU5ZIEdFTkVSQUwsIFNQRUNJQUwsIElORElSRUNULCBJTkNJREVOVEFMLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMsIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgVEhFIFVTRSBPUiBJTkFCSUxJVFkgVE8gVVNFIFRIRSBGT05UIFNPRlRXQVJFIE9SIEZST00gT1RIRVIgREVBTElOR1MgSU4gVEhFIEZPTlQgU09GVFdBUkUuaHR0cDovL3d3dy5hZG9iZS5jb20vdHlwZS9sZWdhbC5odG1sU2xhc2hlZCB6ZXJvU3RyYWlnaHQgbEFsdGVybmF0ZSBhQWx0ZXJuYXRlIGdTZXJpZmVkIEkAQwBvAHAAeQByAGkAZwBoAHQAIAAyADAAMQAwACwAIAAyADAAMQAyACAAQQBkAG8AYgBlACAAUwB5AHMAdABlAG0AcwAgAEkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkAC4AIABBAGwAbAAgAFIAaQBnAGgAdABzACAAUgBlAHMAZQByAHYAZQBkAC4AUwBvAHUAcgBjAGUAIABTAGEAbgBzACAAUAByAG8AUgBlAGcAdQBsAGEAcgAxAC4AMAA1ADAAOwBBAEQAQgBFADsAUwBvAHUAcgBjAGUAUwBhAG4AcwBQAHIAbwAtAFIAZQBnAHUAbABhAHIAOwBBAEQATwBCAEUAVgBlAHIAcwBpAG8AbgAgADEALgAwADUAMAA7AFAAUwAgAFYAZQByAHMAaQBvAG4AIAAxAC4AMAAwADAAOwBoAG8AdABjAG8AbgB2ACAAMQAuADAALgA3ADAAOwBtAGEAawBlAG8AdABmAC4AbABpAGIAMgAuADUALgA1ADkAMAAwAFMAbwB1AHIAYwBlAFMAYQBuAHMAUAByAG8ALQBSAGUAZwB1AGwAYQByAFMAbwB1AHIAYwBlACAAaQBzACAAYQAgAHQAcgBhAGQAZQBtAGEAcgBrACAAbwBmACAAQQBkAG8AYgBlACAAUwB5AHMAdABlAG0AcwAgAEkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaQBuACAAdABoAGUAIABVAG4AaQB0AGUAZAAgAFMAdABhAHQAZQBzACAAYQBuAGQALwBvAHIAIABvAHQAaABlAHIAIABjAG8AdQBuAHQAcgBpAGUAcwAuAEEAZABvAGIAZQAgAFMAeQBzAHQAZQBtAHMAIABJAG4AYwBvAHIAcABvAHIAYQB0AGUAZABQAGEAdQBsACAARAAuACAASAB1AG4AdABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBkAG8AYgBlAC4AYwBvAG0ALwB0AHkAcABlAEMAbwBwAHkAcgBpAGcAaAB0ACAAMgAwADEAMAAsACAAMgAwADEAMgAgAEEAZABvAGIAZQAgAFMAeQBzAHQAZQBtAHMAIABJAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgACgAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGEAZABvAGIAZQAuAGMAbwBtAC8AKQAsACAAdwBpAHQAaAAgAFIAZQBzAGUAcgB2AGUAZAAgAEYAbwBuAHQAIABOAGEAbQBlACAAJwBTAG8AdQByAGMAZQAnAC4AIABBAGwAbAAgAFIAaQBnAGgAdABzACAAUgBlAHMAZQByAHYAZQBkAC4AIABTAG8AdQByAGMAZQAgAGkAcwAgAGEAIAB0AHIAYQBkAGUAbQBhAHIAawAgAG8AZgAgAEEAZABvAGIAZQAgAFMAeQBzAHQAZQBtAHMAIABJAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGkAbgAgAHQAaABlACAAVQBuAGkAdABlAGQAIABTAHQAYQB0AGUAcwAgAGEAbgBkAC8AbwByACAAbwB0AGgAZQByACAAYwBvAHUAbgB0AHIAaQBlAHMALgANAAoADQAKAFQAaABpAHMAIABGAG8AbgB0ACAAUwBvAGYAdAB3AGEAcgBlACAAaQBzACAAbABpAGMAZQBuAHMAZQBkACAAdQBuAGQAZQByACAAdABoAGUAIABTAEkATAAgAE8AcABlAG4AIABGAG8AbgB0ACAATABpAGMAZQBuAHMAZQAsACAAVgBlAHIAcwBpAG8AbgAgADEALgAxAC4ADQAKAA0ACgBUAGgAaQBzACAAbABpAGMAZQBuAHMAZQAgAGkAcwAgAGMAbwBwAGkAZQBkACAAYgBlAGwAbwB3ACwAIABhAG4AZAAgAGkAcwAgAGEAbABzAG8AIABhAHYAYQBpAGwAYQBiAGwAZQAgAHcAaQB0AGgAIABhACAARgBBAFEAIABhAHQAOgAgAGgAdAB0AHAAOgAvAC8AcwBjAHIAaQBwAHQAcwAuAHMAaQBsAC4AbwByAGcALwBPAEYATAANAAoADQAKAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQANAAoAUwBJAEwAIABPAFAARQBOACAARgBPAE4AVAAgAEwASQBDAEUATgBTAEUAIABWAGUAcgBzAGkAbwBuACAAMQAuADEAIAAtACAAMgA2ACAARgBlAGIAcgB1AGEAcgB5ACAAMgAwADAANwANAAoALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAC0ALQAtAA0ACgANAAoAUABSAEUAQQBNAEIATABFAA0ACgBUAGgAZQAgAGcAbwBhAGwAcwAgAG8AZgAgAHQAaABlACAATwBwAGUAbgAgAEYAbwBuAHQAIABMAGkAYwBlAG4AcwBlACAAKABPAEYATAApACAAYQByAGUAIAB0AG8AIABzAHQAaQBtAHUAbABhAHQAZQAgAHcAbwByAGwAZAB3AGkAZABlACAAZABlAHYAZQBsAG8AcABtAGUAbgB0ACAAbwBmACAAYwBvAGwAbABhAGIAbwByAGEAdABpAHYAZQAgAGYAbwBuAHQAIABwAHIAbwBqAGUAYwB0AHMALAAgAHQAbwAgAHMAdQBwAHAAbwByAHQAIAB0AGgAZQAgAGYAbwBuAHQAIABjAHIAZQBhAHQAaQBvAG4AIABlAGYAZgBvAHIAdABzACAAbwBmACAAYQBjAGEAZABlAG0AaQBjACAAYQBuAGQAIABsAGkAbgBnAHUAaQBzAHQAaQBjACAAYwBvAG0AbQB1AG4AaQB0AGkAZQBzACwAIABhAG4AZAAgAHQAbwAgAHAAcgBvAHYAaQBkAGUAIABhACAAZgByAGUAZQAgAGEAbgBkACAAbwBwAGUAbgAgAGYAcgBhAG0AZQB3AG8AcgBrACAAaQBuACAAdwBoAGkAYwBoACAAZgBvAG4AdABzACAAbQBhAHkAIABiAGUAIABzAGgAYQByAGUAZAAgAGEAbgBkACAAaQBtAHAAcgBvAHYAZQBkACAAaQBuACAAcABhAHIAdABuAGUAcgBzAGgAaQBwACAAdwBpAHQAaAAgAG8AdABoAGUAcgBzAC4ADQAKAA0ACgBUAGgAZQAgAE8ARgBMACAAYQBsAGwAbwB3AHMAIAB0AGgAZQAgAGwAaQBjAGUAbgBzAGUAZAAgAGYAbwBuAHQAcwAgAHQAbwAgAGIAZQAgAHUAcwBlAGQALAAgAHMAdAB1AGQAaQBlAGQALAAgAG0AbwBkAGkAZgBpAGUAZAAgAGEAbgBkACAAcgBlAGQAaQBzAHQAcgBpAGIAdQB0AGUAZAAgAGYAcgBlAGUAbAB5ACAAYQBzACAAbABvAG4AZwAgAGEAcwAgAHQAaABlAHkAIABhAHIAZQAgAG4AbwB0ACAAcwBvAGwAZAAgAGIAeQAgAHQAaABlAG0AcwBlAGwAdgBlAHMALgAgAFQAaABlACAAZgBvAG4AdABzACwAIABpAG4AYwBsAHUAZABpAG4AZwAgAGEAbgB5ACAAZABlAHIAaQB2AGEAdABpAHYAZQAgAHcAbwByAGsAcwAsACAAYwBhAG4AIABiAGUAIABiAHUAbgBkAGwAZQBkACwAIABlAG0AYgBlAGQAZABlAGQALAAgAHIAZQBkAGkAcwB0AHIAaQBiAHUAdABlAGQAIABhAG4AZAAvAG8AcgAgAHMAbwBsAGQAIAB3AGkAdABoACAAYQBuAHkAIABzAG8AZgB0AHcAYQByAGUAIABwAHIAbwB2AGkAZABlAGQAIAB0AGgAYQB0ACAAYQBuAHkAIAByAGUAcwBlAHIAdgBlAGQAIABuAGEAbQBlAHMAIABhAHIAZQAgAG4AbwB0ACAAdQBzAGUAZAAgAGIAeQAgAGQAZQByAGkAdgBhAHQAaQB2AGUAIAB3AG8AcgBrAHMALgAgAFQAaABlACAAZgBvAG4AdABzACAAYQBuAGQAIABkAGUAcgBpAHYAYQB0AGkAdgBlAHMALAAgAGgAbwB3AGUAdgBlAHIALAAgAGMAYQBuAG4AbwB0ACAAYgBlACAAcgBlAGwAZQBhAHMAZQBkACAAdQBuAGQAZQByACAAYQBuAHkAIABvAHQAaABlAHIAIAB0AHkAcABlACAAbwBmACAAbABpAGMAZQBuAHMAZQAuACAAVABoAGUAIAByAGUAcQB1AGkAcgBlAG0AZQBuAHQAIABmAG8AcgAgAGYAbwBuAHQAcwAgAHQAbwAgAHIAZQBtAGEAaQBuACAAdQBuAGQAZQByACAAdABoAGkAcwAgAGwAaQBjAGUAbgBzAGUAIABkAG8AZQBzACAAbgBvAHQAIABhAHAAcABsAHkAIAB0AG8AIABhAG4AeQAgAGQAbwBjAHUAbQBlAG4AdAAgAGMAcgBlAGEAdABlAGQAIAB1AHMAaQBuAGcAIAB0AGgAZQAgAGYAbwBuAHQAcwAgAG8AcgAgAHQAaABlAGkAcgAgAGQAZQByAGkAdgBhAHQAaQB2AGUAcwAuAA0ACgANAAoARABFAEYASQBOAEkAVABJAE8ATgBTAA0ACgAiAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUAIgAgAHIAZQBmAGUAcgBzACAAdABvACAAdABoAGUAIABzAGUAdAAgAG8AZgAgAGYAaQBsAGUAcwAgAHIAZQBsAGUAYQBzAGUAZAAgAGIAeQAgAHQAaABlACAAQwBvAHAAeQByAGkAZwBoAHQAIABIAG8AbABkAGUAcgAoAHMAKQAgAHUAbgBkAGUAcgAgAHQAaABpAHMAIABsAGkAYwBlAG4AcwBlACAAYQBuAGQAIABjAGwAZQBhAHIAbAB5ACAAbQBhAHIAawBlAGQAIABhAHMAIABzAHUAYwBoAC4AIABUAGgAaQBzACAAbQBhAHkAIABpAG4AYwBsAHUAZABlACAAcwBvAHUAcgBjAGUAIABmAGkAbABlAHMALAAgAGIAdQBpAGwAZAAgAHMAYwByAGkAcAB0AHMAIABhAG4AZAAgAGQAbwBjAHUAbQBlAG4AdABhAHQAaQBvAG4ALgANAAoADQAKACIAUgBlAHMAZQByAHYAZQBkACAARgBvAG4AdAAgAE4AYQBtAGUAIgAgAHIAZQBmAGUAcgBzACAAdABvACAAYQBuAHkAIABuAGEAbQBlAHMAIABzAHAAZQBjAGkAZgBpAGUAZAAgAGEAcwAgAHMAdQBjAGgAIABhAGYAdABlAHIAIAB0AGgAZQAgAGMAbwBwAHkAcgBpAGcAaAB0ACAAcwB0AGEAdABlAG0AZQBuAHQAKABzACkALgANAAoADQAKACIATwByAGkAZwBpAG4AYQBsACAAVgBlAHIAcwBpAG8AbgAiACAAcgBlAGYAZQByAHMAIAB0AG8AIAB0AGgAZQAgAGMAbwBsAGwAZQBjAHQAaQBvAG4AIABvAGYAIABGAG8AbgB0ACAAUwBvAGYAdAB3AGEAcgBlACAAYwBvAG0AcABvAG4AZQBuAHQAcwAgAGEAcwAgAGQAaQBzAHQAcgBpAGIAdQB0AGUAZAAgAGIAeQAgAHQAaABlACAAQwBvAHAAeQByAGkAZwBoAHQAIABIAG8AbABkAGUAcgAoAHMAKQAuAA0ACgANAAoAIgBNAG8AZABpAGYAaQBlAGQAIABWAGUAcgBzAGkAbwBuACIAIAByAGUAZgBlAHIAcwAgAHQAbwAgAGEAbgB5ACAAZABlAHIAaQB2AGEAdABpAHYAZQAgAG0AYQBkAGUAIABiAHkAIABhAGQAZABpAG4AZwAgAHQAbwAsACAAZABlAGwAZQB0AGkAbgBnACwAIABvAHIAIABzAHUAYgBzAHQAaQB0AHUAdABpAG4AZwAgAC0ALQAgAGkAbgAgAHAAYQByAHQAIABvAHIAIABpAG4AIAB3AGgAbwBsAGUAIAAtAC0AIABhAG4AeQAgAG8AZgAgAHQAaABlACAAYwBvAG0AcABvAG4AZQBuAHQAcwAgAG8AZgAgAHQAaABlACAATwByAGkAZwBpAG4AYQBsACAAVgBlAHIAcwBpAG8AbgAsACAAYgB5ACAAYwBoAGEAbgBnAGkAbgBnACAAZgBvAHIAbQBhAHQAcwAgAG8AcgAgAGIAeQAgAHAAbwByAHQAaQBuAGcAIAB0AGgAZQAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUAIAB0AG8AIABhACAAbgBlAHcAIABlAG4AdgBpAHIAbwBuAG0AZQBuAHQALgANAAoADQAKACIAQQB1AHQAaABvAHIAIgAgAHIAZQBmAGUAcgBzACAAdABvACAAYQBuAHkAIABkAGUAcwBpAGcAbgBlAHIALAAgAGUAbgBnAGkAbgBlAGUAcgAsACAAcAByAG8AZwByAGEAbQBtAGUAcgAsACAAdABlAGMAaABuAGkAYwBhAGwAIAB3AHIAaQB0AGUAcgAgAG8AcgAgAG8AdABoAGUAcgAgAHAAZQByAHMAbwBuACAAdwBoAG8AIABjAG8AbgB0AHIAaQBiAHUAdABlAGQAIAB0AG8AIAB0AGgAZQAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUALgANAAoADQAKAFAARQBSAE0ASQBTAFMASQBPAE4AIAAmACAAQwBPAE4ARABJAFQASQBPAE4AUwANAAoAUABlAHIAbQBpAHMAcwBpAG8AbgAgAGkAcwAgAGgAZQByAGUAYgB5ACAAZwByAGEAbgB0AGUAZAAsACAAZgByAGUAZQAgAG8AZgAgAGMAaABhAHIAZwBlACwAIAB0AG8AIABhAG4AeQAgAHAAZQByAHMAbwBuACAAbwBiAHQAYQBpAG4AaQBuAGcAIABhACAAYwBvAHAAeQAgAG8AZgAgAHQAaABlACAARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAsACAAdABvACAAdQBzAGUALAAgAHMAdAB1AGQAeQAsACAAYwBvAHAAeQAsACAAbQBlAHIAZwBlACwAIABlAG0AYgBlAGQALAAgAG0AbwBkAGkAZgB5ACwAIAByAGUAZABpAHMAdAByAGkAYgB1AHQAZQAsACAAYQBuAGQAIABzAGUAbABsACAAbQBvAGQAaQBmAGkAZQBkACAAYQBuAGQAIAB1AG4AbQBvAGQAaQBmAGkAZQBkACAAYwBvAHAAaQBlAHMAIABvAGYAIAB0AGgAZQAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUALAAgAHMAdQBiAGoAZQBjAHQAIAB0AG8AIAB0AGgAZQAgAGYAbwBsAGwAbwB3AGkAbgBnACAAYwBvAG4AZABpAHQAaQBvAG4AcwA6AA0ACgANAAoAMQApACAATgBlAGkAdABoAGUAcgAgAHQAaABlACAARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAgAG4AbwByACAAYQBuAHkAIABvAGYAIABpAHQAcwAgAGkAbgBkAGkAdgBpAGQAdQBhAGwAIABjAG8AbQBwAG8AbgBlAG4AdABzACwAIABpAG4AIABPAHIAaQBnAGkAbgBhAGwAIABvAHIAIABNAG8AZABpAGYAaQBlAGQAIABWAGUAcgBzAGkAbwBuAHMALAAgAG0AYQB5ACAAYgBlACAAcwBvAGwAZAAgAGIAeQAgAGkAdABzAGUAbABmAC4ADQAKAA0ACgAyACkAIABPAHIAaQBnAGkAbgBhAGwAIABvAHIAIABNAG8AZABpAGYAaQBlAGQAIABWAGUAcgBzAGkAbwBuAHMAIABvAGYAIAB0AGgAZQAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUAIABtAGEAeQAgAGIAZQAgAGIAdQBuAGQAbABlAGQALAAgAHIAZQBkAGkAcwB0AHIAaQBiAHUAdABlAGQAIABhAG4AZAAvAG8AcgAgAHMAbwBsAGQAIAB3AGkAdABoACAAYQBuAHkAIABzAG8AZgB0AHcAYQByAGUALAAgAHAAcgBvAHYAaQBkAGUAZAAgAHQAaABhAHQAIABlAGEAYwBoACAAYwBvAHAAeQAgAGMAbwBuAHQAYQBpAG4AcwAgAHQAaABlACAAYQBiAG8AdgBlACAAYwBvAHAAeQByAGkAZwBoAHQAIABuAG8AdABpAGMAZQAgAGEAbgBkACAAdABoAGkAcwAgAGwAaQBjAGUAbgBzAGUALgAgAFQAaABlAHMAZQAgAGMAYQBuACAAYgBlACAAaQBuAGMAbAB1AGQAZQBkACAAZQBpAHQAaABlAHIAIABhAHMAIABzAHQAYQBuAGQALQBhAGwAbwBuAGUAIAB0AGUAeAB0ACAAZgBpAGwAZQBzACwAIABoAHUAbQBhAG4ALQByAGUAYQBkAGEAYgBsAGUAIABoAGUAYQBkAGUAcgBzACAAbwByACAAaQBuACAAdABoAGUAIABhAHAAcAByAG8AcAByAGkAYQB0AGUAIABtAGEAYwBoAGkAbgBlAC0AcgBlAGEAZABhAGIAbABlACAAbQBlAHQAYQBkAGEAdABhACAAZgBpAGUAbABkAHMAIAB3AGkAdABoAGkAbgAgAHQAZQB4AHQAIABvAHIAIABiAGkAbgBhAHIAeQAgAGYAaQBsAGUAcwAgAGEAcwAgAGwAbwBuAGcAIABhAHMAIAB0AGgAbwBzAGUAIABmAGkAZQBsAGQAcwAgAGMAYQBuACAAYgBlACAAZQBhAHMAaQBsAHkAIAB2AGkAZQB3AGUAZAAgAGIAeQAgAHQAaABlACAAdQBzAGUAcgAuAA0ACgANAAoAMwApACAATgBvACAATQBvAGQAaQBmAGkAZQBkACAAVgBlAHIAcwBpAG8AbgAgAG8AZgAgAHQAaABlACAARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAgAG0AYQB5ACAAdQBzAGUAIAB0AGgAZQAgAFIAZQBzAGUAcgB2AGUAZAAgAEYAbwBuAHQAIABOAGEAbQBlACgAcwApACAAdQBuAGwAZQBzAHMAIABlAHgAcABsAGkAYwBpAHQAIAB3AHIAaQB0AHQAZQBuACAAcABlAHIAbQBpAHMAcwBpAG8AbgAgAGkAcwAgAGcAcgBhAG4AdABlAGQAIABiAHkAIAB0AGgAZQAgAGMAbwByAHIAZQBzAHAAbwBuAGQAaQBuAGcAIABDAG8AcAB5AHIAaQBnAGgAdAAgAEgAbwBsAGQAZQByAC4AIABUAGgAaQBzACAAcgBlAHMAdAByAGkAYwB0AGkAbwBuACAAbwBuAGwAeQAgAGEAcABwAGwAaQBlAHMAIAB0AG8AIAB0AGgAZQAgAHAAcgBpAG0AYQByAHkAIABmAG8AbgB0ACAAbgBhAG0AZQAgAGEAcwAgAHAAcgBlAHMAZQBuAHQAZQBkACAAdABvACAAdABoAGUAIAB1AHMAZQByAHMALgANAAoADQAKADQAKQAgAFQAaABlACAAbgBhAG0AZQAoAHMAKQAgAG8AZgAgAHQAaABlACAAQwBvAHAAeQByAGkAZwBoAHQAIABIAG8AbABkAGUAcgAoAHMAKQAgAG8AcgAgAHQAaABlACAAQQB1AHQAaABvAHIAKABzACkAIABvAGYAIAB0AGgAZQAgAEYAbwBuAHQAIABTAG8AZgB0AHcAYQByAGUAIABzAGgAYQBsAGwAIABuAG8AdAAgAGIAZQAgAHUAcwBlAGQAIAB0AG8AIABwAHIAbwBtAG8AdABlACwAIABlAG4AZABvAHIAcwBlACAAbwByACAAYQBkAHYAZQByAHQAaQBzAGUAIABhAG4AeQAgAE0AbwBkAGkAZgBpAGUAZAAgAFYAZQByAHMAaQBvAG4ALAAgAGUAeABjAGUAcAB0ACAAdABvACAAYQBjAGsAbgBvAHcAbABlAGQAZwBlACAAdABoAGUAIABjAG8AbgB0AHIAaQBiAHUAdABpAG8AbgAoAHMAKQAgAG8AZgAgAHQAaABlACAAQwBvAHAAeQByAGkAZwBoAHQAIABIAG8AbABkAGUAcgAoAHMAKQAgAGEAbgBkACAAdABoAGUAIABBAHUAdABoAG8AcgAoAHMAKQAgAG8AcgAgAHcAaQB0AGgAIAB0AGgAZQBpAHIAIABlAHgAcABsAGkAYwBpAHQAIAB3AHIAaQB0AHQAZQBuACAAcABlAHIAbQBpAHMAcwBpAG8AbgAuAA0ACgANAAoANQApACAAVABoAGUAIABGAG8AbgB0ACAAUwBvAGYAdAB3AGEAcgBlACwAIABtAG8AZABpAGYAaQBlAGQAIABvAHIAIAB1AG4AbQBvAGQAaQBmAGkAZQBkACwAIABpAG4AIABwAGEAcgB0ACAAbwByACAAaQBuACAAdwBoAG8AbABlACwAIABtAHUAcwB0ACAAYgBlACAAZABpAHMAdAByAGkAYgB1AHQAZQBkACAAZQBuAHQAaQByAGUAbAB5ACAAdQBuAGQAZQByACAAdABoAGkAcwAgAGwAaQBjAGUAbgBzAGUALAAgAGEAbgBkACAAbQB1AHMAdAAgAG4AbwB0ACAAYgBlACAAZABpAHMAdAByAGkAYgB1AHQAZQBkACAAdQBuAGQAZQByACAAYQBuAHkAIABvAHQAaABlAHIAIABsAGkAYwBlAG4AcwBlAC4AIABUAGgAZQAgAHIAZQBxAHUAaQByAGUAbQBlAG4AdAAgAGYAbwByACAAZgBvAG4AdABzACAAdABvACAAcgBlAG0AYQBpAG4AIAB1AG4AZABlAHIAIAB0AGgAaQBzACAAbABpAGMAZQBuAHMAZQAgAGQAbwBlAHMAIABuAG8AdAAgAGEAcABwAGwAeQAgAHQAbwAgAGEAbgB5ACAAZABvAGMAdQBtAGUAbgB0ACAAYwByAGUAYQB0AGUAZAAgAHUAcwBpAG4AZwAgAHQAaABlACAARgBvAG4AdAAgAFMAbwBmAHQAdwBhAHIAZQAuAA0ACgANAAoAVABFAFIATQBJAE4AQQBUAEkATwBOAA0ACgBUAGgAaQBzACAAbABpAGMAZQBuAHMAZQAgAGIAZQBjAG8AbQBlAHMAIABuAHUAbABsACAAYQBuAGQAIAB2AG8AaQBkACAAaQBmACAAYQBuAHkAIABvAGYAIAB0AGgAZQAgAGEAYgBvAHYAZQAgAGMAbwBuAGQAaQB0AGkAbwBuAHMAIABhAHIAZQAgAG4AbwB0ACAAbQBlAHQALgANAAoADQAKAEQASQBTAEMATABBAEkATQBFAFIADQAKAFQASABFACAARgBPAE4AVAAgAFMATwBGAFQAVwBBAFIARQAgAEkAUwAgAFAAUgBPAFYASQBEAEUARAAgACIAQQBTACAASQBTACIALAAgAFcASQBUAEgATwBVAFQAIABXAEEAUgBSAEEATgBUAFkAIABPAEYAIABBAE4AWQAgAEsASQBOAEQALAAgAEUAWABQAFIARQBTAFMAIABPAFIAIABJAE0AUABMAEkARQBEACwAIABJAE4AQwBMAFUARABJAE4ARwAgAEIAVQBUACAATgBPAFQAIABMAEkATQBJAFQARQBEACAAVABPACAAQQBOAFkAIABXAEEAUgBSAEEATgBUAEkARQBTACAATwBGACAATQBFAFIAQwBIAEEATgBUAEEAQgBJAEwASQBUAFkALAAgAEYASQBUAE4ARQBTAFMAIABGAE8AUgAgAEEAIABQAEEAUgBUAEkAQwBVAEwAQQBSACAAUABVAFIAUABPAFMARQAgAEEATgBEACAATgBPAE4ASQBOAEYAUgBJAE4ARwBFAE0ARQBOAFQAIABPAEYAIABDAE8AUABZAFIASQBHAEgAVAAsACAAUABBAFQARQBOAFQALAAgAFQAUgBBAEQARQBNAEEAUgBLACwAIABPAFIAIABPAFQASABFAFIAIABSAEkARwBIAFQALgAgAEkATgAgAE4ATwAgAEUAVgBFAE4AVAAgAFMASABBAEwATAAgAFQASABFACAAQwBPAFAAWQBSAEkARwBIAFQAIABIAE8ATABEAEUAUgAgAEIARQAgAEwASQBBAEIATABFACAARgBPAFIAIABBAE4AWQAgAEMATABBAEkATQAsACAARABBAE0AQQBHAEUAUwAgAE8AUgAgAE8AVABIAEUAUgAgAEwASQBBAEIASQBMAEkAVABZACwAIABJAE4AQwBMAFUARABJAE4ARwAgAEEATgBZACAARwBFAE4ARQBSAEEATAAsACAAUwBQAEUAQwBJAEEATAAsACAASQBOAEQASQBSAEUAQwBUACwAIABJAE4AQwBJAEQARQBOAFQAQQBMACwAIABPAFIAIABDAE8ATgBTAEUAUQBVAEUATgBUAEkAQQBMACAARABBAE0AQQBHAEUAUwAsACAAVwBIAEUAVABIAEUAUgAgAEkATgAgAEEATgAgAEEAQwBUAEkATwBOACAATwBGACAAQwBPAE4AVABSAEEAQwBUACwAIABUAE8AUgBUACAATwBSACAATwBUAEgARQBSAFcASQBTAEUALAAgAEEAUgBJAFMASQBOAEcAIABGAFIATwBNACwAIABPAFUAVAAgAE8ARgAgAFQASABFACAAVQBTAEUAIABPAFIAIABJAE4AQQBCAEkATABJAFQAWQAgAFQATwAgAFUAUwBFACAAVABIAEUAIABGAE8ATgBUACAAUwBPAEYAVABXAEEAUgBFACAATwBSACAARgBSAE8ATQAgAE8AVABIAEUAUgAgAEQARQBBAEwASQBOAEcAUwAgAEkATgAgAFQASABFACAARgBPAE4AVAAgAFMATwBGAFQAVwBBAFIARQAuAA0ACgBoAHQAdABwADoALwAvAHcAdwB3AC4AYQBkAG8AYgBlAC4AYwBvAG0ALwB0AHkAcABlAC8AbABlAGcAYQBsAC4AaAB0AG0AbABTAGwAYQBzAGgAZQBkACAAegBlAHIAbwBTAHQAcgBhAGkAZwBoAHQAIABsAEEAbAB0AGUAcgBuAGEAdABlACAAYQBBAGwAdABlAHIAbgBhAHQAZQAgAGcAUwBlAHIAaQBmAGUAZAAgAEkAAAACAAAAAAAA/7UAMgAAAAAAAAAAAAAAAAAAAAAAAAAABFsAAAECAQMAAwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0ARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAK0AyQDHAK4AYgEEAQUAYwEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMAkABkAP0BFAD/ARUBFgEXARgBGQDLAGUAyAEaAMoBGwEcAR0BHgEfASABIQEiASMBJAElASYBJwD4ASgBKQEqASsBLAEtAS4BLwEwAM8AzADNATEAzgEyAPoBMwE0ATUBNgE3ATgBOQE6ATsBPAE9AT4BPwDiAUABQQFCAGYBQwFEAUUBRgDTANAA0QCvAGcBRwFIAUkBSgFLAUwBTQFOAU8BUACRALABUQFSAVMBVAFVAVYBVwFYAVkBWgFbAVwBXQFeAV8A5AFgAWEBYgFjAWQBZQFmAWcBaAFpANYA1ADVAWoAaAFrAWwBbQFuAW8BcAFxAXIBcwF0AXUBdgF3AXgBeQF6AXsBfAF9AX4BfwGAAYEA6wGCALsBgwGEAYUBhgGHAOYBiAGJAOkA7QGKAGoAaQBrAG0AbAGLAYwAbgGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoAoABvAP4BmwEAAZwBnQGeAZ8BAQBxAHAAcgGgAHMBoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQD5Aa4BrwGwAbEBsgGzAbQBtQG2AHUAdAB2AbcAdwG4AbkBugG7AbwBvQDXAb4BvwHAAcEBwgHDAcQBxQHGAccA4wHIAckBygB4AcsBzAHNAc4BzwB6AHkAewB9AHwB0AHRAdIB0wHUAdUB1gHXAdgB2QChALEB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegA5QHpAeoB6wHsAIkB7QHuAe8B8AHxAfIAfwB+AIAB8wCBAfQB9QH2AfcB+AH5AfoB+wH8Af0B/gH/AgACAQICAgMCBAIFAgYCBwIIAgkCCgDsAgsAugIMAg0CDgIPAhAA5wIRAhIA6gDuAhMCFAIVAhYCFwDAAMECGAIZAhoCGwIcAh0CHgIfAiACIQIiAiMCJAIlAiYCJwIoAikCKgIrAiwCLQIuAi8CMAIxAjICMwI0AjUCNgI3AjgCOQI6AjsCPAI9Aj4CPwJAAkECQgJDAkQCRQJGAkcCSAJJAkoCSwJMAk0ACQATABQAFQAWABcAGAAZABoAGwAcAk4CTwJQAlECUgJTAlQCVQJWAlcCWAJZAloCWwJcAl0CXgJfAmACYQJiAmMCZAJlAmYCZwJoAmkCagJrABEADwAdAB4AqwAEAKMAIgCiAAoABQC2ALcAtAC1AMQAxQC+AL8AqQCqABACbACyALMCbQJuAMMAhwBCAAsADAA+AEAAXgBgABIAXwA/AOgADQCCAMIAhgCIAIsCbwCKAIwCcAAjAnEABgJyAnMCdAJ1AnYCdwJ4AnkCegJ7AnwCfQJ+An8CgAKBAoICgwKEAoUChgKHAogCiQKKAosCjAKNAo4CjwKQApECkgKTApQClQKWApcCmAKZApoCmwKcAp0CngKfAqACoQKiAqMCpAKlAqYCpwKoAqkAnQKqAJ4CqwKsAq0CrgKvArACsQKyArMCtAK1ArYCtwK4ArkCugK7ArwCvQK+Ar8CwALBAsICwwLEAsUCxgLHAsgCyQLKAIMAvQAHAIUAlgLLAIQCzALNAs4CzwLQAtEC0gLTAtQC1QLWALwC1wLYAAgAxgD1APQA9gLZAtoC2wLcAt0C3gAOAO8A8AC4At8AIAAfACEAlACVAJMAQQCPAGEApwCkAJsAkgLgAJgAnAClAuEC4gCZAJoC4wLkAuUC5gLnAugC6QLqAusC7ALtAu4C7wLwAvEC8gLzAvQC9QL2AvcC+AC5AvkC+gL7AvwC/QL+AEMAjQDYAOEC/wMAAwEDAgMDANkAjgDaANsA3QDfANwA3gDgAwQDBQMGAwcDCAMJAwoDCwMMAw0DDgMPAxADEQMSAxMDFAMVAxYDFwMYAxkDGgMbAxwDHQMeAx8DIAMhAyIDIwMkAyUDJgMnAygDKQMqAysDLAMtAy4DLwMwAzEDMgMzAzQDNQM2AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRANFA0YDRwNIA0kDSgNLA0wDTQNOA08DUANRA1IDUwNUA1UDVgNXA1gDWQNaA1sDXANdA14DXwNgA2EDYgNjA2QDZQNmA2cDaANpA2oDawNsA20DbgNvA3ADcQNyA3MDdAN1A3YDdwN4A3kDegN7A3wDfQN+A38DgAOBA4IDgwOEA4UDhgOHA4gDiQOKA4sDjAONA44DjwOQA5EDkgOTA5QDlQOWA5cDmAOZA5oDmwOcA50DngOfA6ADoQOiA6MDpAOlA6YDpwOoA6kDqgOrA6wDrQOuA68DsAOxA7IDswO0A7UDtgO3A7gDuQO6A7sDvAO9A74DvwPAA8EDwgPDA8QDxQPGA8cDyAPJA8oDywPMA80DzgPPA9AD0QPSA9MD1APVA9YD1wPYA9kD2gPbA9wD3QPeA98D4APhA+ID4wPkA+UD5gPnA+gD6QPqA+sD7APtA+4D7wPwA/ED8gPzA/QD9QP2A/cD+AP5A/oD+wP8A/0D/gP/BAAEAQQCBAMEBAQFBAYEBwQIBAkECgQLBAwEDQQOBA8EEAQRBBIEEwQUBBUEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQmBCcEKAQpBCoEKwQsBC0ELgQvBDAEMQQyBDMENAQ1BDYENwQ4BDkEOgQ7BDwEPQQ+BD8EQARBBEIEQwREBEUERgRHBEgESQRKBEsETARNBE4ETwRQBFEEUgRTBFQEVQRWBFcEWARZBFoEWwRcBF0EXgRfBGAEYQRiBGMEZARlBGYEZwRoBE5VTEwCQ1IHQW1hY3JvbgZBYnJldmUHdW5pMDFDRAd1bmkxRUEwB3VuaTFFQTIHdW5pMUVBNAd1bmkxRUE2B3VuaTFFQTgHdW5pMUVBQQd1bmkxRUFDB3VuaTFFQUUHdW5pMUVCMAd1bmkxRUIyB3VuaTFFQjQHdW5pMUVCNgdBb2dvbmVrC0NjaXJjdW1mbGV4CkNkb3RhY2NlbnQGRGNhcm9uB3VuaTFFMEMHdW5pMUUwRQZEY3JvYXQGRWNhcm9uB0VtYWNyb24GRWJyZXZlCkVkb3RhY2NlbnQHdW5pMUVCOAd1bmkxRUJBB3VuaTFFQkMHdW5pMUVCRQd1bmkxRUMwB3VuaTFFQzIHdW5pMUVDNAd1bmkxRUM2B0VvZ29uZWsLR2NpcmN1bWZsZXgKR2RvdGFjY2VudAd1bmkwMTIyBkdjYXJvbgd1bmkxRTIwC3VuaTAwNDcwMzAzC0hjaXJjdW1mbGV4B3VuaTFFMjQHdW5pMUUyQQRIYmFyBkl0aWxkZQdJbWFjcm9uB3VuaTAxQ0YHdW5pMUVDOAd1bmkxRUNBB0lvZ29uZWsLSmNpcmN1bWZsZXgHdW5pMDEzNgZMYWN1dGUGTGNhcm9uB3VuaTAxM0IETGRvdAd1bmkxRTM2B3VuaTFFMzgHdW5pMUUzQQd1bmkxRTQyBk5hY3V0ZQZOY2Fyb24HdW5pMDE0NQd1bmkxRTQ0B3VuaTFFNDYHdW5pMUU0OAdPbWFjcm9uDU9odW5nYXJ1bWxhdXQHdW5pMDFEMQd1bmkxRUNDB3VuaTFFQ0UHdW5pMUVEMAd1bmkxRUQyB3VuaTFFRDQHdW5pMUVENgd1bmkxRUQ4BU9ob3JuB3VuaTFFREEHdW5pMUVEQwd1bmkxRURFB3VuaTFFRTAHdW5pMUVFMgd1bmkwMUVBBlJhY3V0ZQZSY2Fyb24HdW5pMDE1Ngd1bmkxRTVBB3VuaTFFNUMHdW5pMUU1RQZTYWN1dGULU2NpcmN1bWZsZXgHdW5pMDE1RQd1bmkwMjE4B3VuaTFFNjAHdW5pMUU2Mgd1bmkxRTlFBlRjYXJvbgd1bmkwMTYyB3VuaTAyMUEHdW5pMUU2Qwd1bmkxRTZFBlV0aWxkZQdVbWFjcm9uBlVicmV2ZQVVcmluZw1VaHVuZ2FydW1sYXV0B3VuaTAxRDMHdW5pMDFENQd1bmkwMUQ3B3VuaTAxRDkHdW5pMDFEQgd1bmkxRUU0B3VuaTFFRTYHVW9nb25lawVVaG9ybgd1bmkxRUU4B3VuaTFFRUEHdW5pMUVFQwd1bmkxRUVFB3VuaTFFRjAGV2dyYXZlBldhY3V0ZQtXY2lyY3VtZmxleAlXZGllcmVzaXMGWWdyYXZlC1ljaXJjdW1mbGV4B3VuaTFFOEUHdW5pMUVGNAd1bmkxRUY2B3VuaTFFRjgGWmFjdXRlClpkb3RhY2NlbnQHdW5pMUU5Mgd1bmkwMThGB2FtYWNyb24GYWJyZXZlB3VuaTAxQ0UHdW5pMUVBMQd1bmkxRUEzB3VuaTFFQTUHdW5pMUVBNwd1bmkxRUE5B3VuaTFFQUIHdW5pMUVBRAd1bmkxRUFGB3VuaTFFQjEHdW5pMUVCMwd1bmkxRUI1B3VuaTFFQjcHYW9nb25lawtjY2lyY3VtZmxleApjZG90YWNjZW50BmRjYXJvbgd1bmkxRTBEB3VuaTFFMEYGZWNhcm9uB2VtYWNyb24GZWJyZXZlCmVkb3RhY2NlbnQHdW5pMUVCOQd1bmkxRUJCB3VuaTFFQkQHdW5pMUVCRgd1bmkxRUMxB3VuaTFFQzMHdW5pMUVDNQd1bmkxRUM3B2VvZ29uZWsLZ2NpcmN1bWZsZXgKZ2RvdGFjY2VudAd1bmkwMTIzBmdjYXJvbgd1bmkxRTIxC3VuaTAwNjcwMzAzC2hjaXJjdW1mbGV4B3VuaTFFMjUHdW5pMUUyQgRoYmFyBml0aWxkZQdpbWFjcm9uB3VuaTAxRDAHdW5pMUVDOQd1bmkxRUNCB2lvZ29uZWsJaW9nb25lay5kC2pjaXJjdW1mbGV4B3VuaTAxMzcMa2dyZWVubGFuZGljBmxhY3V0ZQZsY2Fyb24EbGRvdAd1bmkwMTNDB3VuaTFFMzcHdW5pMUUzOQd1bmkxRTNCB3VuaTFFNDMGbmFjdXRlBm5jYXJvbgd1bmkwMTQ2B3VuaTFFNDUHdW5pMUU0Nwd1bmkxRTQ5C25hcG9zdHJvcGhlB29tYWNyb24Nb2h1bmdhcnVtbGF1dAd1bmkwMUQyB3VuaTFFQ0QHdW5pMUVDRgd1bmkxRUQxB3VuaTFFRDMHdW5pMUVENQd1bmkxRUQ3B3VuaTFFRDkFb2hvcm4HdW5pMUVEQgd1bmkxRUREB3VuaTFFREYHdW5pMUVFMQd1bmkxRUUzB3VuaTAxRUIGcmFjdXRlB3VuaTAxNTcGcmNhcm9uB3VuaTFFNUIHdW5pMUU1RAd1bmkxRTVGBnNhY3V0ZQtzY2lyY3VtZmxleAd1bmkwMTVGB3VuaTAyMTkHdW5pMUU2MQd1bmkxRTYzBnRjYXJvbgd1bmkwMTYzB3VuaTAyMUIHdW5pMUU2RAd1bmkxRTZGB3VuaTFFOTcGdXRpbGRlB3VtYWNyb24GdWJyZXZlBXVyaW5nDXVodW5nYXJ1bWxhdXQHdW5pMDFENAd1bmkwMUQ2B3VuaTAxRDgHdW5pMDFEQQd1bmkwMURDB3VuaTFFRTUHdW5pMUVFNwd1b2dvbmVrBXVob3JuB3VuaTFFRTkHdW5pMUVFQgd1bmkxRUVEB3VuaTFFRUYHdW5pMUVGMQZ3Z3JhdmUGd2FjdXRlC3djaXJjdW1mbGV4CXdkaWVyZXNpcwZ5Z3JhdmULeWNpcmN1bWZsZXgHdW5pMUU4Rgd1bmkxRUY1B3VuaTFFRjcHdW5pMUVGOQZ6YWN1dGUKemRvdGFjY2VudAd1bmkxRTkzB3VuaTAyMzcHdW5pMDI1MQd1bmkwMjU5B3VuaTAyNjEDZl9mA2ZfdANJLmEISWdyYXZlLmEISWFjdXRlLmENSWNpcmN1bWZsZXguYQhJdGlsZGUuYQtJZGllcmVzaXMuYQlJbWFjcm9uLmEMSWRvdGFjY2VudC5hCXVuaTAxQ0YuYQl1bmkxRUM4LmEJdW5pMUVDQS5hCUlvZ29uZWsuYQNhLmEIYWdyYXZlLmEIYWFjdXRlLmENYWNpcmN1bWZsZXguYQhhdGlsZGUuYQthZGllcmVzaXMuYQlhbWFjcm9uLmEIYWJyZXZlLmEHYXJpbmcuYQl1bmkwMUNFLmEJdW5pMUVBMS5hCXVuaTFFQTMuYQl1bmkxRUE1LmEJdW5pMUVBNy5hCXVuaTFFQTkuYQl1bmkxRUFCLmEJdW5pMUVBRC5hCXVuaTFFQUYuYQl1bmkxRUIxLmEJdW5pMUVCMy5hCXVuaTFFQjUuYQl1bmkxRUI3LmEJYW9nb25lay5hA2cuYQ1nY2lyY3VtZmxleC5hCGdicmV2ZS5hDGdkb3RhY2NlbnQuYQl1bmkwMTIzLmEIZ2Nhcm9uLmEJdW5pMUUyMS5hDXVuaTAwNjcwMzAzLmEDbC5hCGxhY3V0ZS5hCGxjYXJvbi5hBmxkb3QuYQl1bmkwMTNDLmEJdW5pMUUzNy5hCXVuaTFFMzkuYQl1bmkxRTNCLmEIbHNsYXNoLmEEZmwuYQl6ZXJvLnBudW0Ib25lLnBudW0IdHdvLnBudW0KdGhyZWUucG51bQlmb3VyLnBudW0JZml2ZS5wbnVtCHNpeC5wbnVtCnNldmVuLnBudW0KZWlnaHQucG51bQluaW5lLnBudW0JemVyby50bnVtCG9uZS50bnVtCHR3by50bnVtCnRocmVlLnRudW0JZm91ci50bnVtCWZpdmUudG51bQhzaXgudG51bQpzZXZlbi50bnVtCmVpZ2h0LnRudW0JbmluZS50bnVtCXplcm8ub251bQhvbmUub251bQh0d28ub251bQp0aHJlZS5vbnVtCWZvdXIub251bQlmaXZlLm9udW0Ic2l4Lm9udW0Kc2V2ZW4ub251bQplaWdodC5vbnVtCW5pbmUub251bQd1bmkwMEFECmZpZ3VyZWRhc2gHdW5pMjAxNQd1bmkyMTE3B3VuaTIxMjAHYXQuY2FzZQl6ZXJvLnN1cHMIb25lLnN1cHMIdHdvLnN1cHMKdGhyZWUuc3Vwcwlmb3VyLnN1cHMJZml2ZS5zdXBzCHNpeC5zdXBzCnNldmVuLnN1cHMKZWlnaHQuc3VwcwluaW5lLnN1cHMOcGFyZW5sZWZ0LnN1cHMPcGFyZW5yaWdodC5zdXBzC3BlcmlvZC5zdXBzCmNvbW1hLnN1cHMJemVyby5zdWJzCG9uZS5zdWJzCHR3by5zdWJzCnRocmVlLnN1YnMJZm91ci5zdWJzCWZpdmUuc3VicwhzaXguc3VicwpzZXZlbi5zdWJzCmVpZ2h0LnN1YnMJbmluZS5zdWJzDnBhcmVubGVmdC5zdWJzD3BhcmVucmlnaHQuc3VicwtwZXJpb2Quc3Vicwpjb21tYS5zdWJzCXplcm8uZG5vbQhvbmUuZG5vbQh0d28uZG5vbQp0aHJlZS5kbm9tCWZvdXIuZG5vbQlmaXZlLmRub20Ic2l4LmRub20Kc2V2ZW4uZG5vbQplaWdodC5kbm9tCW5pbmUuZG5vbQ5wYXJlbmxlZnQuZG5vbQ9wYXJlbnJpZ2h0LmRub20LcGVyaW9kLmRub20KY29tbWEuZG5vbQl6ZXJvLm51bXIIb25lLm51bXIIdHdvLm51bXIKdGhyZWUubnVtcglmb3VyLm51bXIJZml2ZS5udW1yCHNpeC5udW1yCnNldmVuLm51bXIKZWlnaHQubnVtcgluaW5lLm51bXIOcGFyZW5sZWZ0Lm51bXIPcGFyZW5yaWdodC5udW1yC3BlcmlvZC5udW1yCmNvbW1hLm51bXINb3JkZmVtaW5pbmUuYQZhLnN1cHMGYi5zdXBzBmMuc3VwcwZkLnN1cHMGZS5zdXBzBmYuc3VwcwZnLnN1cHMGaC5zdXBzBmkuc3VwcwZqLnN1cHMGay5zdXBzBmwuc3VwcwZtLnN1cHMGbi5zdXBzBm8uc3VwcwZwLnN1cHMGcS5zdXBzBnIuc3VwcwZzLnN1cHMGdC5zdXBzBnUuc3VwcwZ2LnN1cHMGdy5zdXBzBnguc3VwcwZ5LnN1cHMGei5zdXBzC2VncmF2ZS5zdXBzC2VhY3V0ZS5zdXBzDHVuaTAyNTkuc3VwcwZhLnN1cGEGZy5zdXBhBmwuc3VwYQRFdXJvB3VuaTAxOTINY29sb25tb25ldGFyeQRsaXJhB3VuaTIwQTYGcGVzZXRhBGRvbmcHdW5pMjBCMQd1bmkyMEIyB3VuaTIwQjUHdW5pMjBCOQd1bmkyMEJBB3VuaTIyMTUKc2xhc2guZnJhYwhvbmV0aGlyZAl0d290aGlyZHMJb25lZWlnaHRoDHRocmVlZWlnaHRocwtmaXZlZWlnaHRocwxzZXZlbmVpZ2h0aHMHdW5pMjIxOQd1bmkwMEI1B3VuaTIyMDYHdW5pMjEyNgd1bmkyMTEzCWVzdGltYXRlZAd1bmkyMTkwB2Fycm93dXAHdW5pMjE5MglhcnJvd2Rvd24HdW5pMjVBMAd1bmkyNUM2B3VuaTI1QzkHdW5pMjc1Mgd0cmlhZ3VwB3VuaTI1QjMHdW5pMjVCNgd1bmkyNUI3B3RyaWFnZG4HdW5pMjVCRAd1bmkyNUMwB3VuaTI1QzEHdW5pMjYxMAd1bmkyNjExB3VuaTI3MTMHdW5pMjY2QQd1bmkyMDMyB3VuaTIwMzMHdW5pMDJCQgd1bmkwMkJDB3VuaTAyQkUHdW5pMDJCRgd1bmkwMkM4B3VuaTAyQzkHdW5pMDJDQQd1bmkwMkNCB3VuaTAyQ0MHdW5pMDMwMAt1bmkwMzAwLmNhcAd1bmkwMzAxC3VuaTAzMDEuY2FwB3VuaTAzMDILdW5pMDMwMi5jYXAHdW5pMDMwMwt1bmkwMzAzLmNhcAd1bmkwMzA0C3VuaTAzMDQuY2FwB3VuaTAzMDYLdW5pMDMwNi5jYXAHdW5pMDMwNwt1bmkwMzA3LmNhcAd1bmkwMzA4C3VuaTAzMDguY2FwB3VuaTAzMDkLdW5pMDMwOS5jYXAHdW5pMDMwQQt1bmkwMzBBLmNhcAd1bmkwMzBCC3VuaTAzMEIuY2FwB3VuaTAzMEMLdW5pMDMwQy5jYXAHdW5pMDMwRgt1bmkwMzBGLmNhcAd1bmkwMzEyB3VuaTAzMTMHdW5pMDMxQgd1bmkwMzIzB3VuaTAzMjQHdW5pMDMyNgd1bmkwMzI3C3VuaTAzMjcuY2FwB3VuaTAzMjgLdW5pMDMyOC5jYXAHdW5pMDMyRQd1bmkwMzMxC3VuaTAzMDgwMzA0D3VuaTAzMDgwMzA0LmNhcAt1bmkwMzA4MDMwMQ91bmkwMzA4MDMwMS5jYXALdW5pMDMwODAzMEMPdW5pMDMwODAzMEMuY2FwC3VuaTAzMDgwMzAwD3VuaTAzMDgwMzAwLmNhcAt1bmkwMzAyMDMwMQ91bmkwMzAyMDMwMS5jYXALdW5pMDMwMjAzMDAPdW5pMDMwMjAzMDAuY2FwC3VuaTAzMDIwMzA5D3VuaTAzMDIwMzA5LmNhcAt1bmkwMzAyMDMwMw91bmkwMzAyMDMwMy5jYXALdW5pMDMwNjAzMDEPdW5pMDMwNjAzMDEuY2FwC3VuaTAzMDYwMzAwD3VuaTAzMDYwMzAwLmNhcAt1bmkwMzA2MDMwOQ91bmkwMzA2MDMwOS5jYXALdW5pMDMwNjAzMDMPdW5pMDMwNjAzMDMuY2FwCXVuaTAzMEMuYQl1bmkwMzI2LmEHdW5pMDBBMAd1bmkyMDA3CnNwYWNlLmZyYWMMbmJzcGFjZS5mcmFjB3VuaTAyNDMHdW5pMDEyQwd1bmkwMTRFB3VuaTAxODAHdW5pMDEyRAd1bmkwMTRGC3VuaTAzMDIwMzA2D3VuaTAzMDIwMzA2LmNhcAd1bmkxRTA2B3VuaTFFMDcHdW5pMUUzNAd1bmkxRTM1B3VuaTFFMTYHdW5pMUUxNwd1bmkxRTUyB3VuaTFFNTMHdW5pMjAxNgd1bmkyMDNEB3VuaTIzMUMHdW5pMjMxRAd1bmkyMzFFB3VuaTIzMUYHdW5pMjdFNgd1bmkyN0U3B3VuaTJFMjIHdW5pMkUyMwd1bmkyRTI0B3VuaTJFMjUGemVyby4wB3plcm8uMHMHemVyby4wcAh6ZXJvLjBwcwVpLnRyawRBLnNjBEIuc2MEQy5zYwRELnNjBEUuc2MERi5zYwRHLnNjBEguc2MESS5zYwRKLnNjBEsuc2METC5zYwRNLnNjBE4uc2METy5zYwRQLnNjBFEuc2MEUi5zYwRTLnNjBFQuc2MEVS5zYwRWLnNjBFcuc2MEWC5zYwRZLnNjBFouc2MJQWdyYXZlLnNjCUFhY3V0ZS5zYw5BY2lyY3VtZmxleC5zYwlBdGlsZGUuc2MMQWRpZXJlc2lzLnNjCkFtYWNyb24uc2MJQWJyZXZlLnNjCEFyaW5nLnNjCnVuaTAxQ0Quc2MKdW5pMUVBMC5zYwp1bmkxRUEyLnNjCnVuaTFFQTQuc2MKdW5pMUVBNi5zYwp1bmkxRUE4LnNjCnVuaTFFQUEuc2MKdW5pMUVBQy5zYwp1bmkxRUFFLnNjCnVuaTFFQjAuc2MKdW5pMUVCMi5zYwp1bmkxRUI0LnNjCnVuaTFFQjYuc2MKQW9nb25lay5zYwVBRS5zYwp1bmkwMjQzLnNjCnVuaTFFMDYuc2MLQ2NlZGlsbGEuc2MJQ2FjdXRlLnNjDkNjaXJjdW1mbGV4LnNjCUNjYXJvbi5zYw1DZG90YWNjZW50LnNjCURjYXJvbi5zYwp1bmkxRTBDLnNjCnVuaTFFMEUuc2MJRGNyb2F0LnNjCUVncmF2ZS5zYwlFYWN1dGUuc2MORWNpcmN1bWZsZXguc2MJRWNhcm9uLnNjDEVkaWVyZXNpcy5zYwpFbWFjcm9uLnNjCUVicmV2ZS5zYw1FZG90YWNjZW50LnNjCnVuaTFFQjguc2MKdW5pMUVCQS5zYwp1bmkxRUJDLnNjCnVuaTFFQkUuc2MKdW5pMUVDMC5zYwp1bmkxRUMyLnNjCnVuaTFFQzQuc2MKdW5pMUVDNi5zYwpFb2dvbmVrLnNjCnVuaTFFMTYuc2MOR2NpcmN1bWZsZXguc2MJR2JyZXZlLnNjDUdkb3RhY2NlbnQuc2MKdW5pMDEyMi5zYwlHY2Fyb24uc2MKdW5pMUUyMC5zYw51bmkwMDQ3MDMwMy5zYw5IY2lyY3VtZmxleC5zYwp1bmkxRTI0LnNjCnVuaTFFMkEuc2MHSGJhci5zYwlJZ3JhdmUuc2MJSWFjdXRlLnNjDkljaXJjdW1mbGV4LnNjCUl0aWxkZS5zYwxJZGllcmVzaXMuc2MKSW1hY3Jvbi5zYw1JZG90YWNjZW50LnNjCnVuaTAxQ0Yuc2MKdW5pMUVDOC5zYwp1bmkxRUNBLnNjCklvZ29uZWsuc2MKdW5pMDEyQy5zYw5KY2lyY3VtZmxleC5zYwp1bmkwMTM2LnNjCnVuaTFFMzQuc2MJTGFjdXRlLnNjCUxjYXJvbi5zYwp1bmkwMTNCLnNjB0xkb3Quc2MKdW5pMUUzNi5zYwp1bmkxRTM4LnNjCnVuaTFFM0Euc2MJTHNsYXNoLnNjCnVuaTFFNDIuc2MJTmFjdXRlLnNjCU5jYXJvbi5zYwlOdGlsZGUuc2MKdW5pMDE0NS5zYwp1bmkxRTQ0LnNjCnVuaTFFNDYuc2MKdW5pMUU0OC5zYwlPZ3JhdmUuc2MJT2FjdXRlLnNjDk9jaXJjdW1mbGV4LnNjCU90aWxkZS5zYwxPZGllcmVzaXMuc2MKT21hY3Jvbi5zYxBPaHVuZ2FydW1sYXV0LnNjCnVuaTAxRDEuc2MKdW5pMUVDQy5zYwp1bmkxRUNFLnNjCnVuaTFFRDAuc2MKdW5pMUVEMi5zYwp1bmkxRUQ0LnNjCnVuaTFFRDYuc2MKdW5pMUVEOC5zYwlPc2xhc2guc2MFT0Uuc2MIT2hvcm4uc2MKdW5pMUVEQS5zYwp1bmkxRURDLnNjCnVuaTFFREUuc2MKdW5pMUVFMC5zYwp1bmkxRUUyLnNjCnVuaTAxRUEuc2MKdW5pMDE0RS5zYwp1bmkxRTUyLnNjCVJhY3V0ZS5zYwlSY2Fyb24uc2MKdW5pMDE1Ni5zYwp1bmkxRTVBLnNjCnVuaTFFNUMuc2MKdW5pMUU1RS5zYwlTYWN1dGUuc2MOU2NpcmN1bWZsZXguc2MJU2Nhcm9uLnNjCnVuaTAxNUUuc2MKdW5pMDIxOC5zYwp1bmkxRTYwLnNjCnVuaTFFNjIuc2MNZ2VybWFuZGJscy5zYwp1bmkxRTlFLnNjCVRjYXJvbi5zYwp1bmkwMTYyLnNjCnVuaTAyMUEuc2MKdW5pMUU2Qy5zYwp1bmkxRTZFLnNjCVVncmF2ZS5zYwlVYWN1dGUuc2MOVWNpcmN1bWZsZXguc2MJVXRpbGRlLnNjDFVkaWVyZXNpcy5zYwpVbWFjcm9uLnNjCVVicmV2ZS5zYwhVcmluZy5zYxBVaHVuZ2FydW1sYXV0LnNjCnVuaTAxRDMuc2MKdW5pMDFENS5zYwp1bmkwMUQ3LnNjCnVuaTAxRDkuc2MKdW5pMDFEQi5zYwp1bmkxRUU0LnNjCnVuaTFFRTYuc2MKVW9nb25lay5zYwhVaG9ybi5zYwp1bmkxRUU4LnNjCnVuaTFFRUEuc2MKdW5pMUVFQy5zYwp1bmkxRUVFLnNjCnVuaTFFRjAuc2MJV2dyYXZlLnNjCVdhY3V0ZS5zYw5XY2lyY3VtZmxleC5zYwxXZGllcmVzaXMuc2MJWWdyYXZlLnNjCVlhY3V0ZS5zYw5ZY2lyY3VtZmxleC5zYwxZZGllcmVzaXMuc2MKdW5pMUU4RS5zYwp1bmkxRUY0LnNjCnVuaTFFRjYuc2MKdW5pMUVGOC5zYwlaYWN1dGUuc2MJWmNhcm9uLnNjDVpkb3Rh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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//D/0v/2/97/+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAA/8YAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+j/6P/aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/6n/2P/Y/6cAAAA7AAAAAAAAAAAAAAAAAAAAAAAA/8L/3QAA/9T/3f/C/+sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9gAZAAAAAAAAAAAAAAAAAAAAAAAA/9gAAAAAAAD/6AAA/+H/sAAZAAn/7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/9j/8QAA//IAAAAA//z/8v/JAAAAAAAPAA0AGAAAAAAAAP/4//YAAP/2AAAAAAAA//L/+v+i/9j/6P+w/8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUABQADv/yABAABAAU/+b/zP/G//IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+gAAP/8//IAAAAA//b/8gAA//0AAAAQAAYAAAAAAAD/8v/8AAAAAAAAAAD/8AAA//YAAP/iAAD/7AAA/+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAQAEP/6AAr//AAAAAAAAAAA//IABv/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/8gAA//z//P/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//wAAP/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+7/8v/8//n/7AAA//b/8gAAAAAAAAAAAAAAAAAAAAD/6P/2/+MAAAAAAAD/9gAA//L/9gAAAAD/zAAOABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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//b/3gAA//L/dgAA//b/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//UAAAAAAAAAAAAAAAAAAAAAAAD/2AAAAAD/7P/5/+z/7P/iAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/6cABgAGAA3/9v+2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//kAAAAAAAAAAAAAAAAAAAAAAAD/6QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//QAA//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//0AAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYADQANABwACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAYADQAAABMAAAAXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYADQANABwACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAYADQAAABMAAAAXAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9gAA/+//7wAAAAAAAAAAAAAAAAAAAAAAAAAA//IAAP/s//YAAAAA/+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//oADQAKAA0ABv/oAAAAAAAAAAAAAAAAAAD/2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAMACQAAAA0AAAAGAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/94AAAAAAAAAAP/lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+z/6P/6/+//7//eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//cAAP/5AAAAAAAAAAD/+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+gAAAAA//b/4gAAAAAAAAAA/4gABAAAAA0AAP+Q/87/9v+yAAD/1QAA/+j/bgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/0gAA/+f/7P/rAAD/9v/sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4n/8gAAAAD/3P+WAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//cAAAAAAAAAAAAAAAAAAAAAAAD/3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/9wAAAAAAAAAAP/oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAD/9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/9gAAAAD/6wAA//f/9wAA/8gAFAAKABQAAP+///L/8P/t//b/6gAA//H/t//9AAD/4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/6AAAABAAAAAAAAAAAAAAAAAAAAAD//AAA/+3/6wAA/+z/9P/n/+3/+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8EAAAAAAAD/8P/EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/2//AAAAAAAAAAAAAAAAAAAAAAAAD/9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+z/9gAAAAAAAAAA//L/8P/5ABT/+QAGAA0ABgAAAAP/8gAA/+//9v/w//n/+wAA//D/9gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAYABgAAAAAAAAAAAAD//P/5AAAAEAAA/+X/8gAAAAAAAP/y//kABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/5//YAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+cAAP/8/74AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/mAAD/5gAAAAAAAAAA//wAAP/yAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//L/8P/IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/8AAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//D/vf/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/9gAAP/v/9MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/vAAD/+QAAAAAAAAAAAAAAAP/sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/9IAAP/2/8kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4v/uAAAAAAAAAAD/4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/rAAD/8gAAAAAAAAAAAAAAAP/oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/rAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+N/8kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/3wAAAAAAAAAAAAAAAAAAAAAAAP98/8YAAAAAAAD/3v/w/98AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/zwAAAAAAAAAAAAAAAAAA/+wAAAAA//kAAP/2AAAAAAAAAAAAAAAAAAAAAP/d//UAAP/8AAD/7AAA//z/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//kAAAAAAAAAAP/oAAAAAAAAAAAAAAAA/98AAAAA//EAAAAAAAD/8gAAAAAAAAAAAAAAAAAAAAD//AAA//b/9gAA/+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//L/6AAAAAAAAAAA/+wAAAAAAAAAAgAEAvYDEQAAAxwDMwAcAzUDNQA0A0ADQQA1AAIAHQAEADcAAABNAE4ANABoAGgANgB+AH4ANwCgAKIAOACoAKgAOwDMAM0APADlAOUAPgD7APsAPwEWARYAQAEsAS0AQQFRAVMAQwFZAVkARgF+AX8ARwGWAZoASQGfAZ8ATgGqAasATwG3AbcAUQHBAcIAUgHKAcoAVALmAuYAVQLwAvAAVgNbA3QAVwOKA4oAcQOnA6cAcgO+A74AcwPkA+QAdAPqA+oAdQQRBBIAdgABAAIDFgMXAAEACQAGABYAFwAgADAAMQNdA20DbgABAAUDEwMUAxUDGgMbAAIAEwAEABMAAAAVADcAEACiAKIAMwDNAM0ANADlAOUANQEtAS0ANgFTAVMANwF/AX8AOAGWAZYAOQGYAZoAOgGfAZ8APQGrAasAPgG3AbcAPwHCAcIAQAHKAcoAQQNbA2oAQgNsA3QAUgPkA+QAWwQSBBIAXAABAAEDEgABAAYAEgAYACwAMgNpA28AAQACAxgDGQABABQABAAIAAwAEgAYAB4AIgAmACwAMgEtAZkBnwGrA1sDXwNjA2kDbwPkAAEAAwL6AwIDBAABADYACQATABkAGwAzADUAcwC2AOQBZwHfAeAB4QHiAeMB5AHlAeYB5wHoAfMB9AH1AfYB9wH4AfkB+gH7AfwCAwIFAhgCIQIjAo8CkAKRApIDYANqA3ADcgQsBC0ELgQvBDAEMQQyBDMENAQ1BDYAAgAtAAQAIAAAACIAJQAdACgAKAAhACoAcgAiAHQAtQBrALcBAgCtAQYBIQD5AS0BLQEVAS8BMAEWATIBMgEYATkBlAEZAZYBlgF1AZgBmwF2AZ4ByQF6AcwBzAGmAeYB5gGnAfoB+gGoAf0CCwGpAg4CGAG4AhsCGwHDAh0CHQHEAh8CHwHFAiECIQHGAiMCIwHHAuAC4QHIAzoDPQHKAz8DPwHOA0IDSQHPA0sDSwHXA1sDXgHYA2ADYQHcA2QDZgHeA2kDigHhA4wDlgIDA6kDrwIOA8ADwwIVA8UDygIZA9MD4gIfA+oD+gIvA/wEEQJABBgEKAJWBCoEKgJnBC0ELQJoBDMEMwJpBDUENgJqAAIAwAAEAAQADAAFAAUADQAGAAYADwAHAAcAFgAIAAgAPAAJAAkAPQAKAAoAEQALAAsAQAAMAAwAQQANAA0AQwAOAA4AEgAPAA8AFAAQABEAQAASABIAFgATABMARwAUABQAFgAVABUAGAAWABYAGgAXABcAHAAYABgAHgAZABkASwAaABoAIAAbABsATQAcABwAIgAdAB0AJAAeAB4AJgAfAB8AMAAgACAAJwAiACIAKgAjACMAKwAkACQALAAlACUALwAoACgALQAqACsALwAsAC0AMAAuAC4ANgAvAC8AMwAwADAANAAxADEANQAyADIANgAzADMAVwA0ADQAOAA1ADUAWAA2ADYAOQA3ADcAOgA4AE0ADABOAE4APABPAFMADwBUAFcAFgBYAGgAPABpAG8AEQBwAHIAQAB0AH4AQQB/AH8AQwCAAIAAEgCBAIEAFACCAIIARQCDAIgAFACJAJAAQACRAKAAFgChAKEAPACiAKcAFwCoAKgAFgCpAK4AGACvALUAGgC3ALsAHAC8AMwAHgDNANIAHwDTANYAIADXAN4AIgDfAOIAJADjAOMAFgDkAOQASQDlAOUAFgDmAPsAJgD8APwAKgD9AQEAJwECAQIALgEGARYAKgEXAR0ALAEeASEALwEtAS0ANgEvATAALQEyATIALgE5AUEALwFCAVEAMAFSAVIAKgFTAVgAMQFZAVkAMAFaAV8AMwFgAWYANAFnAWcAUQFoAW0ANQFuAX4ANgF/AYQANwGFAYgAOAGJAZAAOQGRAZQAOgGWAZYAMAGYAZgANgGZAZkAMAGaAZoANgGbAZsAKwGeAZ4ANQGfAaoAQgGrAckANgHMAcwALgHmAeYACQH6AfoACAH9Af4AKQH/AgAAKAIBAgEAKQICAgIAAQIDAgMAAgIEAgQAVAIFAgUABwIGAgcAVQIIAggAMgIJAgkAVgIKAgoAMgILAgsAVgIOAg4AUgIP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ZG5vbQN0ZnJhYwN6ZnJhYwOEZnJhYwOOZnJhYwOYZnJhYwOibGlnYQOsbGlnYQOybGlnYQO4bGlnYQO+bGlnYQPEbG9jbAPKbG9jbAPQbG9jbAPWbnVtcgPcbnVtcgPibnVtcgPobnVtcgPubnVtcgP0b251bQP6b251bQQAb251bQQGb251bQQMb251bQQSb3JkbgQYb3JkbgQeb3JkbgQkb3JkbgQqb3JkbgQwcG51bQQ2cG51bQQ8cG51bQRCcG51bQRIcG51bQROc2FsdARUc2FsdARgc2FsdARsc2FsdAR4c2FsdASEc2luZgSQc2luZgSWc2luZgScc2luZgSic2luZgSoc21jcASuc21jcAS2c21jcAS+c21jcATGc21jcATOc3MwMQTWc3MwMQTcc3MwMQTic3MwMQToc3MwMQTuc3MwMgT0c3MwMgT6c3MwMgUAc3MwMgUGc3MwMgUMc3MwMwUSc3MwMwUYc3MwMwUec3MwMwUkc3MwMwUqc3MwNAUwc3MwNAU2c3MwNAU8c3MwNAVCc3MwNAVIc3MwNQVOc3MwNQVUc3MwNQVac3MwNQVgc3MwNQVmc3VicwVsc3VicwVyc3VicwV4c3VicwV+c3VicwWEc3VwcwWKc3VwcwWWc3VwcwWic3VwcwWuc3VwcwW6emVybwXGemVybwXMemVybwXSemVybwXYemVybwXeAAAAAgAAAAEAAAACAAAAAQAAAAIAAAABAAAAAgAAAAEAAAACAAAAAQAAAAIACQAKAAAAAgAJAAoAAAACAAkACgAAAAIACQAKAAAAAgAJAAoAAAABABkAAAABABkAAAABABkAAAABABkAAAABABkAAAAFAAQABQAGAAcACAAAAAUABAAFAAYABwAIAAAABQAEAAUABgAHAAgAAAAFAAQABQAGAAcACAAAAAUABAAFAAYABwAIAAAAAQANAAAAAQANAAAAAQANAAAAAQANAAAAAQANAAAAAwAMAA4ADwAAAAMADAAOAA8AAAADAAwADgAPAAAAAwAMAA4ADwAAAAMADAAOAA8AAAABAB4AAAABAB4AAAABAB4AAAABAB4AAAABAB4AAAABAAIAAAABAAIAAAABAAIAAAABAAwAAAABAAwAAAABAAwAAAABAAwAAAABAAwAAAABABYAAAABABYAAAABABYAAAABABYAAAAB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A34DfwOAA4EDggODA4QDhQOGA4cDiAOJA4oDiwOOA48DkAORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDogOjA6QDpQOmA6cDqQOqA6sDrAOtA64DrwOwA7EDsgOzA8ADwQPDA8QDxQPGA8cDyAPJA8oDywPMA80DzgPPA9AD0QPSA9MD1APVA9YD1wPYA9kD2gPbA9wD3QPeA98D4APhA+ID4wPkA+UD5gPnA+gD6QPqA+0D7gPvA/AD8QPyA/MD9AP1A/YD9wP4A/kD+wP8A/0D/gP/BAAEAQQCBAMEBAQFBAYEBwQIBAkECgQLBAwEDQQOBA8EEAQRBBIEEwQUBBUEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQmBCcEKAQpBCoDiwOOA48DkAORA5IDkwOUA5UDlgOZA5oDmwOcA50DngOfA6ADoQOiA6MDpAOlA6YDpwOwA7EDsgOzA7QDtQO2A7cDuAO5A7sDvAO9A74DvgPAA8EDywPMA80DzgPPA9AD0QPSA9MD1APVA9YD1wPYA9kD2gPbA9wD3QPeA98D4APhA+ID4wPkA+UD5gPnA+gD6QPqA+0D7wPuA/AD8QPyA/MD9AP1A/YD9wP4A/kD+wP8A/0D/gP/BAAEAQQCBAMEBAQFBAYEBwQIBAkECgQLBAwEDQQOBA8EEAQRBBIEEwQUBBUEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQmBCcEKAQpBCsB8wH0AfUB9gH3AfgB+QH6AfsB/AHzAfQB9QH2AfcB+AH5AfoB+wH8BFQCMAJrAooCiwKMAvcC+QL7Av0C/wMBAwMDBQMHAwkDCwMNAw8DFwMZAx0DHwMhAyMDJQMnAykDKwMtAy8DMQMzA4wDvwPrA4wDvwPrA0EDjQONA8IDwgOoA6gD7APsA7oAAQhiAHgA9gD8AQIBCAEOARQBGgEgASYBLgE0AToBQAFGAUwBUgFYAV4BZAFqAXABdgF8AYIBiAGOAZQBnAGiAagBrgG0AboBwgHIAdAB1gHcAeQB6gHwAfYB/AICAggCDgIUAhoCIAImAiwCMgI4Aj4CRAJKAlACVgJcAmICaAJuAnQCegKAAoYCjAKSApgCngKkAqoCsAK2ArwCwgLIAs4C1ALaAuAC5gLsAvIC+AL+AwQDCgMQ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'; // fonts.js ends here ================================================ FILE: src/app/test_widget/test_results.js ================================================ /*global components */ /** * @fileOverview This file registers the `test-results` component. This component is the main container and contains procedures for creating new `suites`. {@link test-results.js}, {@link test-widget.js}, {@link test-suite.js} should have executed already. * @name test_results.js * @author Etienne Prud’homme * @license MIT */ /** * Main test container module. * @returns {Object} Method to build a new `suite` of tests. */ var testResults = (function() { 'use strict'; var exports = {}; var proto = {}; var template = '' + '
' + '
' + ' No tests loaded' + ' ' + '
' + '
' + '
' + ''; var buildSuiteElement = function() {}; proto.attachedCallback = function() { var self = this; // console.log(self); var testSuites = self.querySelector('.test-suites'); var hideShowButton = self.querySelector('button.toggle-display'); var placeholder = self.querySelector('em.placeholder'); /** * Builds a new suite of tests. * @param {suite} newSuite - The suite to build * @returns {HTMLElement} The newly created suite. */ buildSuiteElement = function (newSuite) { // toggle button and placeholder views if (hideShowButton.disabled === true) { hideShowButton.removeAttribute('disabled'); } placeholder.textContent = ''; // actually create the suite var _testSuiteFragment = components.createElement('test-suite'); var _testSuite = ''; // Take the first Node (not a comment) for(var i=0, len=_testSuiteFragment.childNodes.length; i ends here ================================================ FILE: src/app/test_widget/test_suite.js ================================================ /*global components */ /** * @fileOverview This file registers the `test-suite` component. {@link test-results} and {@link test-widget} should have executed already. * @name test_suite.js * @author Etienne Prud’homme * @license MIT */ /** * Registers the `test-suite` component. */ (function() { 'use strict'; var self = null; var proto = {}; var template = '' + '
' + '
' + '
' + '
Code:
' + '
' + ''; function updateView() { var suiteName = self.dataset.name; var suitePassed = self.dataset.suitePassed; var suiteCode = self.code; var numberOfTests = self.dataset.numberOfTests; // Is it ever used? var suite = self; var codeContainer = { container: self.getElementsByClassName('suite-code-container')[0], suiteName: self.getElementsByClassName('suite-name')[0], suiteCode: self.getElementsByClassName('suite-code')[0] }; var titleEnd = numberOfTests > 1 ? ' Tests' : ' Test'; self.querySelector('.suite-title').textContent = suiteName + titleEnd; // Redefinition at each update? /** * Displays the secret code. * @param {boolean} show - Whether the code should be shown. */ function displayCode (show) { if (show) { codeContainer.container.style.display = 'block'; codeContainer.suiteName.textContent = suiteName; codeContainer.suiteCode.textContent = suiteCode; } else { codeContainer.container.style.display = 'none'; codeContainer.suiteName.textContent = ''; codeContainer.suiteCode.textContent = ''; } } if (suitePassed === 'true') { displayCode(true); } else { displayCode(false); } } /** * Called when the component is attached to the DOM. */ proto.attachedCallback = function() { var suite = this.suite; // Is it ever used? self = this; updateView(); }; /** * Called when the main container changed its attributes. */ proto.attributeChangedCallback = function() { self = this; updateView(); }; components.registerElement('test-suite', template, proto); })(); // test_suite.js ends here ================================================ FILE: src/app/test_widget/test_widget.js ================================================ /*global MutationObserver, components, sourceSansProFont */ /** * @fileOverview This file provides the test widget module. It injects an iFrame inside the current document to display a list of tests. * @name test_widget.js * @author Etienne Prud’homme * @license MIT */ /** * Module to handle the test widget. * @returns {Object} Methods to build the widget ({@link buildWidget}) and kill it ({@link killWidget}). * @throws {Error} Initialization errors. */ var testWidget = (function() { 'use strict'; var exports = {}; var frameId = null; var frameElement = null; var lastFrameHeight = 0; var lastWindowHeight = null; // TODO: Should we use a link element instead? var outerStyles = '/* The iFrame class. Note that an iFrame acts like a normal element */' + '.test-widget-display {' + 'resize: both;' + 'direction: rtl;' + 'position: fixed;' + 'min-width: 325px;' + 'max-width: 500px;' + 'max-height: 100%;' + 'overflow-y: auto;' + 'border: none;' + 'background-color: rgba(230, 230, 230, 0.9);' + 'opacity: 0.5;' + 'transition: opacity 0.3s, max-height 0.3s;' + '' + 'top: 0px;' + 'right: 0px;' + 'text-align: left;' + 'z-index: 99999 !important;' + '}' + '.test-widget-display:hover {' + 'opacity: 1;' + '}'; var innerStyles = '@font-face{' + 'font-family: "Source Sans Pro";' + 'src: url(data:font/ttf;base64,' + sourceSansProFont + ') format("truetype");' + '} ' + '* {' + 'font-family: "Source Sans Pro", sans-serif;' + '}' + 'body {' + 'padding: 0.5em;' + 'margin: 0;' + '}' + 'img {' + 'height: 2.25em;' + 'margin-bottom: -0.75em;' + '}' + '.udacity-header {' + 'font-size: 2em;' + '}' + '.test-desc {' + 'width: 100%;' + '}' + '.correct {' + 'color: #060;' + '-webkit-animation-duration: 0.5s;' + '-webkit-animation-name: popin;' + 'animation-duration: 0.5s;' + 'animation-name: popin;' + '}' + '.correct::before {' + 'content: "✓ ";' + '}' + '.incorrect {' + 'color: #900;' + '}' + '.incorrect::before {' + 'content: "✗ ";' + '}' + '.error {' + 'color: #a48700;' + '}' + '.error::before {' + 'content: "?? ";' + '}' + '.flex-container {' + 'display: flex;' + 'justify-content: space-between;' + '}' + '.toggle-display {' + 'display: inline-block;' + 'float: right;' + 'height: 2em;' + 'color: white;' + 'box-sizing: border-box;' + 'border-radius: 2px;' + 'border-color: #777;' + 'border: 1px solid transparent;' + 'background-color: #777;' + 'cursor: pointer;' + '}' + '.toggle-display:hover:not(:disabled) {' + 'border-color: #555;' + 'background-color: #555;' + '}' + '.toggle-display:disabled {' + 'background-color: #888;' + 'color: #ddd;' + '}' + '.hide {' + 'max-height: 0px;' + 'overflow: hidden;' + '}' + '.shown::before {' + 'content: "Hide";' + '}' + '.hidden::before {' + 'content: "Show";' + '}' + '.suite-title {' + 'font-size: 1.25em;' + '}' + '.suite-code-container {' + 'background: rgba(0,0,0,0.6);' + 'color: #eee;' + 'display: none;' + 'padding: 6px 0.5em;' + 'margin: 0.5em -0.5em;' + 'text-align: center;' + '}' + '/* Custom animation for the iFrame */' + '@keyframes popin {' + 'from {' + 'font-size: 1em;' + '}' + '25% {' + 'font-size: 1.5em;' + '}' + 'to {' + 'font-size: 1em;' + '}' + '}'; var template = { head: ' Udacity Feedback' + ' ' + // Disabled until a solution is found. Because it’s an injected script, it // wouldn’t be secure to pass the extension path. // ' ' + ' ' + ' ', body: ' ' + ' ' + '
Udacity Feedback
' + '
' + '
' + ' ' + ' ' + '' }; /** * Returns the frame context. * @returns {Document} The current * @throws {Error} Errors about bad initialization. * @private */ var _frameContext = function () { if(frameId === null) { throw new Error('The widget must first be created.'); } var tw = document.getElementById(frameId); if(tw === null) { throw new Error('The “' + frameId + '” iframe doesn’t exist.'); } // Compatibility fix return tw.contentWindow || tw.contentDocument.document || tw.contentDocument; }; /** * Get the widget document. It prevents direct access to the iFrame. * @returns {Document} */ var _frameDocument = function() { return _frameContext().document; }; /** * Calculate the height of the test-widget could have. It can’t be bigger than the window since it has position of fixed. * @returns {} */ var _calculateFrameHeight = function() { var frameHeight = _frameDocument().body.offsetHeight; var windowHeight = window.innerHeight; return frameHeight < windowHeight ? frameHeight : windowHeight; }; /** * Set the `testWidget` frame element height to its inner height (height of child document). */ var _setFrameHeight = function() { var frameHeight = _calculateFrameHeight(); // console.log("frameHeight = ", frameHeight); if(window.innerHeight !== lastWindowHeight || frameHeight !== lastFrameHeight) { lastWindowHeight = window.innerHeight; lastFrameHeight = frameHeight; frameElement.style.height = frameHeight + 'px'; // console.log("frameElement.style.height = ", frameElement.style.height); } // console.log("lastFrameHeight = ", lastFrameHeight); // console.log("lastWindowHeight = ", lastWindowHeight); }; /** * Execute a callback function when the iFrame document changes. * @param {function} callback - The callback to call when the iFrame document changes. */ var _onFrameChange = function(callback) { var frameDocument = _frameDocument(); var observer = new MutationObserver(function(mutations) { // debugger; // console.log('Inside _onFrameChange MutationObserver. Mutation: ', mutations[i]); // console.log('Callback: ', callback.toString()); callback(mutations); }); observer.observe(frameDocument, {childList: true, attributes: true, characterData: true, subtree: true}); }; /** * Initializes the widget with its random ID (Not really useful) and append the widget to the current Document. The widget is an iFrame * @returns {Document} The iFrame document. * @throws {Error} The test widget can’t be loaded. */ var _buildFrame = function() { frameId = 'tw-' + Math.floor(Math.random() * 100000000000).toString(); // Since the iFrame loading is asynchronous var promise = new Promise( function(resolve, reject) { var tw = document.createElement('iframe'); tw.id = frameId; tw.className = 'test-widget-display'; tw.srcdoc = ''; document.body.appendChild(tw); tw.onload = function() { frameElement = tw; window.addEventListener('resize', function() { _setFrameHeight(); }); _onFrameChange(_setFrameHeight); resolve(tw); }; tw.onerror = function(e) { reject(e); }; }).catch(function(e) { throw new Error('Couldn’t load the test widget: ' + e.message); }); return promise; }; /** * Calls {@link _buildFrame} and initialize {@link testResults}. */ var _buildWidget = function() { // Wait for the iFrame to load since it would return null return _buildFrame().then(function() { var testWidgetDisplay = _frameDocument(); // Reviewer: This is only local testWidgetDisplay.head.innerHTML = template.head; testWidgetDisplay.body.innerHTML = template.body; var outerCSS = document.createElement('style'); outerCSS.id = 'outer-styles'; // Reviewer: This is only local outerCSS.textContent = outerStyles; document.head.appendChild(outerCSS); // console.log("testWidgetDisplay = ", testWidgetDisplay); var viewContainer = testWidgetDisplay.querySelector('.view-container'); // console.log("viewContainer = ", viewContainer); // initialize the view options var testResultsElem = components.createElement('test-results'); viewContainer.appendChild(testResultsElem); }); }; /** * Removes the widget from the current Document. */ var _killWidget = function() { var tw = document.getElementById(frameId); var styles = document.getElementById('outer-styles'); document.body.removeChild(tw); document.head.removeChild(styles); frameId = null; }; exports = { buildWidget: _buildWidget, killWidget: _killWidget, // TODO: Doesn’t seem to be used outside frameDocument: _frameDocument }; return exports; })(); // test-widget.js ends here ================================================ FILE: src/js/ActiveTest.js ================================================ /*global TA */ /** * @fileOverview This file contains the prototype of a single running test. * @name ActiveTest.js * @author Cameron Pittman * @license GPLv3 */ // Custom types documentation /** * An object with collector and reporter properties. * @typedef {Object} definition * @property {string} nodes - String containing a CSS selector (i.e. jQuery style). * @property {string} cssProperty - A CSS property written as camelCase (backgroundColor) that will be collected from {@link nodes}. * @property {string} attribute - An HTML attribute will be collected from {@link node}. * @property {AbsolutePosition} absolutePosition - */ /** * An object containing boolean properties. * @typedef {Object} flags * @property {boolean} alwaysRun - The test continues to run even after it passes. * @property {boolean} noRepeat - The test runs only once rather than repeatedly. */ // Implementation /** * Construct a single test that will be run once or repeatedly. * @param {string} rawTest.description - Title that shows up in the test widget list. * @param {flags} rawTest.flags - Flags controlling the test behaviour. * @param {definition} rawTest.definition - * @returns {} * @throws {} */ function ActiveTest(rawTest) { // TODO: will need to validate all of these this.description = rawTest.description; this.flags = rawTest.flags || {}; this.id = parseInt(Math.random() * 1000000); this.testPassed = false; this.debugData = []; this.incorrectInfo = []; this.gradeRunner = function() {}; var self = this; try { // validate the description. if (typeof this.description !== 'string') { throw new TypeError('Every test needs a description string.'); } // validate the flags if (typeof this.flags !== 'object') { throw new TypeError('If assigned, flags must be an object.'); } if (typeof rawTest.definition !== 'object') { throw new TypeError('Every test needs a definition'); } // alwaysRun and noRepeat flags are mutually exclusive if (this.flags.alwaysRun && this.flags.noRepeat) { throw new TypeError('“alwaysRun” and “noRepeat” flags are mutually exclusive. Only one of them can be set.'); } } catch(e) { } this.ta = new TA(this.description); // translates json definitions to method calls self.queueUp = (function(config) { var methodsToQueue = self.ta._translateConfigToMethods(config); return function() { methodsToQueue.forEach(function(method) { try { method(); } catch (e) { self.hasErred(); console.error(self.description + ' has an invalid definition.'); } }); }; })(rawTest.definition); } /** * Set off the fireworks! A test passed! Assumes you mean test passed unless didPass is false. * @param {Boolean} didPass unless didPass === false, method assumes it to be true. * @return {Boolean} [description] */ ActiveTest.prototype.hasPassed = function(didPass) { var attribute = null; if (!didPass) { attribute = false; } else { attribute = true; this.testPassed = true; if (!this.flags.alwaysRun || this.flags.noRepeat) { this.stopTest(); } window.dispatchEvent(new CustomEvent('ud-test-pass', {'detail': this.description})); } this.element.dataset.testPassed = attribute; this.suite.checkTests(); }; ActiveTest.prototype.hasErred = function() { this.stopTest(); this.element.dataset.testPassed = 'error'; }; /** Run a synchronous activeTest every 1000 ms */ ActiveTest.prototype.runTest = function() { var self = this; var noRepeat = this.flags.noRepeat || false; // run only once on load var alwaysRun = this.flags.alwaysRun || false; // keep running even if test passes var optional = this.flags.optional || false; // test does not affect code display var testRunner = function() { var promise = new Promise(function(resolve, reject) { // clear for every run self.debugData = []; self.values = []; self.incorrectInfo = []; // resolve when the test finishes self.ta.onresult = function(result) { resolve(result); }; self.ta.onerror = function(reason, keepGoing) { self.debugData.push(reason); if (!keepGoing) { self.hasErred(); } }; self.ta.onincorrect = function(reason) { self.incorrectInfo.push(reason); }; // clean out the queue from the last run self.ta.queue.clear(); // this call actually runs the test self.queueUp(); }).then(function(gradedTest) { var testCorrect = gradedTest.isCorrect; // TODO: nothing is done with the values. Do something? var testValues = ''; gradedTest.questions.forEach(function(val) { testValues = testValues + ' ' + val.value; self.values.push(testValues); }); self.hasPassed(testCorrect); }); }; if (noRepeat) { testRunner(); } else { testRunner(); this.gradeRunner = window.setInterval(testRunner, 1000); } }; ActiveTest.prototype.stopTest = function() { var self = this; clearInterval(self.gradeRunner); }; // ActiveTest.js ends here ================================================ FILE: src/js/GradeBook.js ================================================ /** * @fileOverview The GradeBook maintains and reports on the state of a set of questions registered by the TA. The GradeBook reports out on the final state of each active_test. * @name GradeBook.js * @author Cameron Pittman * @license GPLv3 */ /** * The GradeBook constructor sets questions and passed to default values. */ function GradeBook() { this.questions = []; this.passed = false; }; Object.defineProperties(GradeBook.prototype, { numberOfQuestions: { /** * Find the number of questions. * @return {Number} number of questions */ get: function() { return this.questions.length; } }, numberCorrectQuestions: { /** * Find the number of questions evaluated as correct. * @return {Number} numberCorrect - number of correct questions. */ get: function() { var numberCorrect = 0; this.questions.forEach(function(question) { if (question.correct) { numberCorrect += 1; } }); return numberCorrect; } }, allCorrect: { /** * Compares the total questions to total questions correct. * @return {Boolean} isAllGood - true if all are correct and false otherwise. */ get: function() { var isAllGood = false; if (this.numberOfQuestions === this.numberCorrectQuestions && this.numberOfQuestions > 0) { isAllGood = true; } return isAllGood; } }, numberWrongQuestions: { /** * Find the number of wrong questions. * @return {Number} numberWrong - the number of wrong questions. */ get: function() { var numberWrong = 0; numberWrong = numberOfQuestions - numberCorrectQuestions; return numberWrong; } }, report: { /** * Returns all questions and the overall correctness of the active_test. Note: this is the data returned to the active_test component. * @return {Object} - contains a boolean indicating whether the test passes and an array of all questions. */ get: function() { return { isCorrect: this.passed, questions: this.questions }; } } }); /** * Takes in a set of values from the target. Adds to gradebook. * @param {object} target - only what the GradeBook needs to know about the Target */ GradeBook.prototype.recordQuestion = function(target) { target.correct = false; this.questions.push(target); }; /** * Empties the questions array and ensures that the test hasn’t passed prematurely. Called each time a new question is registered. */ GradeBook.prototype.reset = function() { this.questions = []; this.passed = false; }; /** * Will iterate through all the questions and return if they meet grade criteria * @param {Object} config - {String} config.strictness, {Boolean} config.not, {Function} config.callback * @return {Object} the report from the gradebook instance containing whether the test passed and all of the questions in consideration. */ GradeBook.prototype.grade = function(config) { var strictness; var not; var callback; strictness = config.strictness; not = config.not; callback = config.callback; this.questions.forEach(function(question) { question.correct = callback(question); if (not) { question.correct = !question.correct; } }); if (strictness === 'some') { if (this.numberCorrectQuestions <= this.numberOfQuestions && this.numberCorrectQuestions > 0) { this.passed = true; }; } else if (typeof strictness === 'number' && strictness > 0) { if (this.numberCorrectQuestions <= strictness && this.numberCorrectQuestions > 0) { this.passed = true; } } else { this.passed = this.allCorrect; } // one last check to make sure there actually were questions if (this.numberOfQuestions === 0 && not) { this.passed = !this.passed; }; return this.report; }; // GradeBook.js ends here ================================================ FILE: src/js/Queue.js ================================================ /** * @fileOverview This file contains a `queue` Data Structure implementation for chaining promises. * @see http://www.dustindiaz.com/async-method-queues * @see http://www.mattgreer.org/articles/promises-in-wicked-detail/ * @name Queue.js * @author Cameron Pittman * @license GPLv3 */ /** * Queue Data Structure implementation to chain promises. */ function Queue() { this._methods = []; this._flushing = false; this._blocked = false; } Queue.prototype = { add: function(fn) { this._methods.push(fn); if (!this._flushing && !this._blocked) { this.step(); } }, clear: function() { this._flushing = false; this._methods = []; }, step: function() { var self = this; if (!this._flushing) { this._flushing = true; } function executeInPromise(fn) { return new Promise(function (resolve, reject) { if (fn) { try { var ret = fn(); } catch (e) { self.block(); } } resolve(ret); }); } if (!this._blocked) { executeInPromise(this._methods.shift()).then(function(resolve) { if (self._methods.length > 0) { self.step(); } }); } }, block: function() { this._blocked = true; }, unblock: function() { this._blocked = false; this.step(); } }; // Queue.js ends here ================================================ FILE: src/js/README.md ================================================ ## Front-End Grading Engine The files in this directory get concatenated into `ext/app/js/libs/GE.min.js`. See the build script for its order. Before being an extension, the _Front-End Grading Engine_ was a JavaScript library to be used in the page itself. ### Commentary Files as class definitions are capitalized. ================================================ FILE: src/js/Suite.js ================================================ /*global ActiveTest, components */ /** * @fileOverview This file contains the constructor for a `Suite` of tests. * @name Suite.js * @author Cameron Pittman * @license GPLv3 */ function Suite(rawSuite) { var name = rawSuite.name; var code = rawSuite.code; var activeTests = []; var id = parseInt(Math.random() * 1000000); // validate the name if (typeof name !== 'string') { throw new TypeError('Every suite needs a name string.'); } // validate the code if (typeof code !== 'string') { throw new TypeError('Every suite needs a code string.'); } this.name = name; this.code = code; this.activeTests = []; this.id = id; this.suitePassed = false; // put a setter on this to emit an event. } Object.defineProperties(Suite.prototype, { numberOfTests: { get: function() { return this.activeTests.length || 0; } }, numberOfCorrectTests: { get: function() { var numberCorrect = 0; this.activeTests.forEach(function(test) { if (test.testPassed) { numberCorrect += 1; } }); return numberCorrect; } }, numberOfCorrectOrOptionalTests: { get: function() { var numberCorrectOrOptional = 0; this.activeTests.forEach(function(test) { if (test.optional || test.testPassed) { numberCorrectOrOptional += 1; } }); return numberCorrectOrOptional; } }, numberOfOptionalTests: { get: function() { var numberOptional = 0; this.activeTests.forEach(function(test) { if (test.optional) { numberOptional += 1; } }); } }, allCorrect: { get: function() { var allGood = false; if (this.numberOfTests - this.numberOfCorrectOrOptionalTests <= 0) { allGood = true; } return allGood; } } }); Suite.prototype.getDebugData = function() { this.activeTests.forEach(function(at) { if (at.debugData.length > 0) { console.warn('%c' + 'ERROR: ' + at.description + ': ' + at.debugData.join(' '), 'color: red;'); } }); }; Suite.prototype.getIncorrectInfo = function() { this.activeTests.forEach(function(at) { if (at.incorrectInfo.length > 0) { console.warn('Incorrect: ' + at.description + ': ' + at.incorrectInfo.join('\n')); } }); }; Suite.prototype.getValues = function() { this.activeTests.forEach(function(at) { if (at.values.length > 0) { console.warn('Collected Values: ' + at.description + ': ' + at.values.join('\n')); } }); }; Suite.prototype.createTest = function(rawTest) { var activeTest = new ActiveTest(rawTest); activeTest.suite = this; function createTestElement(newTest) { var activeTestFragment = components.createElement('active-test'); var activeTestElement = ''; // When appending a fragment, it becomes void for(var i=0, len=activeTestFragment.childNodes.length; i ends here ================================================ FILE: src/js/TACollectors.js ================================================ /*global Target, GradeBook, Queue, getDomNodeArray */ /** * @fileOverview The Teaching Assistant (TA) is responsible for: * • collecting data from the page and creating a tree of Targets (called a bullseye) representing the information * • traverseing the bullseye and reporting relevant data from Targets and grading instructions into a GradeBook. * • All collectors return the instance of the TA object for chaining. * • Collectors register their operations with the GradeBook, which actually checks the results of the tests. * @name TACollectors.js * @author Cameron Pittman * @license GPLv3 */ /** * The TA constructor sets default values and instantiates a GradeBook. */ function TA(description) { this.target = null; this.gradebook = new GradeBook(); this.operations = []; this.gradeOpposite = false; this.picky = false; this.queue = new Queue(); this.description = description; } Object.defineProperties(TA.prototype, { childPosition: { /** * To find a child node’s index in relation to its immediate siblings * @return {object} TA - the TA instance for chaining. */ get: function() { var self = this; this.queue.add(function() { self._runAgainstBottomTargets(function(target) { var elem = target.element; var position = null; // TODO: correct for other non-normal DOM elems? var ignoreTheseNodes = 0; Array.prototype.slice.apply(target.element.parentNode.children).forEach(function(val, index) { if (val.nodeName === '#text') { ignoreTheseNodes += 1; } if (val === elem) { position = index - ignoreTheseNodes; } }); return position; }); }); return this; } }, count: { /** * To count the number of children at the bottom level of the bullseye * @return {object} TA - the TA instance for chaining. */ get: function() { var self = this; this.queue.add(function() { // doing more than accessing a property on existing target // because counting can move up the bullseye to past // Targets. Need to reset operations self._registerOperation('count'); self._runAgainstNextToBottomTargets(function(target) { var length = null; try { // A `element` is the result of calling `children` (with a // query) that didn’t contain any elements. length = target.children.reduce(function(previous, current) { if(current.element !== null) { return previous + 1; } return previous; }, 0); } catch (e) { length = 0; } return length; }); }); return this; } }, innerHTML: { /** * To pull the innerHTML of a DOM node. * @return {object} TA - the TA instance for chaining. */ get: function() { var self = this; this.queue.add(function() { self._registerOperation('innerHTML'); self._runAgainstBottomTargetElements(function(element) { var html = ''; try { html = element.innerHTML; } catch (e) { self.onerror('Cannot get innerHTML. Element probably doesn’t exist.', true); } return html; }); }); return this; } }, _targetIds: { /** * Not a collector! Private use only. Get an array of all target ids. * @return {array} ids of all targets in the bullseye. */ get: function() { var ids = []; this._traverseTargets(function(target) { ids.push(target.id); }); return ids; } }, UAString: { /** * Get the User-Agent string of the browser. * @return {object} TA - the TA instance for chaining. */ get: function() { var self = this; this.queue.add(function() { self._registerOperation('UAString'); self.target = new Target(); self._runAgainstTopTargetOnly(function(topTarget) { var ua = ''; try { ua = navigator.userAgent; } catch (e) { self.onerror('Can’t find a user agent string.', true); } return ua; }); }); return this; } }, DPR: { /** * Get the Device Pixel Ratio of the viewport. * @return {object} TA - the TA instance for chaining. */ get: function() { var self = this; this.queue.add(function() { self._registerOperation('DPR'); self.target = new Target(); self._runAgainstTopTargetOnly(function(topTarget) { var dpr = null; try { dpr = +window.devicePixelRatio; } catch (e) { self.onerror('Can’t find device pixel ratio.', true); } return dpr; }); }); return this; } } }); /** * Initialized for async call later. */ TA.prototype.onresult = function(testResult) {}; /** * Let the TA know this just happened and refresh the questions in the GradeBook. * @param {string} operation - the thing that just happened */ TA.prototype._registerOperation = function(operation) { this.operations.push(operation); this.gradebook.reset(); }; /** * Private method to traverse all targets in the bullseye. * @param {Function} callback - method to call against each target */ TA.prototype._traverseTargets = function(callback) { // http://www.timlabonne.com/2013/07/tree-traversals-with-javascript/ /** * Recursively dive into a tree structure from the top. Used on the Target structure here. * @param {object} node - a target of bullseye. Start with the top. * @param {function} callback - function to run against each node */ function visitDfs (node, callback) { if (callback) { callback(node); } node.children.forEach(function(child, index, arr) { visitDfs(child, callback); }); } visitDfs(this.target, callback); }; /** * Run a function against the top-level Target in the bullseye * @param {function} callback - the function to run against specified Targets */ TA.prototype._runAgainstTopTargetOnly = function(callback) { var self = this; this.target.value = callback(this.target); if (this.target.value !== undefined && this.target.value !== null) { self.gradebook.recordQuestion(this.target); } else { this.target.children.forEach(function(kid) { self.gradebook.recordQuestion(kid); }); } }; /** * Run a function against bottom targets in the bullseye * @param {function} callback - the function to run against specified Targets */ TA.prototype._runAgainstBottomTargets = function(callback) { var self = this; var allTargets = this._targetIds; this._traverseTargets(function(target) { if (!target.hasChildren && allTargets.indexOf(target.id) > -1) { target.value = callback(target); if (target.value !== undefined && target.value !== null) { self.gradebook.recordQuestion(target); } else { target.children.forEach(function(kid) { self.gradebook.recordQuestion(kid); }); } } }); }; /** * Run a function against the elements of the bottom targets in the bullseye * @param {function} callback - the function to run against specified elements */ TA.prototype._runAgainstBottomTargetElements = function(callback) { var self = this; var allTargets = this._targetIds; this._traverseTargets(function(target) { if (!target.hasChildren && allTargets.indexOf(target.id) > -1) { target.value = callback(target.element); if (target.value !== undefined && target.value !== null) { self.gradebook.recordQuestion(target); } else { target.children.forEach(function(kid) { self.gradebook.recordQuestion(kid); }); } } }); }; /** * Run a function against the next to bottom targets in the bullseye * @param {function} callback - the function to run against specified elements */ TA.prototype._runAgainstNextToBottomTargets = function(callback) { var self = this; this._traverseTargets(function(target) { if (target.hasChildren && !target.hasGrandkids) { target.value = callback(target); if (target.value !== undefined && target.value !== null) { self.gradebook.recordQuestion(target); } else { target.children.forEach(function(kid) { self.gradebook.recordQuestion(kid); }); } } }); }; /** * Generates the top-level target. Matched elements end up as children targets. It will not have a element. * @param {string} CSS selector - the selector of the elements you want to query * @return {object} TA - the TA instance for chaining. */ TA.prototype.theseElements = function(selector) { var self = this; this.queue.add(function() { self._registerOperation('gatherElements'); self.target = new Target(); self._runAgainstTopTargetOnly(function(topTarget) { var elems = getDomNodeArray(selector); if (!selector) { self.onerror('Cannot find elements without a selector.', true); } else if (elems.length > 0) { elems.forEach(function(elem, index, arr) { var target = new Target(); target.element = elem; target.index = index; topTarget.children.push(target); }); } }); }); return this; }; // more common syntax TA.prototype.nodes = TA.prototype.theseElements; /** * Will run a query against the lowest level targets in the Target tree. Note it will traverse all the way down the DOM. * @param {string} CSS selector - the selector of the children you want to query * @return {object} TA - the TA instance for chaining. */ TA.prototype.deepChildren = function(selector) { var self = this; this.queue.add(function() { self._registerOperation('gatherDeepChildElements'); self._runAgainstBottomTargets(function(target) { var elems = getDomNodeArray(selector, target.element); if (!selector) { self.onerror('Cannot find elements without a selector.', true); throw new Error(); } else if (target.element) { if(elems.length === 0) { var childTarget = new Target(); childTarget.element = null; childTarget.index = null; target.children.push(childTarget); } elems.forEach(function(newElem, index) { var childTarget = new Target(); childTarget.element = newElem; childTarget.index = index; target.children.push(childTarget); }); } }); }); }; // for alternate syntax options TA.prototype.children = TA.prototype.deepChildren; TA.prototype.get = function(typeOfValue) { var self = this; switch (typeOfValue) { case 'count': self.count; break; case 'childPosition': self.childPosition; break; case 'innerHTML': self.innerHTML; break; case 'UAString': self.UAString; break; case 'DPR': self.DPR; break; default: self.onerror('Cannot “get”: “' + typeOfValue + '”. Options include: “count”, “childPosition”, “DPR”, “innerHTML”, and “UAString”.'); throw new Error(); } }; TA.prototype.limit = function(limit) { var self = this; if (!limit || limit < 1) { self.onerror('Illegal “limit”. Options include: any positive number, “all” or “some”. Defaults to “all”'); throw new Error(); } this.queue.add(function() { self.strictness = limit; }); return this; }; /** * Get any CSS style of any element. * @param {string} property - the CSS property to examine. Should be camelCased. * @return {object} TA - the TA instance for chaining. */ TA.prototype.cssProperty = function(property) { var self = this; this.queue.add(function() { self._registerOperation('cssProperty'); self._runAgainstBottomTargetElements(function(elem) { var style = null; try { // TODO: this causes a FSL that could affect framerate? style = self._getComputedValue(property, elem); } catch (e) { self.onerror('Cannot get CSS property: “' + property + '”.', true); } return style; }); }); return this; }; /** * Get a specified CSS property value. * @param {string} property - The CSS property name. * @param {HTMLElement} elem - The Element to get the CSS property value. * @returns {string} Either the CSS computed value or a tweaked value (depending * on the property name). * @throws {Error} Bad arguments. */ TA.prototype._getComputedValue = function(property, elem) { var self = this, computedStyles = window.getComputedStyle(elem), value = null; /** * Calculates the margin from a given side. It should only be used with * element having a normal flow. * @param {string} marginName - The margin side. * @returns {string} The tweaked margin value. * @throws {Error} Bad arguments or the CSS property is invalid. * @todo Implement `marginRight` and `marginBottom` */ function getMarginSide(marginName) { var parent = elem.parentElement, // An other container is used to prevent getting the parent padding wrapper = document.createElement('div'), // We need children for calculation (min/max) clone = elem.cloneNode(true), result; // If the position is different than static, it may use the left property // and it’s also hard to take them into account. if(computedStyles.position !== 'static') { // When both left and right are set, left has precedence over right when // the direction is ltr or right when rtl. throw new Error('“getMargin” only support the “static” position'); } // Because the wrapper must be without any of those wrapper.style.border = 'none'; wrapper.style.padding = '0'; wrapper.style.margin = '0'; wrapper.style.position = 'static'; wrapper.style.display = 'block'; wrapper.style.height = 'auto'; wrapper.style.width = 'auto'; wrapper.appendChild(clone); // The parent element of `elem` will get `wrapper` before the `elem` Node parent.insertBefore(wrapper, elem); /** * Calculate the offset from a given side. It thus give the margin if used * We never know about custom styleswith a static position and if the actual * We never know about custom stylesside was set. * @param {string} marginName - The name of the margin as camel case. * @returns {int} The calculated margin. * @throws {Error} The {@link marginName} argument isn’t valid. */ function calculateMarginForSide(marginName) { var value; switch(marginName) { case 'marginLeft': value = clone.offsetLeft - wrapper.offsetLeft; break; case 'marginTop': value = clone.offsetTop - wrapper.offsetTop; break; case 'marginRight': value = wrapper.clientWidth - (parseInt(window.getComputedStyle(clone).width) + calculateMarginForSide('marginLeft')); break; case 'marginBottom': value = wrapper.clientHeight - (parseInt(window.getComputedStyle(clone).height) + calculateMarginForSide('marginTop')); break; default: throw new Error('Wrong type of arguments for “marginName”'); } return value; } // Cache the result if we want to remove the wrapper result = calculateMarginForSide(marginName); wrapper.remove(); return result; } // Specific tweaks for CSS properties switch(property) { case 'marginTop': case 'marginRight': case 'marginBottom': case 'marginLeft': // Firefox (and Safari?) don’t use the CSS2 specs to calculate the margin // when set to `auto` if(computedStyles[property] === '0px' && computedStyles.display === 'block') { value = getMarginSide(property) + 'px'; } break; default: break; } // No special tweaks if(value === null) { value = computedStyles[property]; // A valid CSS value should never be undefined if(value === undefined) { throw new Error(); } } // Return the tweaked computed value or the actual value if no tweaks return value; }; /** * Get any attribute of any element. * @param {string} attribute - the attribute under examination. * @return {object} TA - the TA instance for chaining. */ TA.prototype.attribute = function(attribute) { var self = this; this.queue.add(function() { self._registerOperation('attribute'); self._runAgainstBottomTargetElements(function(elem) { var attrValue = null; try { attrValue = elem.getAttribute(attribute); } catch (e) { self.onerror('Cannot get attribute “' + attribute + '”.', true); } if (attrValue === '') { attrValue = true; } return attrValue; }); }); return this; }; // TODO: Is this even used? Seems to be duplicate of {@link TA.prototype.attribute} /** * Get any property of an object. * @param {string} attribute - the attribute under examination. * @return {object} TA - the TA instance for chaining. */ TA.prototype.property = function(key) { var self = this; this.queue.add(function() { self._registerOperation('property'); self._runAgainstBottomTargetElements(function(obj) { var propertyValue = null; try { propertyValue = obj[key]; } catch (e) { self.onerror('Cannot get attribute “' + attribute + '”.', true); } if (propertyValue === '') { propertyValue = true; } return propertyValue; }); }); return this; }; /** * Get the position of one side of an element relative to the viewport * @param {string} side - the side of the element in question * @return {object} TA - the TA instance for chaining. */ TA.prototype.absolutePosition = function(side) { var self = this; this.queue.add(function() { self._registerOperation('absolutePosition'); // http://stackoverflow.com/questions/2880957/detect-inline-block-type-of-a-dom-element function getDisplayType (element) { var cStyle = element.currentStyle || window.getComputedStyle(element, ''); return cStyle.display; }; function isValidSide(side) { if(side === 'top' || side === 'left' || 'bottom' || 'right') { return true; } console.warn('You didn’t pick a side for absolutePosition! Options are “top”, “left”, “bottom” and “right”.'); return false; } function getOffsetBySide(element, sideName) { var offset = NaN; switch (sideName) { case 'top': offset = element.offsetTop; break; case 'left': offset = element.offsetLeft; break; case 'bottom': offset = element.offsetTop + element.offsetHeight; break; case 'right': offset = element.offsetLeft + element.offsetWidth; break; } return offset; } var selectorFunc = function(elem) { var displayType = getDisplayType(elem); var value = NaN; var maxSize; if(!isValidSide(side)) { return value; } if (displayType === 'block') { value = getOffsetBySide(elem, side); } else if (displayType === 'inline') { value = elem.getBoundingClientRect()[side]; } // To get the widest size of the window, we need to get the biggest value of client and inner. if(side === 'bottom') { // Get the widest window height maxSize = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); value = value === maxSize ? 'max' : value ; } else if(side === 'right') { // Get the widest window width maxSize = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); value = value === maxSize ? 'max' : value; } return value; }; self._runAgainstBottomTargetElements(function(elem) { var absPos = null; try { absPos = selectorFunc(elem); } catch (e) { self.onerror('Cannot get absolute position of “' + side + '”.', true); throw new Error(); } return absPos; }); }); return this; }; /** * Must be used with noRepeat: true * Waits for an event. Grades against event.detail * @param {String} eventName - custom event to listen for * @return {Object} TA for chaining */ TA.prototype.waitForEvent = function(eventName) { var self = this; self.queue.block(); window.addEventListener(eventName, function(e) { self.queue.unblock(); self._runAgainstTopTargetOnly(function(topTarget) { return e.detail; }); }); this.queue.add(function() { self._registerOperation('gatherElements'); self.target = new Target(); }); return this; }; // TACollectors.js ends here ================================================ FILE: src/js/TAReporters.js ================================================ /** * @fileOverview Reporters live on the TA and are responsible for: * giving the GradeBook instructions for evaluating the questions it has collected. * instantiating the grading process by calling gradebook.grade() * @name TAReporters.js * @author Cameron Pittman * @license GPLv3 */ /** * Checks that either values or elements exist on questions in GradeBook. */ TA.prototype.exists = function(bool) { var self = this; if (bool === false && typeof bool === 'boolean') { self.not(true); } this.queue.add(function() { var typeOfOperation = self.operations[self.operations.length - 1]; var doesExistFunc = function() {}; switch (typeOfOperation) { case 'gatherElements': doesExistFunc = function(topTarget) { var doesExist = false; if (topTarget.children.length > 0 || topTarget.element || topTarget.value) { doesExist = true; } if (!doesExist) { self.onincorrect('does not exist'); } return doesExist; }; break; case 'gatherDeepChildElements': doesExistFunc = function(target) { var doesExist = false; if (target.element) { doesExist = true; } if (!doesExist) { self.onincorrect('does not exist'); } return doesExist; }; break; default: doesExistFunc = function(target) { var doesExist = false; if (target.value || target.element) { doesExist = true; } if (!doesExist) { self.onincorrect('does not exist'); } return doesExist; }; break; } var testResult = self.gradebook.grade({ callback: doesExistFunc, not: self.gradeOpposite, strictness: self.strictness }); self.onresult(testResult); }); }; /** * Used by the GradeBook to negate the correctness of a test. * @param {Boolean} bool The gradeOpposite param gets set to this. Will default to true if it isn’t present or is not specifically false. */ TA.prototype.not = function(bool) { var self = this; if (typeof bool !== 'boolean') { bool = true; } this.queue.add(function() { if (bool) { self.gradeOpposite = true; } }); }; /** * Check that question values match an expected value. Always uses strict equality. * @param {*} expected - string, number or array of string and numbers. */ TA.prototype.equals = function(config) { var self = this; this.queue.add(function() { var expected; if (typeof config === 'object' && !(config instanceof Array)) { expected = config.expected; } else { expected = config; } if (typeof expected !== 'string' && typeof expected !== 'number' && !(expected instanceof Array)) { self.onerror('“equals” needs a string, a number, or an array of string and number values.'); throw new Error(); } if (!(expected instanceof Array)) { expected = [expected]; } var equalityFunc = function(target) { var isCorrect = false; expected.forEach(function(e) { if (target.value === e) { isCorrect = true; } }); if (!isCorrect) { self.onincorrect(target.value.toString() + ' is not one of: [' + expected.join(', ') + '].'); } return isCorrect; }; var testResult = self.gradebook.grade({ callback: equalityFunc, not: self.gradeOpposite, strictness: self.strictness }); self.onresult(testResult); }); }; /** * Check that the target value is greater than the given value. * @param {Number} expected - the number for comparison * @param {boolean} orEqualTo - if true, run as >= instead of > */ TA.prototype.isGreaterThan = function(config) { var self = this; this.queue.add(function() { var expected = config.expected || config; var orEqualTo = config.orEqualTo || false; if (typeof expected !== 'number') { self.onerror('“isGreaterThan” needs a number.'); throw new Error(); } var greaterThanFunc = function() {}; switch (orEqualTo) { case true: greaterThanFunc = function(target) { var isGreaterThan = false; if (getUnitlessMeasurement(target.value) >= getUnitlessMeasurement(expected)) { isGreaterThan = true; } if (!isGreaterThan) { self.onincorrect(target.value + ' is not greater than ' + expected); } return isGreaterThan; }; break; default: greaterThanFunc = function(target) { var isGreaterThan = false; if (getUnitlessMeasurement(target.value) > getUnitlessMeasurement(expected)) { isGreaterThan = true; } if (!isGreaterThan) { self.onincorrect(target.value + ' is not greater than ' + expected); } return isGreaterThan; }; break; } var testResult = self.gradebook.grade({ callback: greaterThanFunc, not: self.gradeOpposite, strictness: self.strictness }); self.onresult(testResult); }); }; /** * Check that the target value is less than the given value. * @param {Number} expected - the number for comparison * @param {boolean} orEqualTo - if true, run as <= instead of < */ TA.prototype.isLessThan = function(config) { var self = this; this.queue.add(function() { var expected = config.expected || config; var orEqualTo = config.orEqualTo || false; if (typeof expected !== 'number') { self.onerror('“isLessThan” needs a value.'); throw new Error(); } var lessThanFunc = function() {}; switch (orEqualTo) { case true: lessThanFunc = function(target) { var isLessThan = false; if (getUnitlessMeasurement(target.value) <= getUnitlessMeasurement(expected)) { isLessThan = true; } if (!isLessThan) { self.onincorrect(target.value + ' is not less than ' + expected); } return isLessThan; }; break; default: lessThanFunc = function(target) { var isLessThan = false; if (getUnitlessMeasurement(target.value) < getUnitlessMeasurement(expected)) { isLessThan = true; } if (!isLessThan) { self.onincorrect(target.value + ' is not less than ' + expected); } return isLessThan; }; break; } var testResult = self.gradebook.grade({ callback: lessThanFunc, not: self.gradeOpposite, strictness: self.strictness }); self.onresult(testResult); }); }; /** * Check that the target value is between upper and lower. * @param {Number} lower - the lower bounds of the comparison * @param {Number} upper - the upper bounds of the comparison * @param {Boolean} lowerInclusive - if true, run lower check as >= instead of > * @param {Boolean} upperInclusive - if true, run upper check as <= instead of < */ TA.prototype.isInRange = function(config) { // TODO: would be fantastic to use isLessThan and isGreaterThan instead var self = this; this.queue.add(function() { var lower = getUnitlessMeasurement(config.lower); var upper = getUnitlessMeasurement(config.upper); var lowerInclusive = config.lowerInclusive || true; var upperInclusive = config.upperInclusive || true; // just in case someone screws up the order if (lower > upper) { var temp = lower; lower = upper; upper = temp; }; if (typeof lower !== 'number' || typeof upper !== 'number') { self.onerror("“isInRange” needs an upper and a lower value in its config object."); throw new Error(); } var xIsLessThan = function() {}; switch (upperInclusive) { case true: xIsLessThan = function(target) { var isInRange = false; if (getUnitlessMeasurement(target.value) <= getUnitlessMeasurement(upper)) { isInRange = true; } if (!isInRange) { self.onincorrect(target.value + ' is not less than ' + upper); } return isInRange; }; break; default: xIsLessThan = function(target) { var isInRange = false; if (getUnitlessMeasurement(target.value) < getUnitlessMeasurement(upper)) { isInRange = true; } if (!isInRange) { self.onincorrect(target.value + ' is not less than ' + upper); } return isInRange; }; break; } var xIsGreaterThan = function() {}; switch (lowerInclusive) { case true: xIsGreaterThan = function(target) { var isInRange = false; if (getUnitlessMeasurement(target.value) >= getUnitlessMeasurement(lower)) { isInRange = true; } if (!isInRange) { self.onincorrect(target.value + ' is not greater than ' + lower); } return isInRange; }; break; default: xIsGreaterThan = function(target) { var isInRange = false; if (getUnitlessMeasurement(target.value) > getUnitlessMeasurement(lower)) { isInRange = true; } if (!isInRange) { self.onincorrect(target.value + ' is not greater than ' + lower); } return isInRange; }; break; } var inRangeFunc = function(target) { var isInRange = false; if (xIsLessThan(target) && xIsGreaterThan(target)) { isInRange = true; } return isInRange; }; var testResult = self.gradebook.grade({ callback: inRangeFunc, not: self.gradeOpposite, strictness: self.strictness }); self.onresult(testResult); }); }; /** * Check that the value includes at least one of the given expected values. * @param {Array} expectedValues - search for one of the values in the array using regex * @param {Object} config - includes: nValues, minValues, maxValues. Designate the number of values in expectedValues expected to be found in the target value. Defaults to at least one value needs to be found. * @return {object} result - the GradeBook’s list of questions and overall correctness. */ TA.prototype.hasSubstring = function(config) { var self = this; this.queue.add(function() { config = config || ''; var expectedValues = config.expected; // this simplifies JSON syntax if (typeof config === 'string' || config instanceof Array) { expectedValues = config; } // make sure expectedValues are an array if (!(expectedValues instanceof Array)) { expectedValues = [expectedValues]; }; var nValues = config.nValues || false; var minValues = config.minValues || 1; var maxValues = config.maxValues || expectedValues.length; if (!expectedValues || expectedValues.length === 0) { self.onerror('“hasSubstring” needs at least one regex comparison.'); throw new Error(); }; if (typeof minValues !== 'number' || typeof maxValues !== 'number') { self.onerror('“hasSubstring” “minValue” and “maxValue” need to be numbers.'); throw new Error(); }; /** * Is there a substring in a string? This will answer that question. * @param {object} target - the Target in question * @return {boolean} - whether or not expected substring is in target.value */ var substringFunc = function(target) { var hasNumberOfValsExpected = false; var hits = 0; expectedValues.forEach(function(val) { var matches = target.value.match(new RegExp(val)) || []; if (matches.length > 0) { hits += 1; } else { self.onincorrect(val + ' did not hit against ' + target.value.slice(0, 20)); } }); if (nValues) { (hits === nValues) ? hasNumberOfValsExpected = true : hasNumberOfValsExpected = false; } else if (hits >= minValues && hits <= maxValues) { hasNumberOfValsExpected = true; }; return hasNumberOfValsExpected; }; var testResult = self.gradebook.grade({ callback: substringFunc, not: self.gradeOpposite, strictness: self.strictness }); self.onresult(testResult); }); }; // get all the exposed methods so that the translator knows what’s acceptable var taAvailableMethods = Object.getOwnPropertyNames(TA.prototype).filter(function(key) { return key.indexOf('_') === -1 && key !== 'constructor'; }); TA.prototype._translateConfigToMethods = function(config) { var self = this; // return an array of anonymous functions that are closed over this scope. var methods = []; // so either nodes or elements works in config object config['nodes'] = config['nodes'] || config['elements']; var definitions = Object.keys(config); methods = definitions.map(function(method) { return function() { try { self[method](config[method]); } catch (e) { self.onerror('Method “' + method + '” did not execute. ' + e); throw new Error(); } }; }); return methods; }; // TAReporters.js ends here ================================================ FILE: src/js/Target.js ================================================ /** * @fileOverview Targets are: * • nested into a tree-like structure called a bullseye * • usually mapped 1:1 with DOM elements * * The top-level target living directly on the TA will not map to any element. But it contains children which do map 1:1 with elements. * @name Target.js * @author Cameron Pittman * @license GPLv3 */ /** * Target constructor sets the target defaults. It includes a unique id number for private tracking. */ function Target() { this.id = parseInt(Math.random() * 1000000); this.element = null; this.value = null; this.operation = null; this.children = []; this.index = null; this.correct = false; }; Object.defineProperties(Target.prototype, { hasChildren: { /** * Public method for determining if a Target has child Targets. * @return {Boolean} hasKids - true if there are chldren, false otherwise. */ get: function() { var hasKids = false; if (this.children.length > 0) { hasKids = true; }; return hasKids; } }, hasValue: { /** * Public method for determining if a value exists on a Target. * @return {Boolean} somethingThere - true if a value exists, false otherwise. */ get: function() { var somethingThere = false; if (this.value !== null && this.value !== undefined) { somethingThere = true; }; return somethingThere; } }, hasGrandkids: { /** * Public method for determining if a Target’s children have children. * @return {Boolean} hasGrandKids - true if there are grandchildren, false otherwise. */ get: function() { var gotGrandKids = false; gotGrandKids = this.children.some(function (kid) { return kid.hasChildren; }); return gotGrandKids; } } }); // Target.js ends here ================================================ FILE: src/js/helpers.js ================================================ /** * @fileOverview This file contains helpers for the Grading Engine. * @name helpers.js * @author Cameron Pittman * @license GPLv3 */ // http://stackoverflow.com/questions/7837456/comparing-two-arrays-in-javascript function arrEquals(array1, array2) { if (!array1 || !array2) { return false; } if (array1.length != array2.length) { return false; } for (var i = 0, l = array1.length; i < l; i++) { if (array1[i] instanceof Array && array2[i] instanceof Array) { if (!array1[i].equals(array2[i])) { return false; } } else if (array1[i] != array2[i]) { // Warning - two different object instances will never be equal: {x:20} != {x:20} return false; } } return true; } /** * Creates an Array of DOM nodes that match the selector * @param selector {string} CSS selector - selector to match against * @param {DOM node} parent - parent for starting point * @return {array} Array of DOM nodes */ function getDomNodeArray(selector, parent) { if (!selector) { return []; } parent = parent || document; var nodes = Array.prototype.slice.apply(parent.querySelectorAll(selector)); return nodes; } // modified from http://stackoverflow.com/questions/7960335/javascript-is-given-function-empty Function.prototype.getBody = function() { // Get content between first { and last } var m = this.toString().match(/\{([\s\S]*)\}/m)[1]; // strip whitespace http://stackoverflow.com/questions/14540094/javascript-regular-expression-for-removing-all-spaces-except-for-what-between-do m = m.replace(/([^"]+)|("[^"]+")/g, function($0, $1, $2) { if ($1) { return $1.replace(/\s/g, ''); } else { return $2; } }); // Strip comments return m.replace(/^\s*\/\/.*$/mg, ''); }; // http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string // Use only if necessary... function executeFunctionByName(functionName, context) { var args = [].slice.call(arguments).splice(2); var namespaces = functionName.split('.'); var func = namespaces.pop(); for (var i = 0; i < namespaces.length; i++) { context = context[namespaces[i]]; } return context[func].apply(this, args); } /** * Get the actual number from a measurement. * @param {String} measurement - the measurement to strip * @return {Number} - the number inside */ function getUnitlessMeasurement(measurement) { if (typeof measurement === 'number') { return measurement; } else if (typeof measurement === 'string') { return measurement.match(/\d+/g)[0]; } else { return NaN; } } // helper.js ends here ================================================ FILE: src/js/intro.js ================================================ /** * @fileOverview Udacity’s library for immediate front-end feedback. * @name intro.js * @author Cameron Pittman * @license GPLv3 */ /** * Exposes UdacityFEGradingEngine (Grading Engine) interface * @return {Object} exports - the functions on the exports object */ ;window.UdacityFEGradingEngine ? window.UdacityFEGradingEngine = window.UdacityFEGradingEngine : window.UdacityFEGradingEngine = (function(window, undefined) { 'use strict'; var exports = {}; // intro.js ends here ================================================ FILE: src/js/outro.js ================================================ /** * @fileOverview This file contains the closing statements of the Grading Engine. * @name outro.js * @author Cameron Pittman * @license GPLv3 */ /* jshint ignore:start */ return exports; }(window)); window.dispatchEvent(new CustomEvent('GE-on', {detail: true})); /* jshint ignore:end */ // outro.js ends here // GE.js ends here ================================================ FILE: src/js/registrar.js ================================================ /*global testWidget, Suite, testResults */ /** * @fileOverview Expose functions that create and monitor tests. * @name registrar.js * @author Cameron Pittman * @author Etienne Prud’homme * @license GPLv3 */ var numberOfTests = 0, registeredTests = 0; /* The hotel simply changes the attributes on each web component */ var hotel = { occupiedSuites: [], createSuite: function (rawSuite) { var suite = new Suite(rawSuite); // pass the whole suite to the testResults so you can modify it there later. suite.element = testResults.buildSuiteElement(suite); this.occupiedSuites.push(suite); return suite; } }; Object.defineProperties(hotel, { numberOfPassedSuites: { get: function () { var numberPassed = 0; this.occupiedSuites.forEach(function (suite) { if (suite.suitePassed) { numberPassed += 1; } }); return numberPassed; } }, numberOfSuites: { get: function () { return this.occupiedSuites.length; } }, allCorrect: { get: function () { var allCorrect = (this.numberOfSuites === this.numberOfPassedSuites); // TODO: maybe emit an event if all of them pass? return allCorrect; } } }); /** * Register a suite of tests with the grading engine. * @param {Object} _suite - contains a test’s name and code to display upon completion. * @return {Function} registerTest - a method to register a single test with the grading engine. */ function registerSuite(rawSuite) { var self = this; var newSuite = hotel.createSuite(rawSuite); /** * Register a new test on a specific suite. The test will contain an activeTest. Each active test much return a boolean called isCorrect and an array of the targets in question. * @param {Object} _test - contains a description, activeTest and flags. * @return {Object} self - for chaining tests registrations together (if you’re into that sort of syntax.) */ function registerTest(_test) { newSuite.createTest({ description: _test.description, definition: _test.definition, flags: _test.flags }); return self; } return { registerTest: registerTest }; } var userData = []; var isOn = false; function startTests() { userData.forEach(function(_suite) { numberOfTests += _suite.tests.length; }); return new Promise(function(resolve, reject) { userData.forEach(function (_suite) { var newSuite = registerSuite({ name: _suite.name, code: _suite.code }); _suite.tests.forEach(function (test) { registeredTests++; // console.log('test number: ', registeredTests); try { newSuite.registerTest({ description: test.description, definition: test.definition, flags: test.flags }); } catch(e) { console.warn(e.message); } }); }); }); } /** * For use only when loading a new JSON with user data about the tests they want to run * @param {JSON} suitesJSON Everything the GE needs to know about your tests */ function registerSuites(suitesJSON) { try { if (suitesJSON.length > 0) { userData = JSON.parse(suitesJSON); } } catch (e) { throw new Error('Invalid JSON format.'); } if (userData instanceof Array !== true) { throw new TypeError('Invalid test format. Tests must be wrapped in an array.'); } if (isOn) { startTests(); // console.log('startTests'); } } function turnOn() { if (!isOn) { testWidget.buildWidget().then(function() { isOn = true; // console.log('enters startTests'); startTests(); if(registeredTests === numberOfTests) { window.dispatchEvent(new CustomEvent('tests-registered', { numberOfTests: numberOfTests })); } // console.log('registeredTests = ', registeredTests); // console.log('numberOfTests = ', numberOfTests); // console.log('leaves startTests'); }); } } function turnOff () { hotel.occupiedSuites.forEach(function (suite) { suite.activeTests.forEach(function (activeTest) { activeTest.stopTest(); }); }); hotel.occupiedSuites = []; testWidget.killWidget(); isOn = false; } function debug() { hotel.occupiedSuites.forEach(function (suite) { suite.getDebugData(); suite.getIncorrectInfo(); suite.getValues(); }); } exports.debug = debug; exports.turnOn = turnOn; exports.turnOff = turnOff; exports.registerSuites = registerSuites; // registrar.js ends here