diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..e84613dd6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_size = 4 +trim_trailing_whitespace = true + +[*.{js,html}] +indent_style = space diff --git a/.eslintrc b/.eslintrc index 0d67347a8..fcb231522 100644 --- a/.eslintrc +++ b/.eslintrc @@ -8,11 +8,13 @@ "max-len": [2, 80, 4], "semi": [2, "always"], "strict": [2, "never"], - "no-console": [2, {"allow": ["log", "warn", "error"]}] + "no-console": [2, {"allow": ["log", "warn", "error", "groupCollapsed", "groupEnd", "time", "timeEnd"]}], + "valid-jsdoc": ["error", {"requireReturn": false}] }, "env": { "node": true, - "browser": true + "browser": true, + "worker": true }, "extends": "eslint:recommended" } diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..9ea236ba5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,15 @@ +### Expected behavior + +_Please describe what should happen_ + +### Actual behavior + +_Describe what actually happens_ + +### Steps to reproduce + +_Explain what someone needs to do in order to see what's described in *Actual behavior* above_ + +### Operating system and browser + +_e.g. Mac OS 10.11.6 Safari 10.0_ diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..696bd38d7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ +### Proposed changes + +_Describe what this Pull Request does_ + +### Reason for changes + +_Explain why these changes should be made. Please include an issue # if applicable._ diff --git a/.gitignore b/.gitignore index db98532d4..aad54ff5e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,11 @@ npm-* # Testing /.nyc_output /coverage +/dist.js +/vm.js +/vm.min.js +/playground/assets +/playground/media +/playground/vendor.js +/playground/vm.js +/playground/zenburn.css diff --git a/.npmignore b/.npmignore new file mode 100644 index 000000000..bd86c446a --- /dev/null +++ b/.npmignore @@ -0,0 +1,2 @@ +/.nyc_output +/coverage diff --git a/.travis.yml b/.travis.yml index 00dd791d5..a44d53809 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,35 @@ language: node_js node_js: -- "4" -- "stable" +- '4' +- stable sudo: false cache: directories: - node_modules +install: +- npm install +- npm update +after_script: +- | + # RELEASE_BRANCHES and NPM_TOKEN defined in Travis settings panel + declare exitCode + $(npm bin)/travis-after-all + exitCode=$? + if [[ + # Execute after all jobs finish successfully + $exitCode = 0 && + # Only release on release branches + $RELEASE_BRANCHES =~ $TRAVIS_BRANCH && + # Don't release on PR builds + $TRAVIS_PULL_REQUEST = "false" + ]]; then + # Authenticate NPM + echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" > .npmrc + # Set version to timestamp + npm --no-git-tag-version version $($(npm bin)/json -f package.json version)-prerelease.$(date +%s) + npm publish + # Publish to gh-pages as most recent committer + git config --global user.email $(git log --pretty=format:"%ce" -n1) + git config --global user.name $(git log --pretty=format:"%cn" -n1) + ./node_modules/.bin/gh-pages -x -r https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git -d playground -m "Build for $(git log --pretty=format:%H)" + fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..ddd2e36c3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,25 @@ +## Contributing +The development of scratch-vm is an ongoing process, +and we love to have people in the Scratch and open source communities help us along the way. + +If you're interested in contributing, please take a look at the +[issues](https://github.com/LLK/scratch-vm/issues) on this repository. +Two great ways of helping are by identifying bugs and documenting them as issues, +or fixing issues and creating pull requests. When submitting pull requests please be patient +-- it can take a while to find time to review them. +The organization and class structures can't be radically changed without significant coordination +and collaboration from the Scratch Team, so these types of changes should be avoided. + +It's been said that the Scratch Team spends about one hour of design discussion for every pixel in Scratch, +but some think that estimate is a little low. While we welcome suggestions for new features in our +[suggestions forum](https://scratch.mit.edu/discuss/1/) (especially ones that come with mockups), we are unlikely to accept PRs with +new features that haven't been thought through and discussed as a group. Why? Because we have a strong belief +in the value of keeping things simple for new users. To learn more about our design philosophy, +see [the Scratch Developers page](https://scratch.mit.edu/developers), or +[this paper](http://web.media.mit.edu/~mres/papers/Scratch-CACM-final.pdf). + +Beyond this repo, there are also some other resources that you might want to take a look at: +* [Community Guidelines](https://github.com/LLK/scratch-www/wiki/Community-Guidelines) (we find it important to maintain a constructive and welcoming community, just like on Scratch) +* [Open Source forum](https://scratch.mit.edu/discuss/49/) on Scratch +* [Suggestions forum](https://scratch.mit.edu/discuss/1/) on Scratch +* [Bugs & Glitches forum](https://scratch.mit.edu/discuss/3/) on Scratch diff --git a/Makefile b/Makefile index 74886ded4..14a5870ba 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ ESLINT=./node_modules/.bin/eslint NODE=node TAP=./node_modules/.bin/tap WEBPACK=./node_modules/.bin/webpack --progress --colors +WEBPACK_DEV_SERVER=./node_modules/.bin/webpack-dev-server # ------------------------------------------------------------------------------ @@ -11,6 +12,9 @@ build: watch: $(WEBPACK) --watch +serve: + $(WEBPACK_DEV_SERVER) + # ------------------------------------------------------------------------------ lint: @@ -27,4 +31,4 @@ coverage: # ------------------------------------------------------------------------------ -.PHONY: build lint test coverage benchmark +.PHONY: build lint test coverage benchmark serve diff --git a/README.md b/README.md index 3d6fd7fa0..b701ca103 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,45 @@ ## scratch-vm #### Scratch VM is a library for representing, running, and maintaining the state of computer programs written using [Scratch Blocks](https://github.com/LLK/scratch-blocks). -[](https://travis-ci.com/LLK/scratch-vm) +[](https://travis-ci.org/LLK/scratch-vm) +[](https://coveralls.io/github/LLK/scratch-vm?branch=develop) +[](https://david-dm.org/LLK/scratch-vm) +[](https://david-dm.org/LLK/scratch-vm#info=devDependencies) ## Installation +This requires you to have Git and Node.js installed. + +In your own node environment/application: ```bash -npm install scratch-vm +npm install https://github.com/LLK/scratch-vm.git +``` +If you want to edit/play yourself: +```bash +git clone https://github.com/LLK/scratch-vm.git +cd scratch-vm +npm install ``` -## Setup -```js -var VirtualMachine = require('scratch-vm'); -var vm = new VirtualMachine(); +## Development Server +This requires Node.js to be installed. -// Block events -workspace.addChangeListener(function(e) { - // Handle "tapping" a block - if (e instanceof Blockly.Events.Ui && e.element === 'click') { - var stackBlock = workspace.getBlockById(e.blockId).getRootBlock().id; - vm.runtime.toggleStack(stackBlock); - // Otherwise, pass along to the block listener - } else { - vm.blockListener(e); - } -}); +For convenience, we've included a development server with the VM. This is sometimes useful when running in an environment that's loading remote resources (e.g., SVGs from the Scratch server). -// Run threads -vm.runtime.start(); +## Running the Development Server +Open a Command Prompt or Terminal in the repository and run: +```bash +npm start ``` +Or on Windows: +```bash +StartServerWindows.bat +``` + +## Playground +To run the Playground, make sure the dev server's running and go to [http://localhost:8080/](http://localhost:8080/) - you will be directed to the playground, which demonstrates various tools and internal state. + + + ## Standalone Build ```bash @@ -42,42 +54,51 @@ make build </script> ``` +## How to include in a Node.js App +For an extended setup example, check out the /playground directory, which includes a fully running VM instance. +```js +var VirtualMachine = require('scratch-vm'); +var vm = new VirtualMachine(); + +// Block events +workspace.addChangeListener(vm.blockListener); + +// Run threads +vm.start(); +``` + ## Abstract Syntax Tree #### Overview -The Virtual Machine constructs and maintains the state of an [Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (AST) by listening to events emitted by the [scratch-blocks](https://github.com/LLK/scratch-blocks) workspace via the `blockListener`. At any time, the current state of the AST can be viewed by inspecting the `vm.runtime.blocks` object. +The Virtual Machine constructs and maintains the state of an [Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (AST) by listening to events emitted by the [scratch-blocks](https://github.com/LLK/scratch-blocks) workspace via the `blockListener`. Each target (code-running object, for example, a sprite) keeps an AST for its blocks. At any time, the current state of an AST can be viewed by inspecting the `vm.runtime.targets[...].blocks` object. #### Anatomy of a Block +The VM's block representation contains all the important information for execution and storage. Here's an example representing the "when key pressed" script on a workspace: ```json { - "id": "^1r~63Gdl7;Dh?I*OP3_", - "opcode": "wedo_motorclockwise", - "next": null, - "fields": { - "DURATION": { - "name": "DURATION", - "value": null, - "blocks": { - "1?P=eV(OiDY3vMk!24Ip": { - "id": "1?P=eV(OiDY3vMk!24Ip", - "opcode": "math_number", - "next": null, - "fields": { - "NUM": { - "name": "NUM", - "value": "10", - "blocks": null - } - } - } - } - }, - "SUBSTACK": { - "name": "SUBSTACK", - "value": "@1ln(HsUO4!]*2*%BrE|", - "blocks": null + "_blocks": { + "Q]PK~yJ@BTV8Y~FfISeo": { + "id": "Q]PK~yJ@BTV8Y~FfISeo", + "opcode": "event_whenkeypressed", + "inputs": { + }, + "fields": { + "KEY_OPTION": { + "name": "KEY_OPTION", + "value": "space" } + }, + "next": null, + "topLevel": true, + "parent": null, + "shadow": false, + "x": -69.333333333333, + "y": 174 } + }, + "_scripts": [ + "Q]PK~yJ@BTV8Y~FfISeo" + ] } ``` @@ -90,5 +111,5 @@ make test make coverage ``` -## Donation -We provide [Scratch](https://scratch.mit.edu) free of charge, and want to keep it that way! Please consider making a [donation](https://secure.donationpay.org/scratchfoundation/) to support our continued engineering, community, and resource development efforts. Donations of any size are appreciated. Thank you! +## Donate +We provide [Scratch](https://scratch.mit.edu) free of charge, and want to keep it that way! Please consider making a [donation](https://secure.donationpay.org/scratchfoundation/) to support our continued engineering, design, community, and resource development efforts. Donations of any size are appreciated. Thank you! diff --git a/StartServerWindows.bat b/StartServerWindows.bat new file mode 100644 index 000000000..73a4d84db --- /dev/null +++ b/StartServerWindows.bat @@ -0,0 +1,2 @@ +@echo off +node_modules\.bin\webpack-dev-server --host 0.0.0.0 --content-base .\playground diff --git a/assets/scratch_cat.svg b/assets/scratch_cat.svg new file mode 100644 index 000000000..823455468 --- /dev/null +++ b/assets/scratch_cat.svg @@ -0,0 +1,42 @@ +<svg version="1.1" id="cat" x="0px" y="0px" width="95px" height="111px" viewBox="0 0 95 111" enable-background="new 0 0 95 111" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <g> + <g id="Layer_3"> + <path fill="#FAA51D" stroke="#000000" d="M22.462,79.039c-2.415-0.451-5.304-1.309-7.742-3.503
		C9.268,70.629,7.526,62.535,3.672,64.622c-3.856,2.088-3.782,15.165,8.353,19.194c4.182,1.391,7.998,1.396,11.091,1.312
		c0.811-0.025,7.717-0.654,10.079-4.074c2.361-3.42,0.719-4.272-0.09-4.744C32.295,75.838,25.878,79.677,22.462,79.039z"/> + <path fill="#FFFFFF" d="M4.236,64.877c-1.989,0.613-3.075,4.998-2.076,8.484c0.998,3.49,2.634,5.022,3.863,6.398
		c1.528,1.038-0.72-2.402,1.361-4.15c2.075-1.744,5.733-0.914,5.733-0.914s-2.909-3.987-4.57-6.396
		C6.975,65.988,6.359,64.375,4.236,64.877z"/> + </g> + <g> + <path fill="#FAA51D" d="M38.217,86.756c0,0-8.832,6.2-17.071,8.412l0.086,0.215c1.247,1.824,5.87,7.497-0.334,9.496
		c-5.333,1.717-15.12-13.104-10.821-15.902c2.626-1.713,4.892-0.252,4.892-0.252s3.474-1.07,6.001-2.345
		c4.303-2.161,5.784-3.453,5.784-3.453s4.184-4.306,6.856-4.137C36.281,78.96,41.669,83.504,38.217,86.756z"/> + <path fill="none" stroke="#231F20" stroke-width="1.2" d="M21.232,95.383c1.247,1.824,5.87,7.497-0.334,9.496
		c-5.333,1.717-15.329-13.344-11.03-16.145c2.626-1.713,5.101-0.01,5.101-0.01s3.474-1.072,6.001-2.348
		c4.303-2.161,5.784-3.453,5.784-3.453"/> + <path fill="none" stroke="#231F20" stroke-width="1.2" d="M38.217,86.756c0,0-10.123,7.107-18.804,8.819"/> + </g> + <path fill="#FAA51D" stroke="#231F20" stroke-width="1.2" d="M52.169,74.885c0,0,1.235,0.165,4.744,3.676
	c3.509,3.508,6.026,2.16,8.911,0.724c2.877-1.443,10.537-6.126,6.49-9.817c-4.049-3.688-6.207,1.146-9.715,2.405
	c-3.512,1.26-5.061-2.487-6.858-4.287c-0.589-0.593-1.188-1.099-1.729-1.505c0,0-0.971-0.76-1.906,2.79
	C51.172,72.412,50.162,73.415,52.169,74.885z"/> + <g id="Layer_2_1_"> + <path fill="#FAA51D" stroke="#231F20" stroke-width="1.2" d="M46.753,82.012c1.188-0.912,2.397-2.402,3.951-4.713
		c1.296-1.927,2.7-5.578,2.7-5.578c0.875-2.521,1.934-6.576-1.902-7.296c-1.553-0.291-4.079-0.098-7.67-0.776
		c-3.593-0.681-6.798-2.522-9.517,2.233c-2.718,4.757-9.59,8.271-1.056,16.563c0,0,4.901,3.842,10.764,9.639
		c4.831,4.775,12.045,10.602,12.045,10.602s18.972,2.188,19.535-0.693c1.922-9.79-14.777-6.911-14.777-6.911
		s-4.605-3.933-6.725-5.794c-3.478-3.059-11.125-10.771-11.125-10.771"/> + <path fill="#FFFFFF" d="M51.253,75.434c0,0,2.47-2.66-2.469-5.317c-4.939-2.657-7.213-0.017-8.739,1.521
		c-2.644,2.655,3.443,6.611,3.443,6.611l3.176,3.204c0,0,1.738-1.647,2.499-2.979C50.036,77.26,51.253,75.434,51.253,75.434"/> + </g> + <g id="Layer_8"/> + <path fill="#FAA51D" stroke="#231F20" stroke-width="1.2" d="M29.926,73.218c0.749-0.571,2.889-2.202,4.854-3.657
	c2.428-1.799,6.117-5.849,1.077-7.646c-5.04-1.801-7.507,1.604-11.519,4.946c-2.159,1.801-5.308,2.699-4.319,6.209
	c0.993,3.511,4.862,13.408,11.789,10.17c6.929-3.239-1.799-9.18-3.06-11.157"/> + <g id="Layer_2"> + <path fill="#FAA51D" stroke="#231F20" stroke-width="1.2" d="M52.709,14.156c-1.54-0.143-4.75-0.316-6.518-0.231
		c-4.728,0.225-9.224,1.928-9.224,1.928L23.949,7.357l2.235,18.906c0.646-0.782-10.555,12.804-3.479,24.224
		c7.08,11.426,22.233,16.518,40.988,12.792c18.755-3.729,23.229-14.531,21.986-20.246c-1.242-5.714-8.322-7.823-8.322-7.823
		s-0.09-4.48-3.328-9.97c-1.926-3.268-8.348-8.041-8.348-8.041L62.822,5.647l-7.452,7.204L52.709,14.156z"/> + <path fill="#FFFFFF" d="M76.42,35.066l-2.482-2.064l-9.115,2.661c0,0,0,3.419-4.367,4.367c-4.37,0.951-11.211-2.277-11.211-2.277
		L41.46,41.17c0,0-8.437,0.928-8.739,6.081C32.048,58.704,46.1,63.479,51.425,63.783c2.905,0.167,8.235-0.338,12.277-1.141
		c17.752-3.234,22.551-13.919,21.31-19.635c-1.242-5.714-7.978-7.196-7.978-7.196L76.42,35.066z"/> + <path fill="none" stroke="#231F20" stroke-width="1.2" d="M10.673,46.155c0,0,4.107,0.374,5.974,0.268
		c1.865-0.107,5.492-0.587,5.492-0.587"/> + <path fill="none" stroke="#231F20" stroke-width="1.2" d="M81.656,40.671c0,0,4.549-0.743,6.859-1.549
		c2.715-0.942,4.543-2.545,4.543-2.545"/> + <path fill="none" stroke="#231F20" stroke-width="1.2" d="M22.337,41.909c0,0-2.384-1.777-6.117-3.43
		c-4.134-1.831-6.405-2.303-6.405-2.303"/> + <path fill="none" stroke="#231F20" stroke-width="1.2" d="M82.117,46.622c0,0,2.726,1.104,5.533,1.385
		c2.77,0.276,4.646,0.11,4.646,0.11"/> + <path fill="none" stroke="#000000" stroke-linecap="round" stroke-miterlimit="10" d="M52.35,14.212
		c2.84,0.7,3.887,1.469,3.887,1.469"/> + <line fill="none" stroke="#000000" x1="33.898" y1="13.684" x2="39.956" y2="18.042"/> + </g> + <g id="Layer_5"> + <path fill="#FFFFFF" stroke="#231F20" d="M71.84,25.366c2.924,4.479,3.033,9.591,0.242,11.415
		c-2.793,1.825-7.426-0.332-10.354-4.813c-2.933-4.48-3.037-9.589-0.244-11.415C64.275,18.73,68.913,20.884,71.84,25.366z"/> + <path fill="#231F20" d="M71.089,32.522c0,1.08-0.802,1.956-1.8,1.956c-0.993,0-1.803-0.877-1.803-1.956
		c0-1.08,0.81-1.958,1.803-1.958C70.287,30.564,71.089,31.442,71.089,32.522"/> + </g> + <g id="Layer_7"> + <path fill="#FFFFFF" stroke="#231F20" d="M47.867,28.619c2.926,4.48,2.619,9.862-0.681,12.015
		c-3.302,2.159-8.351,0.272-11.276-4.208c-2.928-4.48-2.624-9.86,0.678-12.017C39.891,22.253,44.938,24.137,47.867,28.619z"/> + <path fill="#231F20" d="M46.079,34.507c0,1.081-0.803,1.957-1.801,1.957c-0.992,0-1.803-0.878-1.803-1.957
		c0-1.08,0.811-1.957,1.803-1.957C45.274,32.55,46.079,33.427,46.079,34.507"/> + </g> + <path fill="#5E4A42" stroke="#000000" d="M59.766,37.926c1.854,0,4.555-0.284,4.697,0.569c0.143,0.855-1.709,4.203-2.988,4.345
	c-1.283,0.142-6.125-2.353-6.195-3.919C55.206,37.355,58.055,37.926,59.766,37.926z"/> + <g id="Layer_4"> + <path fill="none" stroke="#231F20" stroke-width="1.2" d="M46.774,45.235c0,0,10.347,3.054,14.217,3.897
		c3.868,0.842,10.851,1.684,10.851,1.684s-7.99,10.245-17.328,7.644C45.176,55.863,45.345,49.975,46.774,45.235z"/> + </g> + </g> +</svg> diff --git a/assets/stage.png b/assets/stage.png new file mode 100644 index 000000000..b13e9d1f5 Binary files /dev/null and b/assets/stage.png differ diff --git a/package.json b/package.json index 1fcd00ef3..15f2dd459 100644 --- a/package.json +++ b/package.json @@ -9,18 +9,32 @@ "type": "git", "url": "git+ssh://git@github.com/LLK/scratch-vm.git" }, - "main": "./src/index.js", + "main": "./dist.js", "scripts": { - "test": "make test" - }, - "dependencies": { - "htmlparser2": "3.9.0", - "memoizee": "0.3.10" + "prepublish": "./node_modules/.bin/webpack --bail", + "start": "webpack-dev-server", + "build": "webpack --colors --progress", + "test": "make test", + "version": "./node_modules/.bin/json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"" }, "devDependencies": { + "copy-webpack-plugin": "3.0.1", "eslint": "2.7.0", + "expose-loader": "0.7.1", + "gh-pages": "0.11.0", + "highlightjs": "8.7.0", + "htmlparser2": "3.9.0", + "json": "9.0.4", "json-loader": "0.5.4", + "lodash.defaultsdeep": "4.6.0", + "promise": "7.1.1", + "scratch-blocks": "^0.1.0-prepublish", + "scratch-render": "^0.1.0-prepublish", + "script-loader": "0.7.0", + "stats.js": "0.16.0", "tap": "5.7.1", - "webpack": "1.13.0" + "travis-after-all": "1.4.4", + "webpack": "1.13.0", + "webpack-dev-server": "1.14.1" } } diff --git a/playground/index.html b/playground/index.html new file mode 100644 index 000000000..46fa57cb4 --- /dev/null +++ b/playground/index.html @@ -0,0 +1,89 @@ +<!doctype html> + +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>Scratch VM Playground</title> + <link rel="stylesheet" href="playground.css"> + <link rel="stylesheet" href="zenburn.css"> +</head> +<body> + <div id="vm-devtools"> + <h2>Scratch VM Playground</h2> + <select id="selectedTarget" multiple></select> + <div id="projectButtons"> + <button id="greenflag">Green flag</button> + <button id="stopall">Stop</button> + </div> + <div> + Turbo: <input id='turbomode' type='checkbox' /> + </div> + <div> + Pause: <input id='pausemode' type='checkbox' /> + </div> + <div> + Compatibility (30 TPS): <input id='compatmode' type='checkbox' /> + </div> + <div> + Single stepping: <input id='singlestepmode' type='checkbox' /> + <input id='singlestepspeed' type='range' min='1' max='20' value='10' /> + </div> + <br /> + <ul id="playgroundLinks"> + <li><a id="renderexplorer-link" href="#">Renderer</a></li> + <li><a id="threadexplorer-link" href="#">Threads</a></li> + <li><a id="blockexplorer-link" href="#">Block Representation</a></li> + <li><a id="importexport-link" href="#">Import/Export</a></li> + </ul><br /> + <div id="tab-renderexplorer"> + Renderer<br /> + <canvas id="scratch-stage" style="width: 480px; height: 360px;"></canvas><br /> + </div> + <div id="tab-threadexplorer"> + Thread explorer + <pre id="threadexplorer"></pre> + </div> + <div id="tab-blockexplorer"> + Block explorer + <pre id="blockexplorer"></pre> + </div> + <div id="tab-importexport"> + Import/Export<br /> + Project ID: <input id="projectId" value="119615668" /> + <button id="projectLoadButton">Load</button> + <button id="createEmptyProject">New Project</button><br /> + <p> + <input type="button" value="Export to XML" onclick="toXml()"> + + <input type="button" value="Import from XML" onclick="fromXml()" id="import"> + <br /><br /> + <textarea id="importExport"></textarea> + </p> + </div> + </div> + + <div id="blocks"></div> + + <!-- FPS counter, Syntax highlighter, Blocks, Renderer --> + <script src="./vendor.js"></script> + <!-- VM Worker --> + <script src="./vm.js"></script> + <!-- Playground --> + <script src="./playground.js"></script> + <script> + function toXml() { + var output = document.getElementById('importExport'); + var xml = Blockly.Xml.workspaceToDom(workspace); + output.value = Blockly.Xml.domToPrettyText(xml); + output.focus(); + output.select(); + } + + function fromXml() { + var input = document.getElementById('importExport'); + var xml = Blockly.Xml.textToDom(input.value); + Blockly.Xml.domToWorkspace(workspace, xml); + } + </script> +</body> +</html> diff --git a/playground/playground.css b/playground/playground.css new file mode 100644 index 000000000..3eccd2625 --- /dev/null +++ b/playground/playground.css @@ -0,0 +1,73 @@ +body { + background: rgb(36,36,36); +} +a { + color: rgb(217,217,217); +} +h2 { + font-size: 1em; +} +#blocks { + position: absolute; + left: 40%; + right: 0; + top: 0; + bottom: 0; + font-family: "Helvetica Neue", Helvetica, sans-serif; +} +#vm-devtools { + color: rgb(217,217,217); + position: absolute; + left: 1%; + right: 60%; + top: 1%; + bottom: 0; + width: 35%; +} +#blockexplorer, #threadexplorer, #importexport { + position: absolute; + height: 75%; + overflow: scroll; + border: 1px solid #fff; + background: rgb(36,36,36); + color: rgb(217,217,217); + font-family: monospace; + font-size: 10pt; + width: 480px; + height: 360px; +} +#tab-blockexplorer, #tab-threadexplorer, #tab-importexport { + display: none; +} +#importExport { + width: 480px; + height: 360px; + background: rgb(36,36,36); + color: rgb(217,217,217); +} +#projectId { + background: rgb(36,36,36); + color: rgb(217,217,217); + font-family: monospace; + font-size: 10pt; +} +ul#playgroundLinks { + display: block; + list-style-type: none; + margin: 0; + padding: 0; + overflow: hidden; + background-color: #333; +} +#playgroundLinks li { + float: left; +} +#playgroundLinks li a { + display: block; + color: white; + text-align: center; + padding: 5px 10px; +} +#playgroundLinks li a:hover { + background-color: #111; +} diff --git a/playground/playground.js b/playground/playground.js new file mode 100644 index 000000000..577877ae1 --- /dev/null +++ b/playground/playground.js @@ -0,0 +1,312 @@ +var NEW_PROJECT_HASH = 'createEmptyProject'; + +var loadProject = function () { + var id = location.hash.substring(1); + if (id === NEW_PROJECT_HASH) { + window.vm.createEmptyProject(); + return; + } + if (id.length < 1 || !isFinite(id)) { + id = '119615668'; + } + var url = 'https://projects.scratch.mit.edu/internalapi/project/' + + id + '/get/'; + var r = new XMLHttpRequest(); + r.onreadystatechange = function() { + if (this.readyState === 4) { + if (r.status === 200) { + window.vm.loadProject(this.responseText); + } else { + window.vm.createEmptyProject(); + } + } + }; + r.open('GET', url); + r.send(); +}; + +window.onload = function() { + // Lots of global variables to make debugging easier + // Instantiate the VM. + var vm = new window.VirtualMachine(); + window.vm = vm; + + // Loading projects from the server. + document.getElementById('projectLoadButton').onclick = function () { + document.location = '#' + document.getElementById('projectId').value; + location.reload(); + }; + document.getElementById('createEmptyProject').addEventListener('click', + function() { + document.location = '#' + NEW_PROJECT_HASH; + location.reload(); + }); + loadProject(); + + // Instantiate the renderer and connect it to the VM. + var canvas = document.getElementById('scratch-stage'); + var renderer = new window.RenderWebGL(canvas); + window.renderer = renderer; + vm.attachRenderer(renderer); + + // Instantiate scratch-blocks and attach it to the DOM. + var workspace = window.Blockly.inject('blocks', { + media: './media/', + zoom: { + controls: true, + wheel: true, + startScale: 0.75 + }, + colours: { + workspace: '#334771', + flyout: '#283856', + scrollbar: '#24324D', + scrollbarHover: '#0C111A', + insertionMarker: '#FFFFFF', + insertionMarkerOpacity: 0.3, + fieldShadow: 'rgba(255, 255, 255, 0.3)', + dragShadowOpacity: 0.6 + } + }); + window.workspace = workspace; + + // Attach scratch-blocks events to VM. + workspace.addChangeListener(vm.blockListener); + var flyoutWorkspace = workspace.getFlyout().getWorkspace(); + flyoutWorkspace.addChangeListener(vm.flyoutBlockListener); + + // Create FPS counter. + var stats = new window.Stats(); + document.getElementById('tab-renderexplorer').appendChild(stats.dom); + stats.dom.style.position = 'relative'; + stats.begin(); + + // Playground data tabs. + // Block representation tab. + var blockexplorer = document.getElementById('blockexplorer'); + var updateBlockExplorer = function(blocks) { + blockexplorer.innerHTML = JSON.stringify(blocks, null, 2); + window.hljs.highlightBlock(blockexplorer); + }; + + // Thread representation tab. + var threadexplorer = document.getElementById('threadexplorer'); + var cachedThreadJSON = ''; + var updateThreadExplorer = function (newJSON) { + if (newJSON != cachedThreadJSON) { + cachedThreadJSON = newJSON; + threadexplorer.innerHTML = cachedThreadJSON; + window.hljs.highlightBlock(threadexplorer); + } + }; + + // Only request data from the VM thread if the appropriate tab is open. + window.exploreTabOpen = false; + var getPlaygroundData = function () { + vm.getPlaygroundData(); + if (window.exploreTabOpen) { + window.requestAnimationFrame(getPlaygroundData); + } + }; + + // VM handlers. + // Receipt of new playground data (thread, block representations). + vm.on('playgroundData', function(data) { + updateThreadExplorer(data.threads); + updateBlockExplorer(data.blocks); + }); + + // Receipt of new block XML for the selected target. + vm.on('workspaceUpdate', function (data) { + workspace.clear(); + var dom = window.Blockly.Xml.textToDom(data.xml); + window.Blockly.Xml.domToWorkspace(dom, workspace); + }); + + // Receipt of new list of targets, selected target update. + var selectedTarget = document.getElementById('selectedTarget'); + vm.on('targetsUpdate', function (data) { + // Clear select box. + while (selectedTarget.firstChild) { + selectedTarget.removeChild(selectedTarget.firstChild); + } + // Generate new select box. + for (var i = 0; i < data.targetList.length; i++) { + var targetOption = document.createElement('option'); + targetOption.setAttribute('value', data.targetList[i][0]); + // If target id matches editingTarget id, select it. + if (data.targetList[i][0] == data.editingTarget) { + targetOption.setAttribute('selected', 'selected'); + } + targetOption.appendChild( + document.createTextNode(data.targetList[i][1]) + ); + selectedTarget.appendChild(targetOption); + } + }); + selectedTarget.onchange = function () { + vm.setEditingTarget(this.value); + }; + + // Feedback for stacks and blocks running. + vm.on('STACK_GLOW_ON', function(data) { + workspace.glowStack(data.id, true); + }); + vm.on('STACK_GLOW_OFF', function(data) { + workspace.glowStack(data.id, false); + }); + vm.on('BLOCK_GLOW_ON', function(data) { + workspace.glowBlock(data.id, true); + }); + vm.on('BLOCK_GLOW_OFF', function(data) { + workspace.glowBlock(data.id, false); + }); + vm.on('VISUAL_REPORT', function(data) { + workspace.reportValue(data.id, data.value); + }); + + // Feed mouse events as VM I/O events. + document.addEventListener('mousemove', function (e) { + var rect = canvas.getBoundingClientRect(); + var coordinates = { + x: e.clientX - rect.left, + y: e.clientY - rect.top, + canvasWidth: rect.width, + canvasHeight: rect.height + }; + window.vm.postIOData('mouse', coordinates); + }); + canvas.addEventListener('mousedown', function (e) { + var rect = canvas.getBoundingClientRect(); + var data = { + isDown: true, + x: e.clientX - rect.left, + y: e.clientY - rect.top, + canvasWidth: rect.width, + canvasHeight: rect.height + }; + window.vm.postIOData('mouse', data); + e.preventDefault(); + }); + canvas.addEventListener('mouseup', function (e) { + var rect = canvas.getBoundingClientRect(); + var data = { + isDown: false, + x: e.clientX - rect.left, + y: e.clientY - rect.top, + canvasWidth: rect.width, + canvasHeight: rect.height + }; + window.vm.postIOData('mouse', data); + e.preventDefault(); + }); + + // Feed keyboard events as VM I/O events. + document.addEventListener('keydown', function (e) { + // Don't capture keys intended for Blockly inputs. + if (e.target != document && e.target != document.body) { + return; + } + window.vm.postIOData('keyboard', { + keyCode: e.keyCode, + isDown: true + }); + e.preventDefault(); + }); + document.addEventListener('keyup', function(e) { + // Always capture up events, + // even those that have switched to other targets. + window.vm.postIOData('keyboard', { + keyCode: e.keyCode, + isDown: false + }); + // E.g., prevent scroll. + if (e.target != document && e.target != document.body) { + e.preventDefault(); + } + }); + + // Run threads + vm.start(); + + // Inform VM of animation frames. + var animate = function() { + stats.end(); + stats.begin(); + window.vm.animationFrame(); + requestAnimationFrame(animate); + }; + requestAnimationFrame(animate); + + // Handlers for green flag and stop all. + document.getElementById('greenflag').addEventListener('click', function() { + vm.greenFlag(); + }); + document.getElementById('stopall').addEventListener('click', function() { + vm.stopAll(); + }); + document.getElementById('turbomode').addEventListener('change', function() { + var turboOn = document.getElementById('turbomode').checked; + vm.setTurboMode(turboOn); + }); + document.getElementById('pausemode').addEventListener('change', function() { + var pauseOn = document.getElementById('pausemode').checked; + vm.setPauseMode(pauseOn); + }); + document.getElementById('compatmode').addEventListener('change', + function() { + var compatibilityMode = document.getElementById('compatmode').checked; + vm.setCompatibilityMode(compatibilityMode); + }); + document.getElementById('singlestepmode').addEventListener('change', + function() { + var singleStep = document.getElementById('singlestepmode').checked; + vm.setSingleSteppingMode(singleStep); + }); + document.getElementById('singlestepspeed').addEventListener('input', + function() { + var speed = document.getElementById('singlestepspeed').value; + vm.setSingleSteppingSpeed(speed); + }); + + var tabBlockExplorer = document.getElementById('tab-blockexplorer'); + var tabThreadExplorer = document.getElementById('tab-threadexplorer'); + var tabRenderExplorer = document.getElementById('tab-renderexplorer'); + var tabImportExport = document.getElementById('tab-importexport'); + + // Handlers to show different explorers. + document.getElementById('threadexplorer-link').addEventListener('click', + function () { + window.exploreTabOpen = true; + getPlaygroundData(); + tabBlockExplorer.style.display = 'none'; + tabRenderExplorer.style.display = 'none'; + tabThreadExplorer.style.display = 'block'; + tabImportExport.style.display = 'none'; + }); + document.getElementById('blockexplorer-link').addEventListener('click', + function () { + window.exploreTabOpen = true; + getPlaygroundData(); + tabBlockExplorer.style.display = 'block'; + tabRenderExplorer.style.display = 'none'; + tabThreadExplorer.style.display = 'none'; + tabImportExport.style.display = 'none'; + }); + document.getElementById('renderexplorer-link').addEventListener('click', + function () { + window.exploreTabOpen = false; + tabBlockExplorer.style.display = 'none'; + tabRenderExplorer.style.display = 'block'; + tabThreadExplorer.style.display = 'none'; + tabImportExport.style.display = 'none'; + }); + document.getElementById('importexport-link').addEventListener('click', + function () { + window.exploreTabOpen = false; + tabBlockExplorer.style.display = 'none'; + tabRenderExplorer.style.display = 'none'; + tabThreadExplorer.style.display = 'none'; + tabImportExport.style.display = 'block'; + }); +}; diff --git a/src/blocks/scratch3.js b/src/blocks/scratch3.js deleted file mode 100644 index 6bf327642..000000000 --- a/src/blocks/scratch3.js +++ /dev/null @@ -1,82 +0,0 @@ -function Scratch3Blocks(runtime) { - /** - * The runtime instantiating this block package. - * @type {Runtime} - */ - this.runtime = runtime; -} - -/** - * Retrieve the block primitives implemented by this package. - * @return {Object.<string, Function>} Mapping of opcode to Function. - */ -Scratch3Blocks.prototype.getPrimitives = function() { - return { - 'control_repeat': this.repeat, - 'control_forever': this.forever, - 'control_wait': this.wait, - 'control_stop': this.stop, - 'event_whenflagclicked': this.whenFlagClicked, - 'event_whenbroadcastreceived': this.whenBroadcastReceived, - 'event_broadcast': this.broadcast - }; -}; - -Scratch3Blocks.prototype.repeat = function(argValues, util) { - console.log('Running: control_repeat'); - // Initialize loop - if (util.stackFrame.loopCounter === undefined) { - util.stackFrame.loopCounter = parseInt(argValues[0]); // @todo arg - } - // Decrease counter - util.stackFrame.loopCounter--; - // If we still have some left, start the substack - if (util.stackFrame.loopCounter >= 0) { - util.startSubstack(); - } -}; - -Scratch3Blocks.prototype.forever = function(argValues, util) { - console.log('Running: control_forever'); - util.startSubstack(); -}; - -Scratch3Blocks.prototype.wait = function(argValues, util) { - console.log('Running: control_wait'); - util.yield(); - util.timeout(function() { - util.done(); - }, 1000 * parseFloat(argValues[0])); -}; - -Scratch3Blocks.prototype.stop = function() { - console.log('Running: control_stop'); - // @todo - don't use this.runtime - this.runtime.stopAll(); -}; - -Scratch3Blocks.prototype.whenFlagClicked = function() { - console.log('Running: event_whenflagclicked'); - // No-op -}; - -Scratch3Blocks.prototype.whenBroadcastReceived = function() { - console.log('Running: event_whenbroadcastreceived'); - // No-op -}; - -Scratch3Blocks.prototype.broadcast = function(argValues, util) { - console.log('Running: event_broadcast'); - util.startHats(function(hat) { - if (hat.opcode === 'event_whenbroadcastreceived') { - var shadows = hat.fields.CHOICE.blocks; - for (var sb in shadows) { - var shadowblock = shadows[sb]; - return shadowblock.fields.CHOICE.value === argValues[0]; - } - } - return false; - }); -}; - -module.exports = Scratch3Blocks; diff --git a/src/blocks/scratch3_control.js b/src/blocks/scratch3_control.js new file mode 100644 index 000000000..571b1478f --- /dev/null +++ b/src/blocks/scratch3_control.js @@ -0,0 +1,139 @@ +var Cast = require('../util/cast'); +var Timer = require('../util/timer'); + +function Scratch3ControlBlocks(runtime) { + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; +} + +/** + * Retrieve the block primitives implemented by this package. + * @return {Object.<string, Function>} Mapping of opcode to Function. + */ +Scratch3ControlBlocks.prototype.getPrimitives = function() { + return { + 'control_repeat': this.repeat, + 'control_repeat_until': this.repeatUntil, + 'control_forever': this.forever, + 'control_wait': this.wait, + 'control_wait_until': this.waitUntil, + 'control_if': this.if, + 'control_if_else': this.ifElse, + 'control_stop': this.stop, + 'control_create_clone_of': this.createClone, + 'control_delete_this_clone': this.deleteClone + }; +}; + +Scratch3ControlBlocks.prototype.getHats = function () { + return { + 'control_start_as_clone': { + restartExistingThreads: false + } + }; +}; + +Scratch3ControlBlocks.prototype.repeat = function(args, util) { + var times = Math.floor(Cast.toNumber(args.TIMES)); + // Initialize loop + if (util.stackFrame.loopCounter === undefined) { + util.stackFrame.loopCounter = times; + } + // Only execute once per frame. + // When the branch finishes, `repeat` will be executed again and + // the second branch will be taken, yielding for the rest of the frame. + // Decrease counter + util.stackFrame.loopCounter--; + // If we still have some left, start the branch. + if (util.stackFrame.loopCounter >= 0) { + util.startBranch(1, true); + } +}; + +Scratch3ControlBlocks.prototype.repeatUntil = function(args, util) { + var condition = Cast.toBoolean(args.CONDITION); + // If the condition is true, start the branch. + if (!condition) { + util.startBranch(1, true); + } +}; + +Scratch3ControlBlocks.prototype.waitUntil = function(args, util) { + var condition = Cast.toBoolean(args.CONDITION); + if (!condition) { + util.yield(); + } +}; + +Scratch3ControlBlocks.prototype.forever = function(args, util) { + util.startBranch(1, true); +}; + +Scratch3ControlBlocks.prototype.wait = function(args, util) { + if (!util.stackFrame.timer) { + util.stackFrame.timer = new Timer(); + util.stackFrame.timer.start(); + util.yield(); + this.runtime.requestRedraw(); + } else { + var duration = Math.max(0, 1000 * Cast.toNumber(args.DURATION)); + if (util.stackFrame.timer.timeElapsed() < duration) { + util.yield(); + } + } +}; + +Scratch3ControlBlocks.prototype.if = function(args, util) { + var condition = Cast.toBoolean(args.CONDITION); + if (condition) { + util.startBranch(1, false); + } +}; + +Scratch3ControlBlocks.prototype.ifElse = function(args, util) { + var condition = Cast.toBoolean(args.CONDITION); + if (condition) { + util.startBranch(1, false); + } else { + util.startBranch(2, false); + } +}; + +Scratch3ControlBlocks.prototype.stop = function(args, util) { + var option = args.STOP_OPTION; + if (option == 'all') { + util.stopAll(); + } else if (option == 'other scripts in sprite' || + option == 'other scripts in stage') { + util.stopOtherTargetThreads(); + } else if (option == 'this script') { + util.stopThread(); + } +}; + +Scratch3ControlBlocks.prototype.createClone = function (args, util) { + var cloneTarget; + if (args.CLONE_OPTION == '_myself_') { + cloneTarget = util.target; + } else { + cloneTarget = this.runtime.getSpriteTargetByName(args.CLONE_OPTION); + } + if (!cloneTarget) { + return; + } + var newClone = cloneTarget.makeClone(); + if (newClone) { + this.runtime.targets.push(newClone); + } +}; + +Scratch3ControlBlocks.prototype.deleteClone = function (args, util) { + if (util.target.isOriginal) return; + this.runtime.disposeTarget(util.target); + this.runtime.stopForTarget(util.target); +}; + +module.exports = Scratch3ControlBlocks; diff --git a/src/blocks/scratch3_data.js b/src/blocks/scratch3_data.js new file mode 100644 index 000000000..a40172427 --- /dev/null +++ b/src/blocks/scratch3_data.js @@ -0,0 +1,136 @@ +var Cast = require('../util/cast'); + +function Scratch3DataBlocks(runtime) { + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; +} + +/** + * Retrieve the block primitives implemented by this package. + * @return {Object.<string, Function>} Mapping of opcode to Function. + */ +Scratch3DataBlocks.prototype.getPrimitives = function () { + return { + 'data_variable': this.getVariable, + 'data_setvariableto': this.setVariableTo, + 'data_changevariableby': this.changeVariableBy, + 'data_listcontents': this.getListContents, + 'data_addtolist': this.addToList, + 'data_deleteoflist': this.deleteOfList, + 'data_insertatlist': this.insertAtList, + 'data_replaceitemoflist': this.replaceItemOfList, + 'data_itemoflist': this.getItemOfList, + 'data_lengthoflist': this.lengthOfList, + 'data_listcontainsitem': this.listContainsItem + }; +}; + +Scratch3DataBlocks.prototype.getVariable = function (args, util) { + var variable = util.target.lookupOrCreateVariable(args.VARIABLE); + return variable.value; +}; + +Scratch3DataBlocks.prototype.setVariableTo = function (args, util) { + var variable = util.target.lookupOrCreateVariable(args.VARIABLE); + variable.value = args.VALUE; +}; + +Scratch3DataBlocks.prototype.changeVariableBy = function (args, util) { + var variable = util.target.lookupOrCreateVariable(args.VARIABLE); + var castedValue = Cast.toNumber(variable.value); + var dValue = Cast.toNumber(args.VALUE); + variable.value = castedValue + dValue; +}; + +Scratch3DataBlocks.prototype.getListContents = function (args, util) { + var list = util.target.lookupOrCreateList(args.LIST); + // Determine if the list is all single letters. + // If it is, report contents joined together with no separator. + // If it's not, report contents joined together with a space. + var allSingleLetters = true; + for (var i = 0; i < list.contents.length; i++) { + var listItem = list.contents[i]; + if (!((typeof listItem === 'string') && + (listItem.length == 1))) { + allSingleLetters = false; + break; + } + } + if (allSingleLetters) { + return list.contents.join(''); + } else { + return list.contents.join(' '); + } +}; + +Scratch3DataBlocks.prototype.addToList = function (args, util) { + var list = util.target.lookupOrCreateList(args.LIST); + list.contents.push(args.ITEM); +}; + +Scratch3DataBlocks.prototype.deleteOfList = function (args, util) { + var list = util.target.lookupOrCreateList(args.LIST); + var index = Cast.toListIndex(args.INDEX, list.contents.length); + if (index === Cast.LIST_INVALID) { + return; + } else if (index === Cast.LIST_ALL) { + list.contents = []; + return; + } + list.contents.splice(index - 1, 1); +}; + +Scratch3DataBlocks.prototype.insertAtList = function (args, util) { + var item = args.ITEM; + var list = util.target.lookupOrCreateList(args.LIST); + var index = Cast.toListIndex(args.INDEX, list.contents.length + 1); + if (index === Cast.LIST_INVALID) { + return; + } + list.contents.splice(index - 1, 0, item); +}; + +Scratch3DataBlocks.prototype.replaceItemOfList = function (args, util) { + var item = args.ITEM; + var list = util.target.lookupOrCreateList(args.LIST); + var index = Cast.toListIndex(args.INDEX, list.contents.length); + if (index === Cast.LIST_INVALID) { + return; + } + list.contents.splice(index - 1, 1, item); +}; + +Scratch3DataBlocks.prototype.getItemOfList = function (args, util) { + var list = util.target.lookupOrCreateList(args.LIST); + var index = Cast.toListIndex(args.INDEX, list.contents.length); + if (index === Cast.LIST_INVALID) { + return ''; + } + return list.contents[index - 1]; +}; + +Scratch3DataBlocks.prototype.lengthOfList = function (args, util) { + var list = util.target.lookupOrCreateList(args.LIST); + return list.contents.length; +}; + +Scratch3DataBlocks.prototype.listContainsItem = function (args, util) { + var item = args.ITEM; + var list = util.target.lookupOrCreateList(args.LIST); + if (list.contents.indexOf(item) >= 0) { + return true; + } + // Try using Scratch comparison operator on each item. + // (Scratch considers the string '123' equal to the number 123). + for (var i = 0; i < list.contents.length; i++) { + if (Cast.compare(list.contents[i], item) == 0) { + return true; + } + } + return false; +}; + +module.exports = Scratch3DataBlocks; diff --git a/src/blocks/scratch3_event.js b/src/blocks/scratch3_event.js new file mode 100644 index 000000000..7f56e3baf --- /dev/null +++ b/src/blocks/scratch3_event.js @@ -0,0 +1,89 @@ +var Cast = require('../util/cast'); + +function Scratch3EventBlocks(runtime) { + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; +} + +/** + * Retrieve the block primitives implemented by this package. + * @return {Object.<string, Function>} Mapping of opcode to Function. + */ +Scratch3EventBlocks.prototype.getPrimitives = function() { + return { + 'event_broadcast': this.broadcast, + 'event_broadcastandwait': this.broadcastAndWait, + 'event_whengreaterthan': this.hatGreaterThanPredicate + }; +}; + +Scratch3EventBlocks.prototype.getHats = function () { + return { + 'event_whenflagclicked': { + restartExistingThreads: true + }, + 'event_whenkeypressed': { + restartExistingThreads: false + }, + 'event_whenthisspriteclicked': { + restartExistingThreads: true + }, + 'event_whenbackdropswitchesto': { + restartExistingThreads: true + }, + 'event_whengreaterthan': { + restartExistingThreads: false, + edgeActivated: true + }, + 'event_whenbroadcastreceived': { + restartExistingThreads: true + } + }; +}; + +Scratch3EventBlocks.prototype.hatGreaterThanPredicate = function (args, util) { + var option = Cast.toString(args.WHENGREATERTHANMENU).toLowerCase(); + var value = Cast.toNumber(args.VALUE); + // @todo: Other cases :) + if (option == 'timer') { + return util.ioQuery('clock', 'projectTimer') > value; + } + return false; +}; + +Scratch3EventBlocks.prototype.broadcast = function(args, util) { + var broadcastOption = Cast.toString(args.BROADCAST_OPTION); + util.startHats('event_whenbroadcastreceived', { + 'BROADCAST_OPTION': broadcastOption + }); +}; + +Scratch3EventBlocks.prototype.broadcastAndWait = function (args, util) { + var broadcastOption = Cast.toString(args.BROADCAST_OPTION); + // Have we run before, starting threads? + if (!util.stackFrame.startedThreads) { + // No - start hats for this broadcast. + util.stackFrame.startedThreads = util.startHats( + 'event_whenbroadcastreceived', { + 'BROADCAST_OPTION': broadcastOption + } + ); + if (util.stackFrame.startedThreads.length == 0) { + // Nothing was started. + return; + } + } + // We've run before; check if the wait is still going on. + var instance = this; + var waiting = util.stackFrame.startedThreads.some(function(thread) { + return instance.runtime.isActiveThread(thread); + }); + if (waiting) { + util.yield(); + } +}; + +module.exports = Scratch3EventBlocks; diff --git a/src/blocks/scratch3_looks.js b/src/blocks/scratch3_looks.js new file mode 100644 index 000000000..a1d433e94 --- /dev/null +++ b/src/blocks/scratch3_looks.js @@ -0,0 +1,221 @@ +var Cast = require('../util/cast'); + +function Scratch3LooksBlocks(runtime) { + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; +} + +/** + * Retrieve the block primitives implemented by this package. + * @return {Object.<string, Function>} Mapping of opcode to Function. + */ +Scratch3LooksBlocks.prototype.getPrimitives = function() { + return { + 'looks_say': this.say, + 'looks_sayforsecs': this.sayforsecs, + 'looks_think': this.think, + 'looks_thinkforsecs': this.sayforsecs, + 'looks_show': this.show, + 'looks_hide': this.hide, + 'looks_switchcostumeto': this.switchCostume, + 'looks_switchbackdropto': this.switchBackdrop, + 'looks_switchbackdroptoandwait': this.switchBackdropAndWait, + 'looks_nextcostume': this.nextCostume, + 'looks_nextbackdrop': this.nextBackdrop, + 'looks_changeeffectby': this.changeEffect, + 'looks_seteffectto': this.setEffect, + 'looks_cleargraphiceffects': this.clearEffects, + 'looks_changesizeby': this.changeSize, + 'looks_setsizeto': this.setSize, + 'looks_gotofront': this.goToFront, + 'looks_gobacklayers': this.goBackLayers, + 'looks_size': this.getSize, + 'looks_costumeorder': this.getCostumeIndex, + 'looks_backdroporder': this.getBackdropIndex, + 'looks_backdropname': this.getBackdropName + }; +}; + +Scratch3LooksBlocks.prototype.say = function (args, util) { + util.target.setSay('say', args.MESSAGE); +}; + +Scratch3LooksBlocks.prototype.sayforsecs = function (args, util) { + util.target.setSay('say', args.MESSAGE); + return new Promise(function(resolve) { + setTimeout(function() { + // Clear say bubble and proceed. + util.target.setSay(); + resolve(); + }, 1000 * args.SECS); + }); +}; + +Scratch3LooksBlocks.prototype.think = function (args, util) { + util.target.setSay('think', args.MESSAGE); +}; + +Scratch3LooksBlocks.prototype.thinkforsecs = function (args, util) { + util.target.setSay('think', args.MESSAGE); + return new Promise(function(resolve) { + setTimeout(function() { + // Clear say bubble and proceed. + util.target.setSay(); + resolve(); + }, 1000 * args.SECS); + }); +}; + +Scratch3LooksBlocks.prototype.show = function (args, util) { + util.target.setVisible(true); +}; + +Scratch3LooksBlocks.prototype.hide = function (args, util) { + util.target.setVisible(false); +}; + +/** + * Utility function to set the costume or backdrop of a target. + * Matches the behavior of Scratch 2.0 for different types of arguments. + * @param {!Target} target Target to set costume/backdrop to. + * @param {Any} requestedCostume Costume requested, e.g., 0, 'name', etc. + * @param {boolean=} opt_zeroIndex Set to zero-index the requestedCostume. + * @return {Array.<!Thread>} Any threads started by this switch. + */ +Scratch3LooksBlocks.prototype._setCostumeOrBackdrop = function (target, + requestedCostume, opt_zeroIndex) { + if (typeof requestedCostume === 'number') { + target.setCostume(opt_zeroIndex ? + requestedCostume : requestedCostume - 1); + } else { + var costumeIndex = target.getCostumeIndexByName(requestedCostume); + if (costumeIndex > -1) { + target.setCostume(costumeIndex); + } else if (costumeIndex == 'previous costume' || + costumeIndex == 'previous backdrop') { + target.setCostume(target.currentCostume - 1); + } else if (costumeIndex == 'next costume' || + costumeIndex == 'next backdrop') { + target.setCostume(target.currentCostume + 1); + } else { + var forcedNumber = Cast.toNumber(requestedCostume); + if (!isNaN(forcedNumber)) { + target.setCostume(opt_zeroIndex ? + forcedNumber : forcedNumber - 1); + } + } + } + if (target == this.runtime.getTargetForStage()) { + // Target is the stage - start hats. + var newName = target.sprite.costumes[target.currentCostume].name; + return this.runtime.startHats('event_whenbackdropswitchesto', { + 'BACKDROP': newName + }); + } + return []; +}; + +Scratch3LooksBlocks.prototype.switchCostume = function (args, util) { + this._setCostumeOrBackdrop(util.target, args.COSTUME); +}; + +Scratch3LooksBlocks.prototype.nextCostume = function (args, util) { + this._setCostumeOrBackdrop( + util.target, util.target.currentCostume + 1, true + ); +}; + +Scratch3LooksBlocks.prototype.switchBackdrop = function (args) { + this._setCostumeOrBackdrop(this.runtime.getTargetForStage(), args.BACKDROP); +}; + +Scratch3LooksBlocks.prototype.switchBackdropAndWait = function (args, util) { + // Have we run before, starting threads? + if (!util.stackFrame.startedThreads) { + // No - switch the backdrop. + util.stackFrame.startedThreads = ( + this._setCostumeOrBackdrop( + this.runtime.getTargetForStage(), + args.BACKDROP + ) + ); + if (util.stackFrame.startedThreads.length == 0) { + // Nothing was started. + return; + } + } + // We've run before; check if the wait is still going on. + var instance = this; + var waiting = util.stackFrame.startedThreads.some(function(thread) { + return instance.runtime.isActiveThread(thread); + }); + if (waiting) { + util.yield(); + } +}; + +Scratch3LooksBlocks.prototype.nextBackdrop = function () { + var stage = this.runtime.getTargetForStage(); + this._setCostumeOrBackdrop( + stage, stage.currentCostume + 1, true + ); +}; + +Scratch3LooksBlocks.prototype.changeEffect = function (args, util) { + var effect = Cast.toString(args.EFFECT).toLowerCase(); + var change = Cast.toNumber(args.CHANGE); + if (!util.target.effects.hasOwnProperty(effect)) return; + var newValue = change + util.target.effects[effect]; + util.target.setEffect(effect, newValue); +}; + +Scratch3LooksBlocks.prototype.setEffect = function (args, util) { + var effect = Cast.toString(args.EFFECT).toLowerCase(); + var value = Cast.toNumber(args.VALUE); + util.target.setEffect(effect, value); +}; + +Scratch3LooksBlocks.prototype.clearEffects = function (args, util) { + util.target.clearEffects(); +}; + +Scratch3LooksBlocks.prototype.changeSize = function (args, util) { + var change = Cast.toNumber(args.CHANGE); + util.target.setSize(util.target.size + change); +}; + +Scratch3LooksBlocks.prototype.setSize = function (args, util) { + var size = Cast.toNumber(args.SIZE); + util.target.setSize(size); +}; + +Scratch3LooksBlocks.prototype.goToFront = function (args, util) { + util.target.goToFront(); +}; + +Scratch3LooksBlocks.prototype.goBackLayers = function (args, util) { + util.target.goBackLayers(args.NUM); +}; + +Scratch3LooksBlocks.prototype.getSize = function (args, util) { + return util.target.size; +}; + +Scratch3LooksBlocks.prototype.getBackdropIndex = function () { + var stage = this.runtime.getTargetForStage(); + return stage.currentCostume + 1; +}; + +Scratch3LooksBlocks.prototype.getBackdropName = function () { + var stage = this.runtime.getTargetForStage(); + return stage.sprite.costumes[stage.currentCostume].name; +}; + +Scratch3LooksBlocks.prototype.getCostumeIndex = function (args, util) { + return util.target.currentCostume + 1; +}; + +module.exports = Scratch3LooksBlocks; diff --git a/src/blocks/scratch3_motion.js b/src/blocks/scratch3_motion.js new file mode 100644 index 000000000..68078578b --- /dev/null +++ b/src/blocks/scratch3_motion.js @@ -0,0 +1,234 @@ +var Cast = require('../util/cast'); +var MathUtil = require('../util/math-util'); +var Timer = require('../util/timer'); + +function Scratch3MotionBlocks(runtime) { + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; +} + +/** + * Retrieve the block primitives implemented by this package. + * @return {Object.<string, Function>} Mapping of opcode to Function. + */ +Scratch3MotionBlocks.prototype.getPrimitives = function() { + return { + 'motion_movesteps': this.moveSteps, + 'motion_gotoxy': this.goToXY, + 'motion_goto': this.goTo, + 'motion_turnright': this.turnRight, + 'motion_turnleft': this.turnLeft, + 'motion_pointindirection': this.pointInDirection, + 'motion_pointtowards': this.pointTowards, + 'motion_glidesecstoxy': this.glide, + 'motion_ifonedgebounce': this.ifOnEdgeBounce, + 'motion_setrotationstyle': this.setRotationStyle, + 'motion_changexby': this.changeX, + 'motion_setx': this.setX, + 'motion_changeyby': this.changeY, + 'motion_sety': this.setY, + 'motion_xposition': this.getX, + 'motion_yposition': this.getY, + 'motion_direction': this.getDirection + }; +}; + +Scratch3MotionBlocks.prototype.moveSteps = function (args, util) { + var steps = Cast.toNumber(args.STEPS); + var radians = MathUtil.degToRad(90 - util.target.direction); + var dx = steps * Math.cos(radians); + var dy = steps * Math.sin(radians); + util.target.setXY(util.target.x + dx, util.target.y + dy); +}; + +Scratch3MotionBlocks.prototype.goToXY = function (args, util) { + var x = Cast.toNumber(args.X); + var y = Cast.toNumber(args.Y); + util.target.setXY(x, y); +}; + +Scratch3MotionBlocks.prototype.goTo = function (args, util) { + var targetX = 0; + var targetY = 0; + if (args.TO === '_mouse_') { + targetX = util.ioQuery('mouse', 'getX'); + targetY = util.ioQuery('mouse', 'getY'); + } else if (args.TO === '_random_') { + var stageWidth = this.runtime.constructor.STAGE_WIDTH; + var stageHeight = this.runtime.constructor.STAGE_HEIGHT; + targetX = Math.round(stageWidth * (Math.random() - 0.5)); + targetY = Math.round(stageHeight * (Math.random() - 0.5)); + } else { + var goToTarget = this.runtime.getSpriteTargetByName(args.TO); + if (!goToTarget) return; + targetX = goToTarget.x; + targetY = goToTarget.y; + } + util.target.setXY(targetX, targetY); +}; + +Scratch3MotionBlocks.prototype.turnRight = function (args, util) { + var degrees = Cast.toNumber(args.DEGREES); + util.target.setDirection(util.target.direction + degrees); +}; + +Scratch3MotionBlocks.prototype.turnLeft = function (args, util) { + var degrees = Cast.toNumber(args.DEGREES); + util.target.setDirection(util.target.direction - degrees); +}; + +Scratch3MotionBlocks.prototype.pointInDirection = function (args, util) { + var direction = Cast.toNumber(args.DIRECTION); + util.target.setDirection(direction); +}; + +Scratch3MotionBlocks.prototype.pointTowards = function (args, util) { + var targetX = 0; + var targetY = 0; + if (args.TOWARDS === '_mouse_') { + targetX = util.ioQuery('mouse', 'getX'); + targetY = util.ioQuery('mouse', 'getY'); + } else { + var pointTarget = this.runtime.getSpriteTargetByName(args.TOWARDS); + if (!pointTarget) return; + targetX = pointTarget.x; + targetY = pointTarget.y; + } + + var dx = targetX - util.target.x; + var dy = targetY - util.target.y; + var direction = 90 - MathUtil.radToDeg(Math.atan2(dy, dx)); + util.target.setDirection(direction); +}; + +Scratch3MotionBlocks.prototype.glide = function (args, util) { + if (!util.stackFrame.timer) { + // First time: save data for future use. + util.stackFrame.timer = new Timer(); + util.stackFrame.timer.start(); + util.stackFrame.duration = Cast.toNumber(args.SECS); + util.stackFrame.startX = util.target.x; + util.stackFrame.startY = util.target.y; + util.stackFrame.endX = Cast.toNumber(args.X); + util.stackFrame.endY = Cast.toNumber(args.Y); + if (util.stackFrame.duration <= 0) { + // Duration too short to glide. + util.target.setXY(util.stackFrame.endX, util.stackFrame.endY); + return; + } + util.yield(); + } else { + var timeElapsed = util.stackFrame.timer.timeElapsed(); + if (timeElapsed < util.stackFrame.duration * 1000) { + // In progress: move to intermediate position. + var frac = timeElapsed / (util.stackFrame.duration * 1000); + var dx = frac * (util.stackFrame.endX - util.stackFrame.startX); + var dy = frac * (util.stackFrame.endY - util.stackFrame.startY); + util.target.setXY( + util.stackFrame.startX + dx, + util.stackFrame.startY + dy + ); + util.yield(); + } else { + // Finished: move to final position. + util.target.setXY(util.stackFrame.endX, util.stackFrame.endY); + } + } +}; + +Scratch3MotionBlocks.prototype.ifOnEdgeBounce = function (args, util) { + var bounds = util.target.getBounds(); + if (!bounds) { + return; + } + // Measure distance to edges. + // Values are positive when the sprite is far away, + // and clamped to zero when the sprite is beyond. + var stageWidth = this.runtime.constructor.STAGE_WIDTH; + var stageHeight = this.runtime.constructor.STAGE_HEIGHT; + var distLeft = Math.max(0, stageWidth / 2 + bounds.left); + var distTop = Math.max(0, stageHeight / 2 - bounds.top); + var distRight = Math.max(0, stageWidth / 2 - bounds.right); + var distBottom = Math.max(0, stageHeight / 2 + bounds.bottom); + // Find the nearest edge. + var nearestEdge = ''; + var minDist = Infinity; + if (distLeft < minDist) { + minDist = distLeft; + nearestEdge = 'left'; + } + if (distTop < minDist) { + minDist = distTop; + nearestEdge = 'top'; + } + if (distRight < minDist) { + minDist = distRight; + nearestEdge = 'right'; + } + if (distBottom < minDist) { + minDist = distBottom; + nearestEdge = 'bottom'; + } + if (minDist > 0) { + return; // Not touching any edge. + } + // Point away from the nearest edge. + var radians = MathUtil.degToRad(90 - util.target.direction); + var dx = Math.cos(radians); + var dy = -Math.sin(radians); + if (nearestEdge == 'left') { + dx = Math.max(0.2, Math.abs(dx)); + } else if (nearestEdge == 'top') { + dy = Math.max(0.2, Math.abs(dy)); + } else if (nearestEdge == 'right') { + dx = 0 - Math.max(0.2, Math.abs(dx)); + } else if (nearestEdge == 'bottom') { + dy = 0 - Math.max(0.2, Math.abs(dy)); + } + var newDirection = MathUtil.radToDeg(Math.atan2(dy, dx)) + 90; + util.target.setDirection(newDirection); + // Keep within the stage. + var fencedPosition = util.target.keepInFence(util.target.x, util.target.y); + util.target.setXY(fencedPosition[0], fencedPosition[1]); +}; + +Scratch3MotionBlocks.prototype.setRotationStyle = function (args, util) { + util.target.setRotationStyle(args.STYLE); +}; + +Scratch3MotionBlocks.prototype.changeX = function (args, util) { + var dx = Cast.toNumber(args.DX); + util.target.setXY(util.target.x + dx, util.target.y); +}; + +Scratch3MotionBlocks.prototype.setX = function (args, util) { + var x = Cast.toNumber(args.X); + util.target.setXY(x, util.target.y); +}; + +Scratch3MotionBlocks.prototype.changeY = function (args, util) { + var dy = Cast.toNumber(args.DY); + util.target.setXY(util.target.x, util.target.y + dy); +}; + +Scratch3MotionBlocks.prototype.setY = function (args, util) { + var y = Cast.toNumber(args.Y); + util.target.setXY(util.target.x, y); +}; + +Scratch3MotionBlocks.prototype.getX = function (args, util) { + return util.target.x; +}; + +Scratch3MotionBlocks.prototype.getY = function (args, util) { + return util.target.y; +}; + +Scratch3MotionBlocks.prototype.getDirection = function (args, util) { + return util.target.direction; +}; + +module.exports = Scratch3MotionBlocks; diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js new file mode 100644 index 000000000..0d5531778 --- /dev/null +++ b/src/blocks/scratch3_operators.js @@ -0,0 +1,143 @@ +var Cast = require('../util/cast.js'); + +function Scratch3OperatorsBlocks(runtime) { + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; +} + +/** + * Retrieve the block primitives implemented by this package. + * @return {Object.<string, Function>} Mapping of opcode to Function. + */ +Scratch3OperatorsBlocks.prototype.getPrimitives = function() { + return { + 'operator_add': this.add, + 'operator_subtract': this.subtract, + 'operator_multiply': this.multiply, + 'operator_divide': this.divide, + 'operator_lt': this.lt, + 'operator_equals': this.equals, + 'operator_gt': this.gt, + 'operator_and': this.and, + 'operator_or': this.or, + 'operator_not': this.not, + 'operator_random': this.random, + 'operator_join': this.join, + 'operator_letter_of': this.letterOf, + 'operator_length': this.length, + 'operator_mod': this.mod, + 'operator_round': this.round, + 'operator_mathop': this.mathop + }; +}; + +Scratch3OperatorsBlocks.prototype.add = function (args) { + return Cast.toNumber(args.NUM1) + Cast.toNumber(args.NUM2); +}; + +Scratch3OperatorsBlocks.prototype.subtract = function (args) { + return Cast.toNumber(args.NUM1) - Cast.toNumber(args.NUM2); +}; + +Scratch3OperatorsBlocks.prototype.multiply = function (args) { + return Cast.toNumber(args.NUM1) * Cast.toNumber(args.NUM2); +}; + +Scratch3OperatorsBlocks.prototype.divide = function (args) { + return Cast.toNumber(args.NUM1) / Cast.toNumber(args.NUM2); +}; + +Scratch3OperatorsBlocks.prototype.lt = function (args) { + return Cast.compare(args.OPERAND1, args.OPERAND2) < 0; +}; + +Scratch3OperatorsBlocks.prototype.equals = function (args) { + return Cast.compare(args.OPERAND1, args.OPERAND2) == 0; +}; + +Scratch3OperatorsBlocks.prototype.gt = function (args) { + return Cast.compare(args.OPERAND1, args.OPERAND2) > 0; +}; + +Scratch3OperatorsBlocks.prototype.and = function (args) { + return Cast.toBoolean(args.OPERAND1) && Cast.toBoolean(args.OPERAND2); +}; + +Scratch3OperatorsBlocks.prototype.or = function (args) { + return Cast.toBoolean(args.OPERAND1) || Cast.toBoolean(args.OPERAND2); +}; + +Scratch3OperatorsBlocks.prototype.not = function (args) { + return !Cast.toBoolean(args.OPERAND); +}; + +Scratch3OperatorsBlocks.prototype.random = function (args) { + var nFrom = Cast.toNumber(args.FROM); + var nTo = Cast.toNumber(args.TO); + var low = nFrom <= nTo ? nFrom : nTo; + var high = nFrom <= nTo ? nTo : nFrom; + if (low == high) return low; + // If both arguments are ints, truncate the result to an int. + if (Cast.isInt(args.FROM) && Cast.isInt(args.TO)) { + return low + parseInt(Math.random() * ((high + 1) - low)); + } + return (Math.random() * (high - low)) + low; +}; + +Scratch3OperatorsBlocks.prototype.join = function (args) { + return Cast.toString(args.STRING1) + Cast.toString(args.STRING2); +}; + +Scratch3OperatorsBlocks.prototype.letterOf = function (args) { + var index = Cast.toNumber(args.LETTER) - 1; + var str = Cast.toString(args.STRING); + // Out of bounds? + if (index < 0 || index >= str.length) { + return ''; + } + return str.charAt(index); +}; + +Scratch3OperatorsBlocks.prototype.length = function (args) { + return Cast.toString(args.STRING).length; +}; + +Scratch3OperatorsBlocks.prototype.mod = function (args) { + var n = Cast.toNumber(args.NUM1); + var modulus = Cast.toNumber(args.NUM2); + var result = n % modulus; + // Scratch mod is kept positive. + if (result / modulus < 0) result += modulus; + return result; +}; + +Scratch3OperatorsBlocks.prototype.round = function (args) { + return Math.round(Cast.toNumber(args.NUM)); +}; + +Scratch3OperatorsBlocks.prototype.mathop = function (args) { + var operator = Cast.toString(args.OPERATOR).toLowerCase(); + var n = Cast.toNumber(args.NUM); + switch (operator) { + case 'abs': return Math.abs(n); + case 'floor': return Math.floor(n); + case 'ceiling': return Math.ceil(n); + case 'sqrt': return Math.sqrt(n); + case 'sin': return Math.sin((Math.PI * n) / 180); + case 'cos': return Math.cos((Math.PI * n) / 180); + case 'tan': return Math.tan((Math.PI * n) / 180); + case 'asin': return (Math.asin(n) * 180) / Math.PI; + case 'acos': return (Math.acos(n) * 180) / Math.PI; + case 'atan': return (Math.atan(n) * 180) / Math.PI; + case 'ln': return Math.log(n); + case 'log': return Math.log(n) / Math.LN10; + case 'e ^': return Math.exp(n); + case '10 ^': return Math.pow(10, n); + } + return 0; +}; + +module.exports = Scratch3OperatorsBlocks; diff --git a/src/blocks/scratch3_procedures.js b/src/blocks/scratch3_procedures.js new file mode 100644 index 000000000..19a6df370 --- /dev/null +++ b/src/blocks/scratch3_procedures.js @@ -0,0 +1,44 @@ +function Scratch3ProcedureBlocks(runtime) { + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; +} + +/** + * Retrieve the block primitives implemented by this package. + * @return {Object.<string, Function>} Mapping of opcode to Function. + */ +Scratch3ProcedureBlocks.prototype.getPrimitives = function() { + return { + 'procedures_defnoreturn': this.defNoReturn, + 'procedures_callnoreturn': this.callNoReturn, + 'procedures_param': this.param + }; +}; + +Scratch3ProcedureBlocks.prototype.defNoReturn = function () { + // No-op: execute the blocks. +}; + +Scratch3ProcedureBlocks.prototype.callNoReturn = function (args, util) { + if (!util.stackFrame.executed) { + var procedureCode = args.mutation.proccode; + var paramNames = util.getProcedureParamNames(procedureCode); + for (var i = 0; i < paramNames.length; i++) { + if (args.hasOwnProperty('input' + i)) { + util.pushParam(paramNames[i], args['input' + i]); + } + } + util.stackFrame.executed = true; + util.startProcedure(procedureCode); + } +}; + +Scratch3ProcedureBlocks.prototype.param = function (args, util) { + var value = util.getParam(args.mutation.paramname); + return value; +}; + +module.exports = Scratch3ProcedureBlocks; diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js new file mode 100644 index 000000000..293273936 --- /dev/null +++ b/src/blocks/scratch3_sensing.js @@ -0,0 +1,128 @@ +var Cast = require('../util/cast'); + +function Scratch3SensingBlocks(runtime) { + /** + * The runtime instantiating this block package. + * @type {Runtime} + */ + this.runtime = runtime; +} + +/** + * Retrieve the block primitives implemented by this package. + * @return {Object.<string, Function>} Mapping of opcode to Function. + */ +Scratch3SensingBlocks.prototype.getPrimitives = function() { + return { + 'sensing_touchingobject': this.touchingObject, + 'sensing_touchingcolor': this.touchingColor, + 'sensing_coloristouchingcolor': this.colorTouchingColor, + 'sensing_distanceto': this.distanceTo, + 'sensing_timer': this.getTimer, + 'sensing_resettimer': this.resetTimer, + 'sensing_mousex': this.getMouseX, + 'sensing_mousey': this.getMouseY, + 'sensing_mousedown': this.getMouseDown, + 'sensing_keypressed': this.getKeyPressed, + 'sensing_current': this.current, + 'sensing_dayssince2000': this.daysSince2000 + }; +}; + +Scratch3SensingBlocks.prototype.touchingObject = function (args, util) { + var requestedObject = args.TOUCHINGOBJECTMENU; + if (requestedObject == '_mouse_') { + var mouseX = util.ioQuery('mouse', 'getX'); + var mouseY = util.ioQuery('mouse', 'getY'); + return util.target.isTouchingPoint(mouseX, mouseY); + } else if (requestedObject == '_edge_') { + return util.target.isTouchingEdge(); + } else { + return util.target.isTouchingSprite(requestedObject); + } +}; + +Scratch3SensingBlocks.prototype.touchingColor = function (args, util) { + var color = Cast.toRgbColorList(args.COLOR); + return util.target.isTouchingColor(color); +}; + +Scratch3SensingBlocks.prototype.colorTouchingColor = function (args, util) { + var maskColor = Cast.toRgbColorList(args.COLOR); + var targetColor = Cast.toRgbColorList(args.COLOR2); + return util.target.colorIsTouchingColor(targetColor, maskColor); +}; + +Scratch3SensingBlocks.prototype.distanceTo = function (args, util) { + if (util.target.isStage) return 10000; + + var targetX = 0; + var targetY = 0; + if (args.DISTANCETOMENU === '_mouse_') { + targetX = util.ioQuery('mouse', 'getX'); + targetY = util.ioQuery('mouse', 'getY'); + } else { + var distTarget = this.runtime.getSpriteTargetByName( + args.DISTANCETOMENU + ); + if (!distTarget) return 10000; + targetX = distTarget.x; + targetY = distTarget.y; + } + + var dx = util.target.x - targetX; + var dy = util.target.y - targetY; + return Math.sqrt((dx * dx) + (dy * dy)); +}; + +Scratch3SensingBlocks.prototype.getTimer = function (args, util) { + return util.ioQuery('clock', 'projectTimer'); +}; + +Scratch3SensingBlocks.prototype.resetTimer = function (args, util) { + util.ioQuery('clock', 'resetProjectTimer'); +}; + +Scratch3SensingBlocks.prototype.getMouseX = function (args, util) { + return util.ioQuery('mouse', 'getX'); +}; + +Scratch3SensingBlocks.prototype.getMouseY = function (args, util) { + return util.ioQuery('mouse', 'getY'); +}; + +Scratch3SensingBlocks.prototype.getMouseDown = function (args, util) { + return util.ioQuery('mouse', 'getIsDown'); +}; + +Scratch3SensingBlocks.prototype.current = function (args) { + var menuOption = Cast.toString(args.CURRENTMENU).toLowerCase(); + var date = new Date(); + switch (menuOption) { + case 'year': return date.getFullYear(); + case 'month': return date.getMonth() + 1; // getMonth is zero-based + case 'date': return date.getDate(); + case 'dayofweek': return date.getDay() + 1; // getDay is zero-based, Sun=0 + case 'hour': return date.getHours(); + case 'minute': return date.getMinutes(); + case 'second': return date.getSeconds(); + } + return 0; +}; + +Scratch3SensingBlocks.prototype.getKeyPressed = function (args, util) { + return util.ioQuery('keyboard', 'getKeyIsDown', args.KEY_OPTION); +}; + +Scratch3SensingBlocks.prototype.daysSince2000 = function() +{ + var msPerDay = 24 * 60 * 60 * 1000; + var start = new Date(2000, 1-1, 1); + var today = new Date(); + var dstAdjust = today.getTimezoneOffset() - start.getTimezoneOffset(); + var mSecsSinceStart = today.valueOf() - start.valueOf(); + mSecsSinceStart += ((today.getTimezoneOffset() - dstAdjust) * 60 * 1000); + return mSecsSinceStart / msPerDay; +}; + +module.exports = Scratch3SensingBlocks; diff --git a/src/blocks/wedo2.js b/src/blocks/wedo2.js deleted file mode 100644 index 86c73de07..000000000 --- a/src/blocks/wedo2.js +++ /dev/null @@ -1,154 +0,0 @@ - -var YieldTimers = require('../util/yieldtimers.js'); - -function WeDo2Blocks(runtime) { - /** - * The runtime instantiating this block package. - * @type {Runtime} - */ - this.runtime = runtime; - - /** - * Current motor speed, as a percentage (100 = full speed). - * @type {number} - * @private - */ - this._motorSpeed = 100; - - /** - * The timeout ID for a pending motor action. - * @type {?int} - * @private - */ - this._motorTimeout = null; -} - -/** - * Retrieve the block primitives implemented by this package. - * @return {Object.<string, Function>} Mapping of opcode to Function. - */ -WeDo2Blocks.prototype.getPrimitives = function() { - return { - 'wedo_motorclockwise': this.motorClockwise, - 'wedo_motorcounterclockwise': this.motorCounterClockwise, - 'wedo_motorspeed': this.motorSpeed, - 'wedo_setcolor': this.setColor, - 'wedo_whendistanceclose': this.whenDistanceClose, - 'wedo_whentilt': this.whenTilt - }; -}; - -/** - * Clamp a value between a minimum and maximum value. - * @todo move this to a common utility class. - * @param val The value to clamp. - * @param min The minimum return value. - * @param max The maximum return value. - * @returns {number} The clamped value. - * @private - */ -WeDo2Blocks.prototype._clamp = function(val, min, max) { - return Math.max(min, Math.min(val, max)); -}; - -/** - * Common implementation for motor blocks. - * @param direction The direction to turn ('left' or 'right'). - * @param durationSeconds The number of seconds to run. - * @param util The util instance to use for yielding and finishing. - * @private - */ -WeDo2Blocks.prototype._motorOnFor = function(direction, durationSeconds, util) { - if (this._motorTimeout > 0) { - // @todo maybe this should go through util - YieldTimers.resolve(this._motorTimeout); - this._motorTimeout = null; - } - if (window.native) { - window.native.motorRun(direction, this._motorSpeed); - } - - var instance = this; - var myTimeout = this._motorTimeout = util.timeout(function() { - if (instance._motorTimeout == myTimeout) { - instance._motorTimeout = null; - } - if (window.native) { - window.native.motorStop(); - } - util.done(); - }, 1000 * durationSeconds); - - util.yield(); -}; - -WeDo2Blocks.prototype.motorClockwise = function(argValues, util) { - this._motorOnFor('right', parseFloat(argValues[0]), util); -}; - -WeDo2Blocks.prototype.motorCounterClockwise = function(argValues, util) { - this._motorOnFor('left', parseFloat(argValues[0]), util); -}; - -WeDo2Blocks.prototype.motorSpeed = function(argValues) { - var speed = argValues[0]; - switch (speed) { - case 'slow': - this._motorSpeed = 20; - break; - case 'medium': - this._motorSpeed = 50; - break; - case 'fast': - this._motorSpeed = 100; - break; - } -}; - -/** - * Convert a color name to a WeDo color index. - * Supports 'mystery' for a random hue. - * @param colorName The color to retrieve. - * @returns {number} The WeDo color index. - * @private - */ -WeDo2Blocks.prototype._getColor = function(colorName) { - var colors = { - 'yellow': 7, - 'orange': 8, - 'coral': 9, - 'magenta': 1, - 'purple': 2, - 'blue': 3, - 'green': 6, - 'white': 10 - }; - - if (colorName == 'mystery') { - return Math.floor((Math.random() * 10) + 1); - } - - return colors[colorName]; -}; - -WeDo2Blocks.prototype.setColor = function(argValues, util) { - if (window.native) { - var colorIndex = this._getColor(argValues[0]); - window.native.setLedColor(colorIndex); - } - // Pause for quarter second - util.yield(); - util.timeout(function() { - util.done(); - }, 250); -}; - -WeDo2Blocks.prototype.whenDistanceClose = function() { - console.log('Running: wedo_whendistanceclose'); -}; - -WeDo2Blocks.prototype.whenTilt = function() { - console.log('Running: wedo_whentilt'); -}; - -module.exports = WeDo2Blocks; diff --git a/src/engine/adapter.js b/src/engine/adapter.js index 222273c5c..327aae5e3 100644 --- a/src/engine/adapter.js +++ b/src/engine/adapter.js @@ -1,87 +1,147 @@ +var mutationAdapter = require('./mutation-adapter'); var html = require('htmlparser2'); -var memoize = require('memoizee'); -var parseDOM = memoize(html.parseDOM, { - length: 1, - resolvers: [String], - max: 200 -}); /** * Adapter between block creation events and block representation which can be * used by the Scratch runtime. - * - * @param {Object} `Blockly.events.create` - * - * @return {Object} + * @param {Object} e `Blockly.events.create` + * @return {Array.<Object>} List of blocks from this CREATE event. */ module.exports = function (e) { // Validate input if (typeof e !== 'object') return; - if (typeof e.blockId !== 'string') return; if (typeof e.xml !== 'object') return; - // Storage object - var obj = { - id: e.blockId, - opcode: null, - next: null, - fields: {} - }; - - // Set opcode - if (typeof e.xml.attributes === 'object') { - obj.opcode = e.xml.attributes.type.value; - } - - // Extract fields from event's `innerHTML` - if (typeof e.xml.innerHTML !== 'string') return obj; - if (e.xml.innerHTML === '') return obj; - obj.fields = extract(parseDOM(e.xml.innerHTML)); - - return obj; + return domToBlocks(html.parseDOM(e.xml.outerHTML)); }; /** - * Extracts fields from a block's innerHTML. - * @todo Extend this to support vertical grammar / nested blocks. - * - * @param {Object} DOM representation of block's innerHTML - * - * @return {Object} + * Convert outer blocks DOM from a Blockly CREATE event + * to a usable form for the Scratch runtime. + * This structure is based on Blockly xml.js:`domToWorkspace` and `domToBlock`. + * @param {Element} blocksDOM DOM tree for this event. + * @return {Array.<Object>} Usable list of blocks from this CREATE event. */ -function extract (dom) { - // Storage object - var fields = {}; - - // Field - var field = dom[0]; - var fieldName = field.attribs.name; - fields[fieldName] = { - name: fieldName, - value: null, - blocks: {} - }; - - // Shadow block - var shadow = field.children[0]; - var shadowId = shadow.attribs.id; - var shadowOpcode = shadow.attribs.type; - fields[fieldName].blocks[shadowId] = { - id: shadowId, - opcode: shadowOpcode, - next: null, - fields: {} - }; - - // Primitive - var primitive = shadow.children[0]; - var primitiveName = primitive.attribs.name; - var primitiveValue = primitive.children[0].data; - fields[fieldName].blocks[shadowId].fields[primitiveName] = { - name: primitiveName, - value: primitiveValue, - blocks: null - }; - - return fields; +function domToBlocks (blocksDOM) { + // At this level, there could be multiple blocks adjacent in the DOM tree. + var blocks = {}; + for (var i = 0; i < blocksDOM.length; i++) { + var block = blocksDOM[i]; + if (!block.name || !block.attribs) { + continue; + } + var tagName = block.name.toLowerCase(); + if (tagName == 'block' || tagName == 'shadow') { + domToBlock(block, blocks, true, null); + } + } + // Flatten blocks object into a list. + var blocksList = []; + for (var b in blocks) { + blocksList.push(blocks[b]); + } + return blocksList; +} + +/** + * Convert and an individual block DOM to the representation tree. + * Based on Blockly's `domToBlockHeadless_`. + * @param {Element} blockDOM DOM tree for an individual block. + * @param {Object} blocks Collection of blocks to add to. + * @param {Boolean} isTopBlock Whether blocks at this level are "top blocks." + * @param {?string} parent Parent block ID. + */ +function domToBlock (blockDOM, blocks, isTopBlock, parent) { + // Block skeleton. + var block = { + id: blockDOM.attribs.id, // Block ID + opcode: blockDOM.attribs.type, // For execution, "event_whengreenflag". + inputs: {}, // Inputs to this block and the blocks they point to. + fields: {}, // Fields on this block and their values. + next: null, // Next block in the stack, if one exists. + topLevel: isTopBlock, // If this block starts a stack. + parent: parent, // Parent block ID, if available. + shadow: blockDOM.name == 'shadow', // If this represents a shadow/slot. + x: blockDOM.attribs.x, // X position of script, if top-level. + y: blockDOM.attribs.y // Y position of script, if top-level. + }; + + // Add the block to the representation tree. + blocks[block.id] = block; + + // Process XML children and find enclosed blocks, fields, etc. + for (var i = 0; i < blockDOM.children.length; i++) { + var xmlChild = blockDOM.children[i]; + // Enclosed blocks and shadows + var childBlockNode = null; + var childShadowNode = null; + for (var j = 0; j < xmlChild.children.length; j++) { + var grandChildNode = xmlChild.children[j]; + if (!grandChildNode.name) { + // Non-XML tag node. + continue; + } + var grandChildNodeName = grandChildNode.name.toLowerCase(); + if (grandChildNodeName == 'block') { + childBlockNode = grandChildNode; + } else if (grandChildNodeName == 'shadow') { + childShadowNode = grandChildNode; + } + } + + // Use shadow block only if there's no real block node. + if (!childBlockNode && childShadowNode) { + childBlockNode = childShadowNode; + } + + // Not all Blockly-type blocks are handled here, + // as we won't be using all of them for Scratch. + switch (xmlChild.name.toLowerCase()) { + case 'field': + // Add the field to this block. + var fieldName = xmlChild.attribs.name; + var fieldData = ''; + if (xmlChild.children.length > 0 && xmlChild.children[0].data) { + fieldData = xmlChild.children[0].data; + } else { + // If the child of the field with a data property + // doesn't exist, set the data to an empty string. + fieldData = ''; + } + block.fields[fieldName] = { + name: fieldName, + value: fieldData + }; + break; + case 'value': + case 'statement': + // Recursively generate block structure for input block. + domToBlock(childBlockNode, blocks, false, block.id); + if (childShadowNode && childBlockNode != childShadowNode) { + // Also generate the shadow block. + domToBlock(childShadowNode, blocks, false, block.id); + } + // Link this block's input to the child block. + var inputName = xmlChild.attribs.name; + block.inputs[inputName] = { + name: inputName, + block: childBlockNode.attribs.id, + shadow: childShadowNode ? childShadowNode.attribs.id : null + }; + break; + case 'next': + if (!childBlockNode || !childBlockNode.attribs) { + // Invalid child block. + continue; + } + // Recursively generate block structure for next block. + domToBlock(childBlockNode, blocks, false, block.id); + // Link next block to this block. + block.next = childBlockNode.attribs.id; + break; + case 'mutation': + block.mutation = mutationAdapter(xmlChild); + break; + } + } } diff --git a/src/engine/blocks.js b/src/engine/blocks.js new file mode 100644 index 000000000..0e89025e9 --- /dev/null +++ b/src/engine/blocks.js @@ -0,0 +1,494 @@ +var adapter = require('./adapter'); +var mutationAdapter = require('./mutation-adapter'); +var xmlEscape = require('../util/xml-escape'); + +/** + * @fileoverview + * Store and mutate the VM block representation, + * and handle updates from Scratch Blocks events. + */ + +function Blocks () { + /** + * All blocks in the workspace. + * Keys are block IDs, values are metadata about the block. + * @type {Object.<string, Object>} + */ + this._blocks = {}; + + /** + * All top-level scripts in the workspace. + * A list of block IDs that represent scripts (i.e., first block in script). + * @type {Array.<String>} + */ + this._scripts = []; +} + +/** + * Blockly inputs that represent statements/branch. + * are prefixed with this string. + * @const{string} + */ +Blocks.BRANCH_INPUT_PREFIX = 'SUBSTACK'; + +/** + * Provide an object with metadata for the requested block ID. + * @param {!string} blockId ID of block we have stored. + * @return {?Object} Metadata about the block, if it exists. + */ +Blocks.prototype.getBlock = function (blockId) { + return this._blocks[blockId]; +}; + +/** + * Get all known top-level blocks that start scripts. + * @return {Array.<string>} List of block IDs. + */ +Blocks.prototype.getScripts = function () { + return this._scripts; +}; + + /** + * Get the next block for a particular block + * @param {?string} id ID of block to get the next block for + * @return {?string} ID of next block in the sequence + */ +Blocks.prototype.getNextBlock = function (id) { + if (typeof this._blocks[id] === 'undefined') return null; + return this._blocks[id].next; +}; + +/** + * Get the branch for a particular C-shaped block. + * @param {?string} id ID for block to get the branch for. + * @param {?number} branchNum Which branch to select (e.g. for if-else). + * @return {?string} ID of block in the branch. + */ +Blocks.prototype.getBranch = function (id, branchNum) { + var block = this._blocks[id]; + if (typeof block === 'undefined') return null; + if (!branchNum) branchNum = 1; + + var inputName = Blocks.BRANCH_INPUT_PREFIX; + if (branchNum > 1) { + inputName += branchNum; + } + + // Empty C-block? + if (!(inputName in block.inputs)) return null; + return block.inputs[inputName].block; +}; + +/** + * Get the opcode for a particular block + * @param {?string} id ID of block to query + * @return {?string} the opcode corresponding to that block + */ +Blocks.prototype.getOpcode = function (id) { + if (typeof this._blocks[id] === 'undefined') return null; + return this._blocks[id].opcode; +}; + +/** + * Get all fields and their values for a block. + * @param {?string} id ID of block to query. + * @return {!Object} All fields and their values. + */ +Blocks.prototype.getFields = function (id) { + if (typeof this._blocks[id] === 'undefined') return null; + return this._blocks[id].fields; +}; + +/** + * Get all non-branch inputs for a block. + * @param {?string} id ID of block to query. + * @return {!Object} All non-branch inputs and their associated blocks. + */ +Blocks.prototype.getInputs = function (id) { + if (typeof this._blocks[id] === 'undefined') return null; + var inputs = {}; + for (var input in this._blocks[id].inputs) { + // Ignore blocks prefixed with branch prefix. + if (input.substring(0, Blocks.BRANCH_INPUT_PREFIX.length) + != Blocks.BRANCH_INPUT_PREFIX) { + inputs[input] = this._blocks[id].inputs[input]; + } + } + return inputs; +}; + +/** + * Get mutation data for a block. + * @param {?string} id ID of block to query. + * @return {!Object} Mutation for the block. + */ +Blocks.prototype.getMutation = function (id) { + if (typeof this._blocks[id] === 'undefined') return null; + return this._blocks[id].mutation; +}; + +/** + * Get the top-level script for a given block. + * @param {?string} id ID of block to query. + * @return {?string} ID of top-level script block. + */ +Blocks.prototype.getTopLevelScript = function (id) { + if (typeof this._blocks[id] === 'undefined') return null; + var block = this._blocks[id]; + while (block.parent !== null) { + block = this._blocks[block.parent]; + } + return block.id; +}; + +/** + * Get the procedure definition for a given name. + * @param {?string} name Name of procedure to query. + * @return {?string} ID of procedure definition. + */ +Blocks.prototype.getProcedureDefinition = function (name) { + for (var id in this._blocks) { + var block = this._blocks[id]; + if ((block.opcode == 'procedures_defnoreturn' || + block.opcode == 'procedures_defreturn') && + block.mutation.proccode == name) { + return id; + } + } + return null; +}; + +/** + * Get the procedure definition for a given name. + * @param {?string} name Name of procedure to query. + * @return {?string} ID of procedure definition. + */ +Blocks.prototype.getProcedureParamNames = function (name) { + for (var id in this._blocks) { + var block = this._blocks[id]; + if ((block.opcode == 'procedures_defnoreturn' || + block.opcode == 'procedures_defreturn') && + block.mutation.proccode == name) { + return JSON.parse(block.mutation.argumentnames); + } + } + return null; +}; + +// --------------------------------------------------------------------- + +/** + * Create event listener for blocks. Handles validation and serves as a generic + * adapter between the blocks and the runtime interface. + * @param {Object} e Blockly "block" event + * @param {?Runtime} opt_runtime Optional runtime to forward click events to. + */ + +Blocks.prototype.blocklyListen = function (e, opt_runtime) { + // Validate event + if (typeof e !== 'object') return; + if (typeof e.blockId !== 'string') return; + + // UI event: clicked scripts toggle in the runtime. + if (e.element === 'stackclick') { + if (opt_runtime) { + opt_runtime.toggleScript(e.blockId); + } + return; + } + + // Block create/update/destroy + switch (e.type) { + case 'create': + var newBlocks = adapter(e); + // A create event can create many blocks. Add them all. + for (var i = 0; i < newBlocks.length; i++) { + this.createBlock(newBlocks[i]); + } + break; + case 'change': + this.changeBlock({ + id: e.blockId, + element: e.element, + name: e.name, + value: e.newValue + }); + break; + case 'move': + this.moveBlock({ + id: e.blockId, + oldParent: e.oldParentId, + oldInput: e.oldInputName, + newParent: e.newParentId, + newInput: e.newInputName, + newCoordinate: e.newCoordinate + }); + break; + case 'delete': + // Don't accept delete events for missing blocks, + // or shadow blocks being obscured. + if (!this._blocks.hasOwnProperty(e.blockId) || + this._blocks[e.blockId].shadow) { + return; + } + // Inform any runtime to forget about glows on this script. + if (opt_runtime && this._blocks[e.blockId].topLevel) { + opt_runtime.quietGlow(e.blockId); + } + this.deleteBlock({ + id: e.blockId + }); + break; + } +}; + +// --------------------------------------------------------------------- + +/** + * Block management: create blocks and scripts from a `create` event + * @param {!Object} block Blockly create event to be processed + */ +Blocks.prototype.createBlock = function (block) { + // Does the block already exist? + // Could happen, e.g., for an unobscured shadow. + if (this._blocks.hasOwnProperty(block.id)) { + return; + } + // Create new block. + this._blocks[block.id] = block; + // Push block id to scripts array. + // Blocks are added as a top-level stack if they are marked as a top-block + // (if they were top-level XML in the event). + if (block.topLevel) { + this._addScript(block.id); + } +}; + +/** + * Block management: change block field values + * @param {!Object} args Blockly change event to be processed + */ +Blocks.prototype.changeBlock = function (args) { + // Validate + if (args.element !== 'field' && args.element !== 'mutation') return; + if (typeof this._blocks[args.id] === 'undefined') return; + + if (args.element == 'field') { + // Update block value + if (!this._blocks[args.id].fields[args.name]) return; + this._blocks[args.id].fields[args.name].value = args.value; + } else if (args.element == 'mutation') { + this._blocks[args.id].mutation = mutationAdapter(args.value); + } +}; + +/** + * Block management: move blocks from parent to parent + * @param {!Object} e Blockly move event to be processed + */ +Blocks.prototype.moveBlock = function (e) { + if (!this._blocks.hasOwnProperty(e.id)) { + return; + } + + // Move coordinate changes. + if (e.newCoordinate) { + this._blocks[e.id].x = e.newCoordinate.x; + this._blocks[e.id].y = e.newCoordinate.y; + } + + // Remove from any old parent. + if (e.oldParent !== undefined) { + var oldParent = this._blocks[e.oldParent]; + if (e.oldInput !== undefined && + oldParent.inputs[e.oldInput].block === e.id) { + // This block was connected to the old parent's input. + oldParent.inputs[e.oldInput].block = null; + } else if (oldParent.next === e.id) { + // This block was connected to the old parent's next connection. + oldParent.next = null; + } + this._blocks[e.id].parent = null; + } + + // Has the block become a top-level block? + if (e.newParent === undefined) { + this._addScript(e.id); + } else { + // Remove script, if one exists. + this._deleteScript(e.id); + // Otherwise, try to connect it in its new place. + if (e.newInput !== undefined) { + // Moved to the new parent's input. + // Don't obscure the shadow block. + var oldShadow = null; + if (this._blocks[e.newParent].inputs.hasOwnProperty(e.newInput)) { + oldShadow = this._blocks[e.newParent].inputs[e.newInput].shadow; + } + this._blocks[e.newParent].inputs[e.newInput] = { + name: e.newInput, + block: e.id, + shadow: oldShadow + }; + } else { + // Moved to the new parent's next connection. + this._blocks[e.newParent].next = e.id; + } + this._blocks[e.id].parent = e.newParent; + } +}; + +/** + * Block management: delete blocks and their associated scripts. + * @param {!Object} e Blockly delete event to be processed. + */ +Blocks.prototype.deleteBlock = function (e) { + // @todo In runtime, stop threads running on this script. + + // Get block + var block = this._blocks[e.id]; + + // Delete children + if (block.next !== null) { + this.deleteBlock({id: block.next}); + } + + // Delete inputs (including branches) + for (var input in block.inputs) { + // If it's null, the block in this input moved away. + if (block.inputs[input].block !== null) { + this.deleteBlock({id: block.inputs[input].block}); + } + // Delete obscured shadow blocks. + if (block.inputs[input].shadow !== null && + block.inputs[input].shadow !== block.inputs[input].block) { + this.deleteBlock({id: block.inputs[input].shadow}); + } + } + + // Delete any script starting with this block. + this._deleteScript(e.id); + + // Delete block itself. + delete this._blocks[e.id]; +}; + +// --------------------------------------------------------------------- + +/** + * Encode all of `this._blocks` as an XML string usable + * by a Blockly/scratch-blocks workspace. + * @return {string} String of XML representing this object's blocks. + */ +Blocks.prototype.toXML = function () { + var xmlString = '<xml xmlns="http://www.w3.org/1999/xhtml">'; + for (var i = 0; i < this._scripts.length; i++) { + xmlString += this.blockToXML(this._scripts[i]); + } + return xmlString + '</xml>'; +}; + +/** + * Recursively encode an individual block and its children + * into a Blockly/scratch-blocks XML string. + * @param {!string} blockId ID of block to encode. + * @return {string} String of XML representing this block and any children. + */ +Blocks.prototype.blockToXML = function (blockId) { + var block = this._blocks[blockId]; + // Encode properties of this block. + var tagName = (block.shadow) ? 'shadow' : 'block'; + var xy = (block.topLevel) ? + ' x="' + block.x +'"' + ' y="' + block.y +'"' : + ''; + var xmlString = ''; + xmlString += '<' + tagName + + ' id="' + block.id + '"' + + ' type="' + block.opcode + '"' + + xy + + '>'; + // Add any mutation. Must come before inputs. + if (block.mutation) { + xmlString += this.mutationToXML(block.mutation); + } + // Add any inputs on this block. + for (var input in block.inputs) { + var blockInput = block.inputs[input]; + // Only encode a value tag if the value input is occupied. + if (blockInput.block || blockInput.shadow) { + xmlString += '<value name="' + blockInput.name + '">'; + if (blockInput.block) { + xmlString += this.blockToXML(blockInput.block); + } + if (blockInput.shadow && blockInput.shadow != blockInput.block) { + // Obscured shadow. + xmlString += this.blockToXML(blockInput.shadow); + } + xmlString += '</value>'; + } + } + // Add any fields on this block. + for (var field in block.fields) { + var blockField = block.fields[field]; + var value = blockField.value; + if (typeof value === 'string') { + value = xmlEscape(blockField.value); + } + xmlString += '<field name="' + blockField.name + '">' + + value + '</field>'; + } + // Add blocks connected to the next connection. + if (block.next) { + xmlString += '<next>' + this.blockToXML(block.next) + '</next>'; + } + xmlString += '</' + tagName + '>'; + return xmlString; +}; + +/** + * Recursively encode a mutation object to XML. + * @param {!Object} mutation Object representing a mutation. + * @return {string} XML string representing a mutation. + */ +Blocks.prototype.mutationToXML = function (mutation) { + var mutationString = '<' + mutation.tagName; + for (var prop in mutation) { + if (prop == 'children' || prop == 'tagName') continue; + var mutationValue = (typeof mutation[prop] === 'string') ? + xmlEscape(mutation[prop]) : mutation[prop]; + mutationString += ' ' + prop + '="' + mutationValue + '"'; + } + mutationString += '>'; + for (var i = 0; i < mutation.children.length; i++) { + mutationString += this.mutationToXML(mutation.children[i]); + } + mutationString += '</' + mutation.tagName + '>'; + return mutationString; +}; + +// --------------------------------------------------------------------- + +/** + * Helper to add a stack to `this._scripts`. + * @param {?string} topBlockId ID of block that starts the script. + */ +Blocks.prototype._addScript = function (topBlockId) { + var i = this._scripts.indexOf(topBlockId); + if (i > -1) return; // Already in scripts. + this._scripts.push(topBlockId); + // Update `topLevel` property on the top block. + this._blocks[topBlockId].topLevel = true; +}; + +/** + * Helper to remove a script from `this._scripts`. + * @param {?string} topBlockId ID of block that starts the script. + */ +Blocks.prototype._deleteScript = function (topBlockId) { + var i = this._scripts.indexOf(topBlockId); + if (i > -1) this._scripts.splice(i, 1); + // Update `topLevel` property on the top block. + if (this._blocks[topBlockId]) this._blocks[topBlockId].topLevel = false; +}; + +module.exports = Blocks; diff --git a/src/engine/execute.js b/src/engine/execute.js new file mode 100644 index 000000000..6ef0599de --- /dev/null +++ b/src/engine/execute.js @@ -0,0 +1,248 @@ +var Thread = require('./thread'); + +/** + * Utility function to determine if a value is a Promise. + * @param {*} value Value to check for a Promise. + * @return {Boolean} True if the value appears to be a Promise. + */ +var isPromise = function (value) { + return value && value.then && typeof value.then === 'function'; +}; + +/** + * Execute a block. + * @param {!Sequencer} sequencer Which sequencer is executing. + * @param {!Thread} thread Thread which to read and execute. + */ +var execute = function (sequencer, thread) { + var runtime = sequencer.runtime; + var target = thread.target; + + // Current block to execute is the one on the top of the stack. + var currentBlockId = thread.peekStack(); + var currentStackFrame = thread.peekStackFrame(); + + // Check where the block lives: target blocks or flyout blocks. + var targetHasBlock = ( + typeof target.blocks.getBlock(currentBlockId) !== 'undefined' + ); + var flyoutHasBlock = ( + typeof runtime.flyoutBlocks.getBlock(currentBlockId) !== 'undefined' + ); + + // Stop if block or target no longer exists. + if (!target || (!targetHasBlock && !flyoutHasBlock)) { + // No block found: stop the thread; script no longer exists. + sequencer.retireThread(thread); + return; + } + + // Query info about the block. + var blockContainer = null; + if (targetHasBlock) { + blockContainer = target.blocks; + } else { + blockContainer = runtime.flyoutBlocks; + } + var opcode = blockContainer.getOpcode(currentBlockId); + var fields = blockContainer.getFields(currentBlockId); + var inputs = blockContainer.getInputs(currentBlockId); + var blockFunction = runtime.getOpcodeFunction(opcode); + var isHat = runtime.getIsHat(opcode); + + + if (!opcode) { + console.warn('Could not get opcode for block: ' + currentBlockId); + return; + } + + /** + * Handle any reported value from the primitive, either directly returned + * or after a promise resolves. + * @param {*} resolvedValue Value eventually returned from the primitive. + */ + var handleReport = function (resolvedValue) { + thread.pushReportedValue(resolvedValue); + if (isHat) { + // Hat predicate was evaluated. + if (runtime.getIsEdgeActivatedHat(opcode)) { + // If this is an edge-activated hat, only proceed if + // the value is true and used to be false. + var oldEdgeValue = runtime.updateEdgeActivatedValue( + currentBlockId, + resolvedValue + ); + var edgeWasActivated = !oldEdgeValue && resolvedValue; + if (!edgeWasActivated) { + sequencer.retireThread(thread); + } + } else { + // Not an edge-activated hat: retire the thread + // if predicate was false. + if (!resolvedValue) { + sequencer.retireThread(thread); + } + } + } else { + // In a non-hat, report the value visually if necessary if + // at the top of the thread stack. + if (typeof resolvedValue !== 'undefined' && thread.atStackTop()) { + runtime.visualReport(currentBlockId, resolvedValue); + } + // Finished any yields. + thread.status = Thread.STATUS_RUNNING; + } + }; + + // Hats and single-field shadows are implemented slightly differently + // from regular blocks. + // For hats: if they have an associated block function, + // it's treated as a predicate; if not, execution will proceed as a no-op. + // For single-field shadows: If the block has a single field, and no inputs, + // immediately return the value of the field. + if (!blockFunction) { + if (isHat) { + // Skip through the block (hat with no predicate). + return; + } else { + if (Object.keys(fields).length == 1 && + Object.keys(inputs).length == 0) { + // One field and no inputs - treat as arg. + for (var fieldKey in fields) { // One iteration. + handleReport(fields[fieldKey].value); + } + } else { + console.warn('Could not get implementation for opcode: ' + + opcode); + } + thread.requestScriptGlowInFrame = true; + return; + } + } + + // Generate values for arguments (inputs). + var argValues = {}; + + // Add all fields on this block to the argValues. + for (var fieldName in fields) { + argValues[fieldName] = fields[fieldName].value; + } + + // Recursively evaluate input blocks. + for (var inputName in inputs) { + var input = inputs[inputName]; + var inputBlockId = input.block; + // Is there no value for this input waiting in the stack frame? + if (typeof currentStackFrame.reported[inputName] === 'undefined' + && inputBlockId) { + // If there's not, we need to evaluate the block. + // Push to the stack to evaluate the reporter block. + thread.pushStack(inputBlockId); + // Save name of input for `Thread.pushReportedValue`. + currentStackFrame.waitingReporter = inputName; + // Actually execute the block. + execute(sequencer, thread); + if (thread.status === Thread.STATUS_PROMISE_WAIT) { + return; + } else { + // Execution returned immediately, + // and presumably a value was reported, so pop the stack. + currentStackFrame.waitingReporter = null; + thread.popStack(); + } + } + argValues[inputName] = currentStackFrame.reported[inputName]; + } + + // Add any mutation to args (e.g., for procedures). + var mutation = blockContainer.getMutation(currentBlockId); + if (mutation) { + argValues.mutation = mutation; + } + + // If we've gotten this far, all of the input blocks are evaluated, + // and `argValues` is fully populated. So, execute the block primitive. + // First, clear `currentStackFrame.reported`, so any subsequent execution + // (e.g., on return from a branch) gets fresh inputs. + currentStackFrame.reported = {}; + + var primitiveReportedValue = null; + primitiveReportedValue = blockFunction(argValues, { + stackFrame: currentStackFrame.executionContext, + target: target, + yield: function() { + thread.status = Thread.STATUS_YIELD; + }, + startBranch: function (branchNum, isLoop) { + sequencer.stepToBranch(thread, branchNum, isLoop); + }, + stopAll: function () { + runtime.stopAll(); + }, + stopOtherTargetThreads: function() { + runtime.stopForTarget(target, thread); + }, + stopThread: function() { + sequencer.retireThread(thread); + }, + startProcedure: function (procedureCode) { + sequencer.stepToProcedure(thread, procedureCode); + }, + getProcedureParamNames: function (procedureCode) { + return blockContainer.getProcedureParamNames(procedureCode); + }, + pushParam: function (paramName, paramValue) { + thread.pushParam(paramName, paramValue); + }, + getParam: function (paramName) { + return thread.getParam(paramName); + }, + startHats: function(requestedHat, opt_matchFields, opt_target) { + return ( + runtime.startHats(requestedHat, opt_matchFields, opt_target) + ); + }, + ioQuery: function (device, func, args) { + // Find the I/O device and execute the query/function call. + if (runtime.ioDevices[device] && runtime.ioDevices[device][func]) { + var devObject = runtime.ioDevices[device]; + return devObject[func].call(devObject, args); + } + } + }); + + if (typeof primitiveReportedValue === 'undefined') { + // No value reported - potentially a command block. + // Edge-activated hats don't request a glow; all commands do. + thread.requestScriptGlowInFrame = true; + } + + // If it's a promise, wait until promise resolves. + if (isPromise(primitiveReportedValue)) { + if (thread.status === Thread.STATUS_RUNNING) { + // Primitive returned a promise; automatically yield thread. + thread.status = Thread.STATUS_PROMISE_WAIT; + } + // Promise handlers + primitiveReportedValue.then(function(resolvedValue) { + handleReport(resolvedValue); + if (typeof resolvedValue !== 'undefined') { + thread.popStack(); + } else { + var popped = thread.popStack(); + var nextBlockId = thread.target.blocks.getNextBlock(popped); + thread.pushStack(nextBlockId); + } + }, function(rejectionReason) { + // Promise rejected: the primitive had some error. + // Log it and proceed. + console.warn('Primitive rejected promise: ', rejectionReason); + thread.status = Thread.STATUS_RUNNING; + thread.popStack(); + }); + } else if (thread.status === Thread.STATUS_RUNNING) { + handleReport(primitiveReportedValue); + } +}; + +module.exports = execute; diff --git a/src/engine/list.js b/src/engine/list.js new file mode 100644 index 000000000..8ef082cde --- /dev/null +++ b/src/engine/list.js @@ -0,0 +1,16 @@ +/** + * @fileoverview + * Object representing a Scratch list. + */ + + /** + * @param {!string} name Name of the list. + * @param {Array} contents Contents of the list, as an array. + * @constructor + */ +function List (name, contents) { + this.name = name; + this.contents = contents; +} + +module.exports = List; diff --git a/src/engine/mutation-adapter.js b/src/engine/mutation-adapter.js new file mode 100644 index 000000000..12dc123e1 --- /dev/null +++ b/src/engine/mutation-adapter.js @@ -0,0 +1,39 @@ +var html = require('htmlparser2'); + +/** + * Adapter between mutator XML or DOM and block representation which can be + * used by the Scratch runtime. + * @param {(Object|string)} mutation Mutation XML string or DOM. + * @return {Object} Object representing the mutation. + */ +module.exports = function (mutation) { + var mutationParsed; + // Check if the mutation is already parsed; if not, parse it. + if (typeof mutation === 'object') { + mutationParsed = mutation; + } else { + mutationParsed = html.parseDOM(mutation)[0]; + } + return mutatorTagToObject(mutationParsed); +}; + +/** + * Convert a part of a mutation DOM to a mutation VM object, recursively. + * @param {Object} dom DOM object for mutation tag. + * @return {Object} Object representing useful parts of this mutation. + */ +function mutatorTagToObject (dom) { + var obj = Object.create(null); + obj.tagName = dom.name; + obj.children = []; + for (var prop in dom.attribs) { + if (prop == 'xmlns') continue; + obj[prop] = dom.attribs[prop]; + } + for (var i = 0; i < dom.children.length; i++) { + obj.children.push( + mutatorTagToObject(dom.children[i]) + ); + } + return obj; +} diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 0507b96b5..14df35528 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -1,34 +1,37 @@ var EventEmitter = require('events'); var Sequencer = require('./sequencer'); +var Blocks = require('./blocks'); var Thread = require('./thread'); var util = require('util'); +// Virtual I/O devices. +var Clock = require('../io/clock'); +var Keyboard = require('../io/keyboard'); +var Mouse = require('../io/mouse'); + var defaultBlockPackages = { - 'scratch3': require('../blocks/scratch3'), - 'wedo2': require('../blocks/wedo2') + 'scratch3_control': require('../blocks/scratch3_control'), + 'scratch3_event': require('../blocks/scratch3_event'), + 'scratch3_looks': require('../blocks/scratch3_looks'), + 'scratch3_motion': require('../blocks/scratch3_motion'), + 'scratch3_operators': require('../blocks/scratch3_operators'), + 'scratch3_sensing': require('../blocks/scratch3_sensing'), + 'scratch3_data': require('../blocks/scratch3_data'), + 'scratch3_procedures': require('../blocks/scratch3_procedures') }; /** - * Manages blocks, stacks, and the sequencer. + * Manages targets, scripts, and the sequencer. */ function Runtime () { // Bind event emitter EventEmitter.call(this); - // State for the runtime /** - * All blocks in the workspace. - * Keys are block IDs, values are metadata about the block. - * @type {Object.<string, Object>} + * Target management and storage. + * @type {Array.<!Target>} */ - this.blocks = {}; - - /** - * All stacks in the workspace. - * A list of block IDs that represent stacks (first block in stack). - * @type {Array.<String>} - */ - this.stacks = []; + this.targets = []; /** * A list of threads that are currently running in the VM. @@ -40,161 +43,188 @@ function Runtime () { /** @type {!Sequencer} */ this.sequencer = new Sequencer(this); + /** + * Storage container for flyout blocks. + * These will execute on `_editingTarget.` + * @type {!Blocks} + */ + this.flyoutBlocks = new Blocks(); + + /** + * Currently known editing target for the VM. + * @type {?Target} + */ + this._editingTarget = null; + /** * Map to look up a block primitive's implementation function by its opcode. * This is a two-step lookup: package name first, then primitive name. * @type {Object.<string, Function>} */ this._primitives = {}; + + /** + * Map to look up hat blocks' metadata. + * Keys are opcode for hat, values are metadata objects. + * @type {Object.<string, Object>} + */ + this._hats = {}; + + /** + * Currently known values for edge-activated hats. + * Keys are block ID for the hat; values are the currently known values. + * @type {Object.<string, *>} + */ + this._edgeActivatedHatValues = {}; + + /** + * A list of script block IDs that were glowing during the previous frame. + * @type {!Array.<!string>} + */ + this._scriptGlowsPreviousFrame = []; + + /** + * A list of block IDs that were glowing during the previous frame. + * @type {!Array.<!string>} + */ + this._blockGlowsPreviousFrame = []; + + /** + * Currently known number of clones, used to enforce clone limit. + * @type {number} + */ + this._cloneCounter = 0; + + /** + * Whether the project is in "turbo mode." + * @type {Boolean} + */ + this.turboMode = false; + + /** + * Whether the project is in "pause mode." + * @type {Boolean} + */ + this.pauseMode = false; + + /** + * Whether the project is in "compatibility mode" (30 TPS). + * @type {Boolean} + */ + this.compatibilityMode = false; + + /** + * Whether the project is in "single stepping mode." + * @type {Boolean} + */ + this.singleStepping = false; + + /** + * How fast in ms "single stepping mode" should run, in ms. + * Can be updated dynamically. + * @type {!number} + */ + this.singleStepInterval = 1000 / 10; + + /** + * A reference to the current runtime stepping interval, set + * by a `setInterval`. + * @type {!number} + */ + this._steppingInterval = null; + + /** + * Current length of a step. + * Changes as mode switches, and used by the sequencer to calculate + * WORK_TIME. + * @type {!number} + */ + this.currentStepTime = null; + + /** + * Whether any primitive has requested a redraw. + * Affects whether `Sequencer.stepThreads` will yield + * after stepping each thread. + * Reset on every frame. + * @type {boolean} + */ + this.redrawRequested = false; + + // Register all given block packages. this._registerBlockPackages(); + + // Register and initialize "IO devices", containers for processing + // I/O related data. + /** @type {Object.<string, Object>} */ + this.ioDevices = { + 'clock': new Clock(), + 'keyboard': new Keyboard(this), + 'mouse': new Mouse(this) + }; } -/** - * Event name for glowing a stack - * @const {string} - */ -Runtime.STACK_GLOW_ON = 'STACK_GLOW_ON'; - -/** - * Event name for unglowing a stack - * @const {string} - */ -Runtime.STACK_GLOW_OFF = 'STACK_GLOW_OFF'; - -/** - * Event name for glowing a block - * @const {string} - */ -Runtime.BLOCK_GLOW_ON = 'BLOCK_GLOW_ON'; - -/** - * Event name for unglowing a block - * @const {string} - */ -Runtime.BLOCK_GLOW_OFF = 'BLOCK_GLOW_OFF'; - /** * Inherit from EventEmitter */ util.inherits(Runtime, EventEmitter); /** - * How rapidly we try to step threads, in ms. + * Width of the stage, in pixels. + * @const {number} */ -Runtime.THREAD_STEP_INTERVAL = 1000 / 30; +Runtime.STAGE_WIDTH = 480; /** - * Block management: create blocks and stacks from a `create` event - * @param {!Object} block Blockly create event to be processed + * Height of the stage, in pixels. + * @const {number} */ -Runtime.prototype.createBlock = function (block, opt_isFlyoutBlock) { - // Create new block - this.blocks[block.id] = block; - - // Walk each field and add any shadow blocks - // @todo Expand this to cover vertical / nested blocks - for (var i in block.fields) { - var shadows = block.fields[i].blocks; - for (var y in shadows) { - var shadow = shadows[y]; - this.blocks[shadow.id] = shadow; - } - } - - // Push block id to stacks array. New blocks are always a stack even if only - // momentary. If the new block is added to an existing stack this stack will - // be removed by the `moveBlock` method below. - if (!opt_isFlyoutBlock) { - this.stacks.push(block.id); - } -}; +Runtime.STAGE_HEIGHT = 360; /** - * Block management: change block field values - * @param {!Object} args Blockly change event to be processed + * Event name for glowing a script. + * @const {string} */ -Runtime.prototype.changeBlock = function (args) { - // Validate - if (args.element !== 'field') return; - if (typeof this.blocks[args.id] === 'undefined') return; - if (typeof this.blocks[args.id].fields[args.name] === 'undefined') return; - - // Update block value - this.blocks[args.id].fields[args.name].value = args.value; -}; +Runtime.SCRIPT_GLOW_ON = 'STACK_GLOW_ON'; /** - * Block management: move blocks from parent to parent - * @param {!Object} e Blockly move event to be processed + * Event name for unglowing a script. + * @const {string} */ -Runtime.prototype.moveBlock = function (e) { - var _this = this; - - // Block was removed from parent - if (e.newParent === undefined && e.oldParent !== undefined) { - // Add stack - _this.stacks.push(e.id); - - // Update old parent - if (e.oldField === undefined) { - _this.blocks[e.oldParent].next = null; - } else { - delete _this.blocks[e.oldParent].fields[e.oldField]; - } - } else if (e.newParent !== undefined) { - // Block was moved to a new parent - // Either happens because it was previously parentless - // (e.oldParent === undefined) - // or because a block was moved in front of it. - - // Remove stack - _this._deleteStack(e.id); - - // Update new parent - if (e.newField === undefined) { - _this.blocks[e.newParent].next = e.id; - } else { - _this.blocks[e.newParent].fields[e.newField] = { - name: e.newField, - value: e.id, - blocks: {} - }; - } - } -}; +Runtime.SCRIPT_GLOW_OFF = 'STACK_GLOW_OFF'; /** - * Block management: delete blocks and their associated stacks - * @param {!Object} e Blockly delete event to be processed + * Event name for glowing a block. + * @const {string} */ -Runtime.prototype.deleteBlock = function (e) { - // @todo Stop threads running on this stack +Runtime.BLOCK_GLOW_ON = 'BLOCK_GLOW_ON'; - // Get block - var block = this.blocks[e.id]; +/** + * Event name for unglowing a block. + * @const {string} + */ +Runtime.BLOCK_GLOW_OFF = 'BLOCK_GLOW_OFF'; - // Delete children - if (block.next !== null) { - this.deleteBlock({id: block.next}); - } +/** + * Event name for visual value report. + * @const {string} + */ +Runtime.VISUAL_REPORT = 'VISUAL_REPORT'; - // Delete substacks and fields - for (var field in block.fields) { - if (field === 'SUBSTACK') { - this.deleteBlock({id: block.fields[field].value}); - } else { - for (var shadow in block.fields[field].blocks) { - this.deleteBlock({id: shadow}); - } - } - } +/** + * How rapidly we try to step threads by default, in ms. + */ +Runtime.THREAD_STEP_INTERVAL = 1000 / 60; - // Delete stack - this._deleteStack(e.id); +/** + * In compatibility mode, how rapidly we try to step threads, in ms. + */ +Runtime.THREAD_STEP_INTERVAL_COMPATIBILITY = 1000 / 30; - // Delete block - delete this.blocks[e.id]; -}; +/** + * How many clones can be created at a time. + * @const {number} + */ +Runtime.MAX_CLONES = 300; // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- @@ -209,11 +239,23 @@ Runtime.prototype._registerBlockPackages = function () { if (defaultBlockPackages.hasOwnProperty(packageName)) { // @todo pass a different runtime depending on package privilege? var packageObject = new (defaultBlockPackages[packageName])(this); - var packageContents = packageObject.getPrimitives(); - for (var op in packageContents) { - if (packageContents.hasOwnProperty(op)) { - this._primitives[op] = - packageContents[op].bind(packageObject); + // Collect primitives from package. + if (packageObject.getPrimitives) { + var packagePrimitives = packageObject.getPrimitives(); + for (var op in packagePrimitives) { + if (packagePrimitives.hasOwnProperty(op)) { + this._primitives[op] = + packagePrimitives[op].bind(packageObject); + } + } + } + // Collect hat metadata from package. + if (packageObject.getHats) { + var packageHats = packageObject.getHats(); + for (var hatName in packageHats) { + if (packageHats.hasOwnProperty(hatName)) { + this._hats[hatName] = packageHats[hatName]; + } } } } @@ -229,17 +271,67 @@ Runtime.prototype.getOpcodeFunction = function (opcode) { return this._primitives[opcode]; }; +/** + * Return whether an opcode represents a hat block. + * @param {!string} opcode The opcode to look up. + * @return {Boolean} True if the op is known to be a hat. + */ +Runtime.prototype.getIsHat = function (opcode) { + return this._hats.hasOwnProperty(opcode); +}; + +/** + * Return whether an opcode represents an edge-activated hat block. + * @param {!string} opcode The opcode to look up. + * @return {Boolean} True if the op is known to be a edge-activated hat. + */ +Runtime.prototype.getIsEdgeActivatedHat = function (opcode) { + return this._hats.hasOwnProperty(opcode) && + this._hats[opcode].edgeActivated; +}; + +/** + * Update an edge-activated hat block value. + * @param {!string} blockId ID of hat to store value for. + * @param {*} newValue Value to store for edge-activated hat. + * @return {*} The old value for the edge-activated hat. + */ +Runtime.prototype.updateEdgeActivatedValue = function (blockId, newValue) { + var oldValue = this._edgeActivatedHatValues[blockId]; + this._edgeActivatedHatValues[blockId] = newValue; + return oldValue; +}; + +/** + * Clear all edge-activaed hat values. + */ +Runtime.prototype.clearEdgeActivatedValues = function () { + this._edgeActivatedHatValues = {}; +}; + +/** + * Attach the renderer + * @param {!RenderWebGL} renderer The renderer to attach + */ +Runtime.prototype.attachRenderer = function (renderer) { + this.renderer = renderer; +}; + // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- /** * Create a thread and push it to the list of threads. - * @param {!string} id ID of block that starts the stack + * @param {!string} id ID of block that starts the stack. + * @param {!Target} target Target to run thread on. + * @return {!Thread} The newly created thread. */ -Runtime.prototype._pushThread = function (id) { - this.emit(Runtime.STACK_GLOW_ON, id); +Runtime.prototype._pushThread = function (id, target) { var thread = new Thread(id); + thread.target = target; + thread.pushStack(id); this.threads.push(thread); + return thread; }; /** @@ -247,79 +339,201 @@ Runtime.prototype._pushThread = function (id) { * @param {?Thread} thread Thread object to remove from actives */ Runtime.prototype._removeThread = function (thread) { + // Inform sequencer to stop executing that thread. + this.sequencer.retireThread(thread); + // Remove from the list. var i = this.threads.indexOf(thread); if (i > -1) { - this.emit(Runtime.STACK_GLOW_OFF, thread.topBlock); this.threads.splice(i, 1); } }; /** - * Toggle a stack - * @param {!string} stackId ID of block that starts the stack + * Return whether a thread is currently active/running. + * @param {?Thread} thread Thread object to check. + * @return {Boolean} True if the thread is active/running. */ -Runtime.prototype.toggleStack = function (stackId) { - // Remove any existing thread +Runtime.prototype.isActiveThread = function (thread) { + return this.threads.indexOf(thread) > -1; +}; + +/** + * Toggle a script. + * @param {!string} topBlockId ID of block that starts the script. + */ +Runtime.prototype.toggleScript = function (topBlockId) { + // Remove any existing thread. for (var i = 0; i < this.threads.length; i++) { - if (this.threads[i].topBlock == stackId) { + if (this.threads[i].topBlock == topBlockId) { this._removeThread(this.threads[i]); return; } } - // Otherwise add it - this._pushThread(stackId); + // Otherwise add it. + this._pushThread(topBlockId, this._editingTarget); }; /** - * Green flag, which stops currently running threads - * and adds all top-level stacks that start with the green flag + * Run a function `f` for all scripts in a workspace. + * `f` will be called with two parameters: + * - the top block ID of the script. + * - the target that owns the script. + * @param {!Function} f Function to call for each script. + * @param {Target=} opt_target Optionally, a target to restrict to. */ -Runtime.prototype.greenFlag = function () { - // Remove all existing threads - for (var i = 0; i < this.threads.length; i++) { - this._removeThread(this.threads[i]); +Runtime.prototype.allScriptsDo = function (f, opt_target) { + var targets = this.targets; + if (opt_target) { + targets = [opt_target]; } - // Add all top stacks with green flag - for (var j = 0; j < this.stacks.length; j++) { - var topBlock = this.stacks[j]; - if (this.blocks[topBlock].opcode === 'event_whenflagclicked') { - this._pushThread(this.stacks[j]); + for (var t = 0; t < targets.length; t++) { + var target = targets[t]; + var scripts = target.blocks.getScripts(); + for (var j = 0; j < scripts.length; j++) { + var topBlockId = scripts[j]; + f(topBlockId, target); } } }; /** - * Distance sensor hack + * Start all relevant hats. + * @param {!string} requestedHatOpcode Opcode of hats to start. + * @param {Object=} opt_matchFields Optionally, fields to match on the hat. + * @param {Target=} opt_target Optionally, a target to restrict to. + * @return {Array.<Thread>} List of threads started by this function. */ -Runtime.prototype.startDistanceSensors = function () { - // Add all top stacks with distance sensor - for (var j = 0; j < this.stacks.length; j++) { - var topBlock = this.stacks[j]; - if (this.blocks[topBlock].opcode === 'wedo_whendistanceclose') { - var alreadyRunning = false; - for (var k = 0; k < this.threads.length; k++) { - if (this.threads[k].topBlock === topBlock) { - alreadyRunning = true; +Runtime.prototype.startHats = function (requestedHatOpcode, + opt_matchFields, opt_target) { + if (!this._hats.hasOwnProperty(requestedHatOpcode)) { + // No known hat with this opcode. + return; + } + var instance = this; + var newThreads = []; + // Consider all scripts, looking for hats with opcode `requestedHatOpcode`. + this.allScriptsDo(function(topBlockId, target) { + var potentialHatOpcode = target.blocks.getBlock(topBlockId).opcode; + if (potentialHatOpcode !== requestedHatOpcode) { + // Not the right hat. + return; + } + // Match any requested fields. + // For example: ensures that broadcasts match. + // This needs to happen before the block is evaluated + // (i.e., before the predicate can be run) because "broadcast and wait" + // needs to have a precise collection of started threads. + var hatFields = target.blocks.getFields(topBlockId); + if (opt_matchFields) { + for (var matchField in opt_matchFields) { + if (hatFields[matchField].value !== + opt_matchFields[matchField]) { + // Field mismatch. + return; } } - if (!alreadyRunning) { - this._pushThread(this.stacks[j]); + } + // Look up metadata for the relevant hat. + var hatMeta = instance._hats[requestedHatOpcode]; + if (hatMeta.restartExistingThreads) { + // If `restartExistingThreads` is true, we should stop + // any existing threads starting with the top block. + for (var i = 0; i < instance.threads.length; i++) { + if (instance.threads[i].topBlock === topBlockId && + instance.threads[i].target == target) { + instance._removeThread(instance.threads[i]); + } } + } else { + // If `restartExistingThreads` is false, we should + // give up if any threads with the top block are running. + for (var j = 0; j < instance.threads.length; j++) { + if (instance.threads[j].topBlock === topBlockId && + instance.threads[j].target == target) { + // Some thread is already running. + return; + } + } + } + // Start the thread with this top block. + newThreads.push(instance._pushThread(topBlockId, target)); + }, opt_target); + return newThreads; +}; + +/** + * Dispose all targets. Return to clean state. + */ +Runtime.prototype.dispose = function () { + this.stopAll(); + this.targets.map(this.disposeTarget, this); +}; + +/** + * Dispose of a target. + * @param {!Target} disposingTarget Target to dispose of. + */ +Runtime.prototype.disposeTarget = function (disposingTarget) { + this.targets = this.targets.filter(function (target) { + if (disposingTarget !== target) return true; + // Allow target to do dispose actions. + target.dispose(); + // Remove from list of targets. + return false; + }); +}; + +/** + * Stop any threads acting on the target. + * @param {!Target} target Target to stop threads for. + * @param {Thread=} opt_threadException Optional thread to skip. + */ +Runtime.prototype.stopForTarget = function (target, opt_threadException) { + // Stop any threads on the target. + for (var i = 0; i < this.threads.length; i++) { + if (this.threads[i] === opt_threadException) { + continue; + } + if (this.threads[i].target == target) { + this._removeThread(this.threads[i]); } } }; /** - * Stop "everything" + * Start all threads that start with the green flag. + */ +Runtime.prototype.greenFlag = function () { + this.stopAll(); + this.ioDevices.clock.resetProjectTimer(); + this.clearEdgeActivatedValues(); + // Inform all targets of the green flag. + for (var i = 0; i < this.targets.length; i++) { + this.targets[i].onGreenFlag(); + } + this.startHats('event_whenflagclicked'); +}; + +/** + * Stop "everything." */ Runtime.prototype.stopAll = function () { + // Dispose all clones. + var newTargets = []; + for (var i = 0; i < this.targets.length; i++) { + if (this.targets[i].hasOwnProperty('isOriginal') && + !this.targets[i].isOriginal) { + this.targets[i].dispose(); + } else { + newTargets.push(this.targets[i]); + } + } + this.targets = newTargets; + // Dispose all threads. var threadsCopy = this.threads.slice(); while (threadsCopy.length > 0) { - this._removeThread(threadsCopy.pop()); - } - // @todo call stop function in all extensions/packages/WeDo stub - if (window.native) { - window.native.motorStop(); + var poppedThread = threadsCopy.pop(); + this._removeThread(poppedThread); } }; @@ -328,9 +542,182 @@ Runtime.prototype.stopAll = function () { * inactive threads after each iteration. */ Runtime.prototype._step = function () { - var inactiveThreads = this.sequencer.stepThreads(this.threads); - for (var i = 0; i < inactiveThreads.length; i++) { - this._removeThread(inactiveThreads[i]); + if (this.pauseMode) { + // Don't do any execution while in pause mode. + return; + } + // Find all edge-activated hats, and add them to threads to be evaluated. + for (var hatType in this._hats) { + var hat = this._hats[hatType]; + if (hat.edgeActivated) { + this.startHats(hatType); + } + } + this.redrawRequested = false; + var inactiveThreads = this.sequencer.stepThreads(); + this._updateGlows(inactiveThreads); +}; + +/** + * Set the current editing target known by the runtime. + * @param {!Target} editingTarget New editing target. + */ +Runtime.prototype.setEditingTarget = function (editingTarget) { + this._editingTarget = editingTarget; + // Script glows must be cleared. + this._scriptGlowsPreviousFrame = []; + this._updateGlows(); +}; + +/** + * Set whether we are in pause mode. + * @param {boolean} pauseModeOn True iff in pause mode. + */ +Runtime.prototype.setPauseMode = function (pauseModeOn) { + // Inform the project clock/timer to pause/resume its time. + if (this.ioDevices.clock) { + if (pauseModeOn && !this.pauseMode) { + this.ioDevices.clock.pause(); + } + if (!pauseModeOn && this.pauseMode) { + this.ioDevices.clock.resume(); + } + } + this.pauseMode = pauseModeOn; +}; + +/** + * Set whether we are in 30 TPS compatibility mode. + * @param {boolean} compatibilityModeOn True iff in compatibility mode. + */ +Runtime.prototype.setCompatibilityMode = function (compatibilityModeOn) { + this.compatibilityMode = compatibilityModeOn; + if (this._steppingInterval) { + self.clearInterval(this._steppingInterval); + this.start(); + } +}; + +/** + * Set whether we are in single-stepping mode. + * @param {boolean} singleSteppingOn True iff in single-stepping mode. + */ +Runtime.prototype.setSingleSteppingMode = function (singleSteppingOn) { + this.singleStepping = singleSteppingOn; + if (this._steppingInterval) { + self.clearInterval(this._steppingInterval); + this.start(); + } +}; + +/** + * Set the speed during single-stepping mode. + * @param {number} speed Interval length to step threads, in ms. + */ +Runtime.prototype.setSingleSteppingSpeed = function (speed) { + this.singleStepInterval = 1000 / speed; + if (this._steppingInterval) { + self.clearInterval(this._steppingInterval); + this.start(); + } +}; + +/** + * Emit glows/glow clears for blocks and scripts after a single tick. + * Looks at `this.threads` and notices which have turned on/off new glows. + * @param {Array.<Thread>=} opt_extraThreads Optional list of inactive threads. + */ +Runtime.prototype._updateGlows = function (opt_extraThreads) { + var searchThreads = []; + searchThreads.push.apply(searchThreads, this.threads); + if (opt_extraThreads) { + searchThreads.push.apply(searchThreads, opt_extraThreads); + } + // Set of scripts that request a glow this frame. + var requestedGlowsThisFrame = []; + var requestedBlockGlowsThisFrame = []; + // Final set of scripts glowing during this frame. + var finalScriptGlows = []; + var finalBlockGlows = []; + // Find all scripts that should be glowing. + for (var i = 0; i < searchThreads.length; i++) { + var thread = searchThreads[i]; + var target = thread.target; + if (target == this._editingTarget) { + var blockForThread = thread.blockGlowInFrame; + if (thread.requestScriptGlowInFrame) { + var script = target.blocks.getTopLevelScript(blockForThread); + if (!script) { + // Attempt to find in flyout blocks. + script = this.flyoutBlocks.getTopLevelScript( + blockForThread + ); + } + if (script) { + requestedGlowsThisFrame.push(script); + } + } + // Only show block glows in single-stepping mode. + if (this.singleStepping && blockForThread) { + requestedBlockGlowsThisFrame.push(blockForThread); + } + } + } + // Compare to previous frame. + for (var j = 0; j < this._scriptGlowsPreviousFrame.length; j++) { + var previousFrameGlow = this._scriptGlowsPreviousFrame[j]; + if (requestedGlowsThisFrame.indexOf(previousFrameGlow) < 0) { + // Glow turned off. + this.glowScript(previousFrameGlow, false); + } else { + // Still glowing. + finalScriptGlows.push(previousFrameGlow); + } + } + for (var k = 0; k < requestedGlowsThisFrame.length; k++) { + var currentFrameGlow = requestedGlowsThisFrame[k]; + if (this._scriptGlowsPreviousFrame.indexOf(currentFrameGlow) < 0) { + // Glow turned on. + this.glowScript(currentFrameGlow, true); + finalScriptGlows.push(currentFrameGlow); + } + } + for (var m = 0; m < this._blockGlowsPreviousFrame.length; m++) { + var previousBlockGlow = this._blockGlowsPreviousFrame[m]; + if (requestedBlockGlowsThisFrame.indexOf(previousBlockGlow) < 0) { + // Glow turned off. + try { + this.glowBlock(previousBlockGlow, false); + } catch (e) { + // Block has been removed. + } + } else { + // Still glowing. + finalBlockGlows.push(previousBlockGlow); + } + } + for (var p = 0; p < requestedBlockGlowsThisFrame.length; p++) { + var currentBlockFrameGlow = requestedBlockGlowsThisFrame[p]; + if (this._blockGlowsPreviousFrame.indexOf(currentBlockFrameGlow) < 0) { + // Glow turned on. + this.glowBlock(currentBlockFrameGlow, true); + finalBlockGlows.push(currentBlockFrameGlow); + } + } + this._scriptGlowsPreviousFrame = finalScriptGlows; + this._blockGlowsPreviousFrame = finalBlockGlows; +}; + +/** + * "Quiet" a script's glow: stop the VM from generating glow/unglow events + * about that script. Use when a script has just been deleted, but we may + * still be tracking glow data about it. + * @param {!string} scriptBlockId Id of top-level block in script to quiet. + */ +Runtime.prototype.quietGlow = function (scriptBlockId) { + var index = this._scriptGlowsPreviousFrame.indexOf(scriptBlockId); + if (index > -1) { + this._scriptGlowsPreviousFrame.splice(index, 1); } }; @@ -348,55 +735,116 @@ Runtime.prototype.glowBlock = function (blockId, isGlowing) { }; /** - * Set up timers to repeatedly step in a browser + * Emit feedback for script glowing. + * @param {?string} topBlockId ID for the top block to update glow + * @param {boolean} isGlowing True to turn on glow; false to turn off. + */ +Runtime.prototype.glowScript = function (topBlockId, isGlowing) { + if (isGlowing) { + this.emit(Runtime.SCRIPT_GLOW_ON, topBlockId); + } else { + this.emit(Runtime.SCRIPT_GLOW_OFF, topBlockId); + } +}; + +/** + * Emit value for reporter to show in the blocks. + * @param {string} blockId ID for the block. + * @param {string} value Value to show associated with the block. + */ +Runtime.prototype.visualReport = function (blockId, value) { + this.emit(Runtime.VISUAL_REPORT, blockId, String(value)); +}; + +/** + * Get a target by its id. + * @param {string} targetId Id of target to find. + * @return {?Target} The target, if found. + */ +Runtime.prototype.getTargetById = function (targetId) { + for (var i = 0; i < this.targets.length; i++) { + var target = this.targets[i]; + if (target.id == targetId) { + return target; + } + } +}; + +/** + * Get the first original (non-clone-block-created) sprite given a name. + * @param {string} spriteName Name of sprite to look for. + * @return {?Target} Target representing a sprite of the given name. + */ +Runtime.prototype.getSpriteTargetByName = function (spriteName) { + for (var i = 0; i < this.targets.length; i++) { + var target = this.targets[i]; + if (target.sprite && target.sprite.name == spriteName) { + return target; + } + } +}; + +/** + * Update the clone counter to track how many clones are created. + * @param {number} changeAmount How many clones have been created/destroyed. + */ +Runtime.prototype.changeCloneCounter = function (changeAmount) { + this._cloneCounter += changeAmount; +}; + +/** + * Return whether there are clones available. + * @return {boolean} True until the number of clones hits Runtime.MAX_CLONES. + */ +Runtime.prototype.clonesAvailable = function () { + return this._cloneCounter < Runtime.MAX_CLONES; +}; + +/** + * Get a target representing the Scratch stage, if one exists. + * @return {?Target} The target, if found. + */ +Runtime.prototype.getTargetForStage = function () { + for (var i = 0; i < this.targets.length; i++) { + var target = this.targets[i]; + if (target.isStage) { + return target; + } + } +}; + +/** + * Tell the runtime to request a redraw. + * Use after a clone/sprite has completed some visible operation on the stage. + */ +Runtime.prototype.requestRedraw = function () { + this.redrawRequested = true; +}; + +/** + * Handle an animation frame from the main thread. + */ +Runtime.prototype.animationFrame = function () { + if (this.renderer) { + // @todo: Only render when this.redrawRequested or clones rendered. + this.renderer.draw(); + } +}; + +/** + * Set up timers to repeatedly step in a browser. */ Runtime.prototype.start = function () { - if (!window.setInterval) return; - window.setInterval(function() { + var interval = Runtime.THREAD_STEP_INTERVAL; + if (this.singleStepping) { + interval = this.singleStepInterval; + } else if (this.compatibilityMode) { + interval = Runtime.THREAD_STEP_INTERVAL_COMPATIBILITY; + } + this.currentStepTime = interval; + this._steppingInterval = self.setInterval(function() { this._step(); - }.bind(this), Runtime.THREAD_STEP_INTERVAL); -}; - -// ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- - -/** - * Helper to remove a stack from `this.stacks` - * @param {?string} id ID of block that starts the stack - */ -Runtime.prototype._deleteStack = function (id) { - var i = this.stacks.indexOf(id); - if (i > -1) this.stacks.splice(i, 1); -}; - -/** - * Helper to get the next block for a particular block - * @param {?string} id ID of block to get the next block for - * @return {?string} ID of next block in the sequence - */ -Runtime.prototype._getNextBlock = function (id) { - if (typeof this.blocks[id] === 'undefined') return null; - return this.blocks[id].next; -}; - -/** - * Helper to get the substack for a particular C-shaped block - * @param {?string} id ID for block to get the substack for - * @return {?string} ID of block in the substack - */ -Runtime.prototype._getSubstack = function (id) { - if (typeof this.blocks[id] === 'undefined') return null; - return this.blocks[id].fields['SUBSTACK']; -}; - -/** - * Helper to get the opcode for a particular block - * @param {?string} id ID of block to query - * @return {?string} the opcode corresponding to that block - */ -Runtime.prototype._getOpcode = function (id) { - if (typeof this.blocks[id] === 'undefined') return null; - return this.blocks[id].opcode; + }.bind(this), interval); }; module.exports = Runtime; diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index f495264c8..182b9ee65 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -1,6 +1,6 @@ var Timer = require('../util/timer'); var Thread = require('./thread'); -var YieldTimers = require('../util/yieldtimers.js'); +var execute = require('./execute.js'); function Sequencer (runtime) { /** @@ -17,225 +17,238 @@ function Sequencer (runtime) { } /** - * The sequencer does as much work as it can within WORK_TIME milliseconds, - * then yields. This is essentially a rate-limiter for blocks. - * In Scratch 2.0, this is set to 75% of the target stage frame-rate (30fps). - * @const {!number} + * Time to run a warp-mode thread, in ms. + * @type {number} */ -Sequencer.WORK_TIME = 10; +Sequencer.WARP_TIME = 500; /** - * Step through all threads in `this.threads`, running them in order. - * @return {Array.<Thread>} All threads which have finished in this iteration. + * Step through all threads in `this.runtime.threads`, running them in order. + * @return {Array.<!Thread>} List of inactive threads after stepping. */ -Sequencer.prototype.stepThreads = function (threads) { - // Start counting toward WORK_TIME +Sequencer.prototype.stepThreads = function () { + // Work time is 75% of the thread stepping interval. + var WORK_TIME = 0.75 * this.runtime.currentStepTime; + // Start counting toward WORK_TIME. this.timer.start(); - // List of threads which have been killed by this step. + // Count of active threads. + var numActiveThreads = Infinity; + // Whether `stepThreads` has run through a full single tick. + var ranFirstTick = false; var inactiveThreads = []; - // If all of the threads are yielding, we should yield. - var numYieldingThreads = 0; - // While there are still threads to run and we are within WORK_TIME, - // continue executing threads. - while (threads.length > 0 && - threads.length > numYieldingThreads && - this.timer.timeElapsed() < Sequencer.WORK_TIME) { - // New threads at the end of the iteration. - var newThreads = []; - // Attempt to run each thread one time - for (var i = 0; i < threads.length; i++) { - var activeThread = threads[i]; - if (activeThread.status === Thread.STATUS_RUNNING) { + // Conditions for continuing to stepping threads: + // 1. We must have threads in the list, and some must be active. + // 2. Time elapsed must be less than WORK_TIME. + // 3. Either turbo mode, or no redraw has been requested by a primitive. + while (this.runtime.threads.length > 0 && + numActiveThreads > 0 && + this.timer.timeElapsed() < WORK_TIME && + (this.runtime.turboMode || !this.runtime.redrawRequested)) { + numActiveThreads = 0; + // Inline copy of the threads, updated on each step. + var threadsCopy = this.runtime.threads.slice(); + // Attempt to run each thread one time. + for (var i = 0; i < threadsCopy.length; i++) { + var activeThread = threadsCopy[i]; + if (activeThread.stack.length === 0 || + activeThread.status === Thread.STATUS_DONE) { + // Finished with this thread. + if (inactiveThreads.indexOf(activeThread) < 0) { + inactiveThreads.push(activeThread); + } + continue; + } + if (activeThread.status === Thread.STATUS_YIELD_TICK && + !ranFirstTick) { + // Clear single-tick yield from the last call of `stepThreads`. + activeThread.status = Thread.STATUS_RUNNING; + } + if (activeThread.status === Thread.STATUS_RUNNING || + activeThread.status === Thread.STATUS_YIELD) { // Normal-mode thread: step. this.stepThread(activeThread); - } else if (activeThread.status === Thread.STATUS_YIELD) { - // Yield-mode thread: check if the time has passed. - YieldTimers.resolve(activeThread.yieldTimerId); - numYieldingThreads++; - } else if (activeThread.status === Thread.STATUS_DONE) { - // Moved to a done state - finish up - activeThread.status = Thread.STATUS_RUNNING; - // @todo Deal with the return value + activeThread.warpTimer = null; } - // First attempt to pop from the stack - if (activeThread.stack.length > 0 && - activeThread.nextBlock === null && - activeThread.status === Thread.STATUS_DONE) { - activeThread.nextBlock = activeThread.stack.pop(); - // Don't pop stack frame - we need the data. - // A new one won't be created when we execute. - if (activeThread.nextBlock !== null) { - activeThread.status === Thread.STATUS_RUNNING; + if (activeThread.status === Thread.STATUS_RUNNING) { + // After stepping, status is still running. + // If we're in single-stepping mode, mark the thread as + // a single-tick yield so it doesn't re-execute + // until the next frame. + if (this.runtime.singleStepping) { + activeThread.status = Thread.STATUS_YIELD_TICK; } - } - if (activeThread.nextBlock === null && - activeThread.status === Thread.STATUS_DONE) { - // Finished with this thread - tell runtime to clean it up. - inactiveThreads.push(activeThread); - } else { - // Keep this thead in the loop. - newThreads.push(activeThread); + numActiveThreads++; } } - // Effectively filters out threads that have stopped. - threads = newThreads; + // We successfully ticked once. Prevents running STATUS_YIELD_TICK + // threads on the next tick. + ranFirstTick = true; } + // Filter inactive threads from `this.runtime.threads`. + this.runtime.threads = this.runtime.threads.filter(function(thread) { + if (inactiveThreads.indexOf(thread) > -1) { + return false; + } + return true; + }); return inactiveThreads; }; /** - * Step the requested thread - * @param {!Thread} thread Thread object to step + * Step the requested thread for as long as necessary. + * @param {!Thread} thread Thread object to step. */ Sequencer.prototype.stepThread = function (thread) { - // Save the yield timer ID, in case a primitive makes a new one - // @todo hack - perhaps patch this to allow more than one timer per - // primitive, for example... - var oldYieldTimerId = YieldTimers.timerId; + var currentBlockId = thread.peekStack(); + if (!currentBlockId) { + // A "null block" - empty branch. + thread.popStack(); + } + while (thread.peekStack()) { + var isWarpMode = thread.peekStackFrame().warpMode; + if (isWarpMode && !thread.warpTimer) { + // Initialize warp-mode timer if it hasn't been already. + // This will start counting the thread toward `Sequencer.WARP_TIME`. + thread.warpTimer = new Timer(); + thread.warpTimer.start(); + } + // Execute the current block. + // Save the current block ID to notice if we did control flow. + currentBlockId = thread.peekStack(); + execute(this, thread); + thread.blockGlowInFrame = currentBlockId; + // If the thread has yielded or is waiting, yield to other threads. + if (thread.status === Thread.STATUS_YIELD) { + // Mark as running for next iteration. + thread.status = Thread.STATUS_RUNNING; + // In warp mode, yielded blocks are re-executed immediately. + if (isWarpMode && + thread.warpTimer.timeElapsed() <= Sequencer.WARP_TIME) { + continue; + } + return; + } else if (thread.status === Thread.STATUS_PROMISE_WAIT) { + // A promise was returned by the primitive. Yield the thread + // until the promise resolves. Promise resolution should reset + // thread.status to Thread.STATUS_RUNNING. + return; + } + // If no control flow has happened, switch to next block. + if (thread.peekStack() === currentBlockId) { + thread.goToNextBlock(); + } + // If no next block has been found at this point, look on the stack. + while (!thread.peekStack()) { + thread.popStack(); + if (thread.stack.length === 0) { + // No more stack to run! + thread.status = Thread.STATUS_DONE; + return; + } + if (thread.peekStackFrame().isLoop) { + // The current level of the stack is marked as a loop. + // Return to yield for the frame/tick in general. + // Unless we're in warp mode - then only return if the + // warp timer is up. + if (!isWarpMode || + thread.warpTimer.timeElapsed() > Sequencer.WARP_TIME) { + // Don't do anything to the stack, since loops need + // to be re-executed. + return; + } else { + // Don't go to the next block for this level of the stack, + // since loops need to be re-executed. + continue; + } + } else if (thread.peekStackFrame().waitingReporter) { + // This level of the stack was waiting for a value. + // This means a reporter has just returned - so don't go + // to the next block for this level of the stack. + return; + } + // Get next block of existing block on the stack. + thread.goToNextBlock(); + } + // In single-stepping mode, force `stepThread` to only run one block + // at a time. + if (this.runtime.singleStepping) { + return; + } + } +}; - // Save the current block and set the nextBlock. - // If the primitive would like to do control flow, - // it can overwrite nextBlock. - var currentBlock = thread.nextBlock; - if (!currentBlock || !this.runtime.blocks[currentBlock]) { - thread.status = Thread.STATUS_DONE; +/** + * Step a thread into a block's branch. + * @param {!Thread} thread Thread object to step to branch. + * @param {Number} branchNum Which branch to step to (i.e., 1, 2). + * @param {Boolean} isLoop Whether this block is a loop. + */ +Sequencer.prototype.stepToBranch = function (thread, branchNum, isLoop) { + if (!branchNum) { + branchNum = 1; + } + var currentBlockId = thread.peekStack(); + var branchId = thread.target.blocks.getBranch( + currentBlockId, + branchNum + ); + thread.peekStackFrame().isLoop = isLoop; + if (branchId) { + // Push branch ID to the thread's stack. + thread.pushStack(branchId); + } else { + thread.pushStack(null); + } +}; + +/** + * Step a procedure. + * @param {!Thread} thread Thread object to step to procedure. + * @param {!string} procedureCode Procedure code of procedure to step to. + */ +Sequencer.prototype.stepToProcedure = function (thread, procedureCode) { + var definition = thread.target.blocks.getProcedureDefinition(procedureCode); + if (!definition) { return; } - thread.nextBlock = this.runtime._getNextBlock(currentBlock); - - var opcode = this.runtime._getOpcode(currentBlock); - - // Push the current block to the stack - thread.stack.push(currentBlock); - // Push an empty stack frame, if we need one. - // Might not, if we just popped the stack. - if (thread.stack.length > thread.stackFrames.length) { - thread.stackFrames.push({}); - } - var currentStackFrame = thread.stackFrames[thread.stackFrames.length - 1]; - - /** - * A callback for the primitive to indicate its thread should yield. - * @type {Function} - */ - var threadYieldCallback = function () { + // Check if the call is recursive. + // If so, set the thread to yield after pushing. + var isRecursive = thread.isRecursiveCall(procedureCode); + // To step to a procedure, we put its definition on the stack. + // Execution for the thread will proceed through the definition hat + // and on to the main definition of the procedure. + // When that set of blocks finishes executing, it will be popped + // from the stack by the sequencer, returning control to the caller. + thread.pushStack(definition); + // In known warp-mode threads, only yield when time is up. + if (thread.peekStackFrame().warpMode && + thread.warpTimer.timeElapsed() > Sequencer.WARP_TIME) { thread.status = Thread.STATUS_YIELD; - }; - - /** - * A callback for the primitive to indicate its thread is finished - * @type {Function} - */ - var instance = this; - var threadDoneCallback = function () { - thread.status = Thread.STATUS_DONE; - // Refresh nextBlock in case it has changed during a yield. - thread.nextBlock = instance.runtime._getNextBlock(currentBlock); - // Pop the stack and stack frame - thread.stack.pop(); - thread.stackFrames.pop(); - }; - - /** - * A callback for the primitive to start hats. - * @todo very hacked... - */ - var startHats = function(callback) { - for (var i = 0; i < instance.runtime.stacks.length; i++) { - var stack = instance.runtime.stacks[i]; - var stackBlock = instance.runtime.blocks[stack]; - var result = callback(stackBlock); - if (result) { - // Check if the stack is already running - var stackRunning = false; - - for (var j = 0; j < instance.runtime.threads.length; j++) { - if (instance.runtime.threads[j].topBlock == stack) { - stackRunning = true; - break; - } - } - if (!stackRunning) { - instance.runtime._pushThread(stack); - } - } - } - }; - - /** - * Record whether we have switched stack, - * to avoid proceeding the thread automatically. - * @type {boolean} - */ - var switchedStack = false; - /** - * A callback for a primitive to start a substack. - * @type {Function} - */ - var threadStartSubstack = function () { - // Set nextBlock to the start of the substack - var substack = instance.runtime._getSubstack(currentBlock); - if (substack && substack.value) { - thread.nextBlock = substack.value; + } else { + // Look for warp-mode flag on definition, and set the thread + // to warp-mode if needed. + var definitionBlock = thread.target.blocks.getBlock(definition); + var doWarp = definitionBlock.mutation.warp; + if (doWarp) { + thread.peekStackFrame().warpMode = true; } else { - thread.nextBlock = null; - } - switchedStack = true; - }; - - // @todo extreme hack to get the single argument value for prototype - var argValues = []; - var blockInputs = this.runtime.blocks[currentBlock].fields; - for (var bi in blockInputs) { - var outer = blockInputs[bi]; - for (var b in outer.blocks) { - var block = outer.blocks[b]; - var fields = block.fields; - for (var f in fields) { - var field = fields[f]; - argValues.push(field.value); - } - } - } - - if (!opcode) { - console.warn('Could not get opcode for block: ' + currentBlock); - } - else { - var blockFunction = this.runtime.getOpcodeFunction(opcode); - if (!blockFunction) { - console.warn('Could not get implementation for opcode: ' + opcode); - } - else { - try { - // @todo deal with the return value - blockFunction(argValues, { - yield: threadYieldCallback, - done: threadDoneCallback, - timeout: YieldTimers.timeout, - stackFrame: currentStackFrame, - startSubstack: threadStartSubstack, - startHats: startHats - }); - } - catch(e) { - console.error( - 'Exception calling block function for opcode: ' + - opcode + '\n' + e); - } finally { - // Update if the thread has set a yield timer ID - // @todo hack - if (YieldTimers.timerId > oldYieldTimerId) { - thread.yieldTimerId = YieldTimers.timerId; - } - if (thread.status === Thread.STATUS_RUNNING && !switchedStack) { - // Thread executed without yielding - move to done - threadDoneCallback(); - } + // In normal-mode threads, yield any time we have a recursive call. + if (isRecursive) { + thread.status = Thread.STATUS_YIELD; } } } +}; +/** + * Retire a thread in the middle, without considering further blocks. + * @param {!Thread} thread Thread object to retire. + */ +Sequencer.prototype.retireThread = function (thread) { + thread.stack = []; + thread.stackFrame = []; + thread.requestScriptGlowInFrame = false; + thread.status = Thread.STATUS_DONE; }; module.exports = Sequencer; diff --git a/src/engine/target.js b/src/engine/target.js new file mode 100644 index 000000000..d5a59b47a --- /dev/null +++ b/src/engine/target.js @@ -0,0 +1,116 @@ +var Blocks = require('./blocks'); +var Variable = require('../engine/variable'); +var List = require('../engine/list'); +var uid = require('../util/uid'); + +/** + * @fileoverview + * A Target is an abstract "code-running" object for the Scratch VM. + * Examples include sprites/clones or potentially physical-world devices. + */ + +/** + * @param {?Blocks} blocks Blocks instance for the blocks owned by this target. + * @constructor + */ +function Target (blocks) { + if (!blocks) { + blocks = new Blocks(this); + } + /** + * A unique ID for this target. + * @type {string} + */ + this.id = uid(); + /** + * Blocks run as code for this target. + * @type {!Blocks} + */ + this.blocks = blocks; + /** + * Dictionary of variables and their values for this target. + * Key is the variable name. + * @type {Object.<string,*>} + */ + this.variables = {}; + /** + * Dictionary of lists and their contents for this target. + * Key is the list name. + * @type {Object.<string,*>} + */ + this.lists = {}; +} + +/** + * Called when the project receives a "green flag." + * @abstract + */ +Target.prototype.onGreenFlag = function () {}; + +/** + * Return a human-readable name for this target. + * Target implementations should override this. + * @abstract + * @returns {string} Human-readable name for the target. + */ +Target.prototype.getName = function () { + return this.id; +}; + +/** + * Look up a variable object, and create it if one doesn't exist. + * Search begins for local variables; then look for globals. + * @param {!string} name Name of the variable. + * @return {!Variable} Variable object. + */ +Target.prototype.lookupOrCreateVariable = function (name) { + // If we have a local copy, return it. + if (this.variables.hasOwnProperty(name)) { + return this.variables[name]; + } + // If the stage has a global copy, return it. + if (this.runtime && !this.isStage) { + var stage = this.runtime.getTargetForStage(); + if (stage.variables.hasOwnProperty(name)) { + return stage.variables[name]; + } + } + // No variable with this name exists - create it locally. + var newVariable = new Variable(name, 0, false); + this.variables[name] = newVariable; + return newVariable; +}; + +/** +* Look up a list object for this target, and create it if one doesn't exist. +* Search begins for local lists; then look for globals. +* @param {!string} name Name of the list. +* @return {!List} List object. + */ +Target.prototype.lookupOrCreateList = function (name) { + // If we have a local copy, return it. + if (this.lists.hasOwnProperty(name)) { + return this.lists[name]; + } + // If the stage has a global copy, return it. + if (this.runtime && !this.isStage) { + var stage = this.runtime.getTargetForStage(); + if (stage.lists.hasOwnProperty(name)) { + return stage.lists[name]; + } + } + // No list with this name exists - create it locally. + var newList = new List(name, []); + this.lists[name] = newList; + return newList; +}; + +/** + * Call to destroy a target. + * @abstract + */ +Target.prototype.dispose = function () { + +}; + +module.exports = Target; diff --git a/src/engine/thread.js b/src/engine/thread.js index 07ceaca35..9aeb559f3 100644 --- a/src/engine/thread.js +++ b/src/engine/thread.js @@ -9,11 +9,7 @@ function Thread (firstBlock) { * @type {!string} */ this.topBlock = firstBlock; - /** - * ID of next block that the thread will execute, or null if none. - * @type {?string} - */ - this.nextBlock = firstBlock; + /** * Stack for the thread. When the sequencer enters a control structure, * the block is pushed onto the stack so we know where to exit. @@ -34,32 +30,208 @@ function Thread (firstBlock) { this.status = 0; /* Thread.STATUS_RUNNING */ /** - * Yield timer ID (for checking when the thread should unyield). - * @type {number} + * Target of this thread. + * @type {?Target} */ - this.yieldTimerId = -1; + this.target = null; + + /** + * Whether the thread requests its script to glow during this frame. + * @type {boolean} + */ + this.requestScriptGlowInFrame = false; + + /** + * Which block ID should glow during this frame, if any. + * @type {?string} + */ + this.blockGlowInFrame = null; + + /** + * A timer for when the thread enters warp mode. + * Substitutes the sequencer's count toward WORK_TIME on a per-thread basis. + * @type {?Timer} + */ + this.warpTimer = null; } /** * Thread status for initialized or running thread. - * Threads are in this state when the primitive is called for the first time. + * This is the default state for a thread - execution should run normally, + * stepping from block to block. * @const */ Thread.STATUS_RUNNING = 0; /** - * Thread status for a yielded thread. - * Threads are in this state when a primitive has yielded. + * Threads are in this state when a primitive is waiting on a promise; + * execution is paused until the promise changes thread status. * @const */ -Thread.STATUS_YIELD = 1; +Thread.STATUS_PROMISE_WAIT = 1; + +/** + * Thread status for yield. + * @const + */ +Thread.STATUS_YIELD = 2; + +/** + * Thread status for a single-tick yield. This will be cleared when the + * thread is resumed. + * @const + */ +Thread.STATUS_YIELD_TICK = 3; /** * Thread status for a finished/done thread. - * Thread is moved to this state when the interpreter - * can proceed with execution. + * Thread is in this state when there are no more blocks to execute. * @const */ -Thread.STATUS_DONE = 2; +Thread.STATUS_DONE = 4; + +/** + * Push stack and update stack frames appropriately. + * @param {string} blockId Block ID to push to stack. + */ +Thread.prototype.pushStack = function (blockId) { + this.stack.push(blockId); + // Push an empty stack frame, if we need one. + // Might not, if we just popped the stack. + if (this.stack.length > this.stackFrames.length) { + // Copy warp mode from any higher level. + var warpMode = false; + if (this.stackFrames[this.stackFrames.length - 1]) { + warpMode = this.stackFrames[this.stackFrames.length - 1].warpMode; + } + this.stackFrames.push({ + isLoop: false, // Whether this level of the stack is a loop. + warpMode: warpMode, // Whether this level is in warp mode. + reported: {}, // Collects reported input values. + waitingReporter: null, // Name of waiting reporter. + params: {}, // Procedure parameters. + executionContext: {} // A context passed to block implementations. + }); + } +}; + +/** + * Pop last block on the stack and its stack frame. + * @return {string} Block ID popped from the stack. + */ +Thread.prototype.popStack = function () { + this.stackFrames.pop(); + return this.stack.pop(); +}; + +/** + * Get top stack item. + * @return {?string} Block ID on top of stack. + */ +Thread.prototype.peekStack = function () { + return this.stack[this.stack.length - 1]; +}; + + +/** + * Get top stack frame. + * @return {?Object} Last stack frame stored on this thread. + */ +Thread.prototype.peekStackFrame = function () { + return this.stackFrames[this.stackFrames.length - 1]; +}; + +/** + * Get stack frame above the current top. + * @return {?Object} Second to last stack frame stored on this thread. + */ +Thread.prototype.peekParentStackFrame = function () { + return this.stackFrames[this.stackFrames.length - 2]; +}; + +/** + * Push a reported value to the parent of the current stack frame. + * @param {*} value Reported value to push. + */ +Thread.prototype.pushReportedValue = function (value) { + var parentStackFrame = this.peekParentStackFrame(); + if (parentStackFrame) { + var waitingReporter = parentStackFrame.waitingReporter; + parentStackFrame.reported[waitingReporter] = value; + } +}; + +/** + * Add a parameter to the stack frame. + * Use when calling a procedure with parameter values. + * @param {!string} paramName Name of parameter. + * @param {*} value Value to set for parameter. + */ +Thread.prototype.pushParam = function (paramName, value) { + var stackFrame = this.peekStackFrame(); + stackFrame.params[paramName] = value; +}; + +/** + * Get a parameter at the lowest possible level of the stack. + * @param {!string} paramName Name of parameter. + * @return {*} value Value for parameter. + */ +Thread.prototype.getParam = function (paramName) { + for (var i = this.stackFrames.length - 1; i >= 0; i--) { + var frame = this.stackFrames[i]; + if (frame.params.hasOwnProperty(paramName)) { + return frame.params[paramName]; + } + } + return null; +}; + +/** + * Whether the current execution of a thread is at the top of the stack. + * @return {Boolean} True if execution is at top of the stack. + */ +Thread.prototype.atStackTop = function () { + return this.peekStack() === this.topBlock; +}; + + +/** + * Switch the thread to the next block at the current level of the stack. + * For example, this is used in a standard sequence of blocks, + * where execution proceeds from one block to the next. + */ +Thread.prototype.goToNextBlock = function () { + var nextBlockId = this.target.blocks.getNextBlock(this.peekStack()); + // Copy warp mode to next block. + var warpMode = this.peekStackFrame().warpMode; + // The current block is on the stack - pop it and push the next. + // Note that this could push `null` - that is handled by the sequencer. + this.popStack(); + this.pushStack(nextBlockId); + if (this.peekStackFrame()) { + this.peekStackFrame().warpMode = warpMode; + } +}; + +/** + * Attempt to determine whether a procedure call is recursive, + * by examining the stack. + * @param {!string} procedureCode Procedure code of procedure being called. + * @return {boolean} True if the call appears recursive. + */ +Thread.prototype.isRecursiveCall = function (procedureCode) { + var callCount = 5; // Max number of enclosing procedure calls to examine. + var sp = this.stack.length - 1; + for (var i = sp - 1; i >= 0; i--) { + var block = this.target.blocks.getBlock(this.stack[i]); + if (block.opcode == 'procedures_callnoreturn' && + block.mutation.proccode == procedureCode) { + return true; + } + if (--callCount < 0) return false; + } + return false; +}; module.exports = Thread; diff --git a/src/engine/variable.js b/src/engine/variable.js new file mode 100644 index 000000000..4e5e5e6e3 --- /dev/null +++ b/src/engine/variable.js @@ -0,0 +1,18 @@ +/** + * @fileoverview + * Object representing a Scratch variable. + */ + +/** + * @param {!string} name Name of the variable. + * @param {(string|Number)} value Value of the variable. + * @param {boolean} isCloud Whether the variable is stored in the cloud. + * @constructor + */ +function Variable (name, value, isCloud) { + this.name = name; + this.value = value; + this.isCloud = isCloud; +} + +module.exports = Variable; diff --git a/src/import/sb2import.js b/src/import/sb2import.js new file mode 100644 index 000000000..b97144d20 --- /dev/null +++ b/src/import/sb2import.js @@ -0,0 +1,418 @@ +/** + * @fileoverview + * Partial implementation of an SB2 JSON importer. + * Parses provided JSON and then generates all needed + * scratch-vm runtime structures. + */ + +var Blocks = require('../engine/blocks'); +var Clone = require('../sprites/clone'); +var Sprite = require('../sprites/sprite'); +var Color = require('../util/color.js'); +var uid = require('../util/uid'); +var specMap = require('./sb2specmap'); +var Variable = require('../engine/variable'); +var List = require('../engine/list'); + +/** + * Top-level handler. Parse provided JSON, + * and process the top-level object (the stage object). + * @param {!string} json SB2-format JSON to load. + * @param {!Runtime} runtime Runtime object to load all structures into. + */ +function sb2import (json, runtime) { + parseScratchObject( + JSON.parse(json), + runtime, + true + ); +} + +/** + * Parse a single "Scratch object" and create all its in-memory VM objects. + * @param {!Object} object From-JSON "Scratch object:" sprite, stage, watcher. + * @param {!Runtime} runtime Runtime object to load all structures into. + * @param {boolean} topLevel Whether this is the top-level object (stage). + */ +function parseScratchObject (object, runtime, topLevel) { + if (!object.hasOwnProperty('objName')) { + // Watcher/monitor - skip this object until those are implemented in VM. + // @todo + return; + } + // Blocks container for this object. + var blocks = new Blocks(); + // @todo: For now, load all Scratch objects (stage/sprites) as a Sprite. + var sprite = new Sprite(blocks, runtime); + // Sprite/stage name from JSON. + if (object.hasOwnProperty('objName')) { + sprite.name = object.objName; + } + // Costumes from JSON. + if (object.hasOwnProperty('costumes')) { + for (var i = 0; i < object.costumes.length; i++) { + var costume = object.costumes[i]; + // @todo: Make sure all the relevant metadata is being pulled out. + sprite.costumes.push({ + skin: 'https://cdn.assets.scratch.mit.edu/internalapi/asset/' + + costume.baseLayerMD5 + '/get/', + name: costume.costumeName, + bitmapResolution: costume.bitmapResolution, + rotationCenterX: costume.rotationCenterX, + rotationCenterY: costume.rotationCenterY + }); + } + } + // If included, parse any and all scripts/blocks on the object. + if (object.hasOwnProperty('scripts')) { + parseScripts(object.scripts, blocks); + } + // Create the first clone, and load its run-state from JSON. + var target = sprite.createClone(); + // Add it to the runtime's list of targets. + runtime.targets.push(target); + // Load target properties from JSON. + if (object.hasOwnProperty('variables')) { + for (var j = 0; j < object.variables.length; j++) { + var variable = object.variables[j]; + target.variables[variable.name] = new Variable( + variable.name, + variable.value, + variable.isPersistent + ); + } + } + if (object.hasOwnProperty('lists')) { + for (var k = 0; k < object.lists.length; k++) { + var list = object.lists[k]; + // @todo: monitor properties. + target.lists[list.listName] = new List( + list.listName, + list.contents + ); + } + } + if (object.hasOwnProperty('scratchX')) { + target.x = object.scratchX; + } + if (object.hasOwnProperty('scratchY')) { + target.y = object.scratchY; + } + if (object.hasOwnProperty('direction')) { + target.direction = object.direction; + } + if (object.hasOwnProperty('scale')) { + // SB2 stores as 1.0 = 100%; we use % in the VM. + target.size = object.scale * 100; + } + if (object.hasOwnProperty('visible')) { + target.visible = object.visible; + } + if (object.hasOwnProperty('currentCostumeIndex')) { + target.currentCostume = Math.round(object.currentCostumeIndex); + } + if (object.hasOwnProperty('rotationStyle')) { + if (object.rotationStyle == 'none') { + target.rotationStyle = Clone.ROTATION_STYLE_NONE; + } else if (object.rotationStyle == 'leftRight') { + target.rotationStyle = Clone.ROTATION_STYLE_LEFT_RIGHT; + } else if (object.rotationStyle == 'normal') { + target.rotationStyle = Clone.ROTATION_STYLE_ALL_AROUND; + } + } + target.isStage = topLevel; + target.updateAllDrawableProperties(); + // The stage will have child objects; recursively process them. + if (object.children) { + for (var m = 0; m < object.children.length; m++) { + parseScratchObject(object.children[m], runtime, false); + } + } +} + +/** + * Parse a Scratch object's scripts into VM blocks. + * This should only handle top-level scripts that include X, Y coordinates. + * @param {!Object} scripts Scripts object from SB2 JSON. + * @param {!Blocks} blocks Blocks object to load parsed blocks into. + */ +function parseScripts (scripts, blocks) { + for (var i = 0; i < scripts.length; i++) { + var script = scripts[i]; + var scriptX = script[0]; + var scriptY = script[1]; + var blockList = script[2]; + var parsedBlockList = parseBlockList(blockList); + if (parsedBlockList[0]) { + // Adjust script coordinates to account for + // larger block size in scratch-blocks. + // @todo: Determine more precisely the right formulas here. + parsedBlockList[0].x = scriptX * 1.1; + parsedBlockList[0].y = scriptY * 1.1; + parsedBlockList[0].topLevel = true; + parsedBlockList[0].parent = null; + } + // Flatten children and create add the blocks. + var convertedBlocks = flatten(parsedBlockList); + for (var j = 0; j < convertedBlocks.length; j++) { + blocks.createBlock(convertedBlocks[j]); + } + } +} + +/** + * Parse any list of blocks from SB2 JSON into a list of VM-format blocks. + * Could be used to parse a top-level script, + * a list of blocks in a branch (e.g., in forever), + * or a list of blocks in an argument (e.g., move [pick random...]). + * @param {Array.<Object>} blockList SB2 JSON-format block list. + * @return {Array.<Object>} Scratch VM-format block list. + */ +function parseBlockList (blockList) { + var resultingList = []; + var previousBlock = null; // For setting next. + for (var i = 0; i < blockList.length; i++) { + var block = blockList[i]; + var parsedBlock = parseBlock(block); + if (previousBlock) { + parsedBlock.parent = previousBlock.id; + previousBlock.next = parsedBlock.id; + } + previousBlock = parsedBlock; + resultingList.push(parsedBlock); + } + return resultingList; +} + +/** + * Flatten a block tree into a block list. + * Children are temporarily stored on the `block.children` property. + * @param {Array.<Object>} blocks list generated by `parseBlockList`. + * @return {Array.<Object>} Flattened list to be passed to `blocks.createBlock`. + */ +function flatten (blocks) { + var finalBlocks = []; + for (var i = 0; i < blocks.length; i++) { + var block = blocks[i]; + finalBlocks.push(block); + if (block.children) { + finalBlocks = finalBlocks.concat(flatten(block.children)); + } + delete block.children; + } + return finalBlocks; +} + +/** + * Convert a Scratch 2.0 procedure string (e.g., "my_procedure %s %b %n") + * into an argument map. This allows us to provide the expected inputs + * to a mutated procedure call. + * @param {string} procCode Scratch 2.0 procedure string. + * @return {Object} Argument map compatible with those in sb2specmap. + */ +function parseProcedureArgMap (procCode) { + var argMap = [ + {} // First item in list is op string. + ]; + var INPUT_PREFIX = 'input'; + var inputCount = 0; + // Split by %n, %b, %s. + var parts = procCode.split(/(?=[^\\]\%[nbs])/); + for (var i = 0; i < parts.length; i++) { + var part = parts[i].trim(); + if (part.substring(0, 1) == '%') { + var argType = part.substring(1, 2); + var arg = { + type: 'input', + inputName: INPUT_PREFIX + (inputCount++) + }; + if (argType == 'n') { + arg.inputOp = 'math_number'; + } else if (argType == 's') { + arg.inputOp = 'text'; + } + argMap.push(arg); + } + } + return argMap; +} + +/** + * Parse a single SB2 JSON-formatted block and its children. + * @param {!Object} sb2block SB2 JSON-formatted block. + * @return {Object} Scratch VM format block. + */ +function parseBlock (sb2block) { + // First item in block object is the old opcode (e.g., 'forward:'). + var oldOpcode = sb2block[0]; + // Convert the block using the specMap. See sb2specmap.js. + if (!oldOpcode || !specMap[oldOpcode]) { + console.warn('Couldn\'t find SB2 block: ', oldOpcode); + return; + } + var blockMetadata = specMap[oldOpcode]; + // Block skeleton. + var activeBlock = { + id: uid(), // Generate a new block unique ID. + opcode: blockMetadata.opcode, // Converted, e.g. "motion_movesteps". + inputs: {}, // Inputs to this block and the blocks they point to. + fields: {}, // Fields on this block and their values. + next: null, // Next block. + shadow: false, // No shadow blocks in an SB2 by default. + children: [] // Store any generated children, flattened in `flatten`. + }; + // For a procedure call, generate argument map from proc string. + if (oldOpcode == 'call') { + blockMetadata.argMap = parseProcedureArgMap(sb2block[1]); + } + // Look at the expected arguments in `blockMetadata.argMap.` + // The basic problem here is to turn positional SB2 arguments into + // non-positional named Scratch VM arguments. + for (var i = 0; i < blockMetadata.argMap.length; i++) { + var expectedArg = blockMetadata.argMap[i]; + var providedArg = sb2block[i + 1]; // (i = 0 is opcode) + // Whether the input is obscuring a shadow. + var shadowObscured = false; + // Positional argument is an input. + if (expectedArg.type == 'input') { + // Create a new block and input metadata. + var inputUid = uid(); + activeBlock.inputs[expectedArg.inputName] = { + name: expectedArg.inputName, + block: null, + shadow: null + }; + if (typeof providedArg == 'object' && providedArg) { + // Block or block list occupies the input. + var innerBlocks; + if (typeof providedArg[0] == 'object' && providedArg[0]) { + // Block list occupies the input. + innerBlocks = parseBlockList(providedArg); + } else { + // Single block occupies the input. + innerBlocks = [parseBlock(providedArg)]; + } + var previousBlock = null; + for (var j = 0; j < innerBlocks.length; j++) { + if (j == 0) { + innerBlocks[j].parent = activeBlock.id; + } else { + innerBlocks[j].parent = previousBlock; + } + previousBlock = innerBlocks[j].id; + } + // Obscures any shadow. + shadowObscured = true; + activeBlock.inputs[expectedArg.inputName].block = ( + innerBlocks[0].id + ); + activeBlock.children = ( + activeBlock.children.concat(innerBlocks) + ); + } + // Generate a shadow block to occupy the input. + if (!expectedArg.inputOp) { + // No editable shadow input; e.g., for a boolean. + continue; + } + // Each shadow has a field generated for it automatically. + // Value to be filled in the field. + var fieldValue = providedArg; + // Shadows' field names match the input name, except for these: + var fieldName = expectedArg.inputName; + if (expectedArg.inputOp == 'math_number' || + expectedArg.inputOp == 'math_whole_number' || + expectedArg.inputOp == 'math_positive_number' || + expectedArg.inputOp == 'math_integer' || + expectedArg.inputOp == 'math_angle') { + fieldName = 'NUM'; + // Fields are given Scratch 2.0 default values if obscured. + if (shadowObscured) { + fieldValue = 10; + } + } else if (expectedArg.inputOp == 'text') { + fieldName = 'TEXT'; + if (shadowObscured) { + fieldValue = ''; + } + } else if (expectedArg.inputOp == 'colour_picker') { + // Convert SB2 color to hex. + fieldValue = Color.decimalToHex(providedArg); + fieldName = 'COLOUR'; + if (shadowObscured) { + fieldValue = '#990000'; + } + } + var fields = {}; + fields[fieldName] = { + name: fieldName, + value: fieldValue + }; + activeBlock.children.push({ + id: inputUid, + opcode: expectedArg.inputOp, + inputs: {}, + fields: fields, + next: null, + topLevel: false, + parent: activeBlock.id, + shadow: true + }); + activeBlock.inputs[expectedArg.inputName].shadow = inputUid; + // If no block occupying the input, alias to the shadow. + if (!activeBlock.inputs[expectedArg.inputName].block) { + activeBlock.inputs[expectedArg.inputName].block = inputUid; + } + } else if (expectedArg.type == 'field') { + // Add as a field on this block. + activeBlock.fields[expectedArg.fieldName] = { + name: expectedArg.fieldName, + value: providedArg + }; + } + } + // Special cases to generate mutations. + if (oldOpcode == 'stopScripts') { + // Mutation for stop block: if the argument is 'other scripts', + // the block needs a next connection. + if (sb2block[1] == 'other scripts in sprite' || + sb2block[1] == 'other scripts in stage') { + activeBlock.mutation = { + tagName: 'mutation', + hasnext: 'true', + children: [] + }; + } + } else if (oldOpcode == 'procDef') { + // Mutation for procedure definition: + // store all 2.0 proc data. + var procData = sb2block.slice(1); + activeBlock.mutation = { + tagName: 'mutation', + proccode: procData[0], // e.g., "abc %n %b %s" + argumentnames: JSON.stringify(procData[1]), // e.g. ['arg1', 'arg2'] + argumentdefaults: JSON.stringify(procData[2]), // e.g., [1, 'abc'] + warp: procData[3], // Warp mode, e.g., true/false. + children: [] + }; + } else if (oldOpcode == 'call') { + // Mutation for procedure call: + // string for proc code (e.g., "abc %n %b %s"). + activeBlock.mutation = { + tagName: 'mutation', + children: [], + proccode: sb2block[1] + }; + } else if (oldOpcode == 'getParam') { + // Mutation for procedure parameter. + activeBlock.mutation = { + tagName: 'mutation', + children: [], + paramname: sb2block[1], // Name of parameter. + shape: sb2block[2] // Shape - in 2.0, 'r' or 'b'. + }; + } + return activeBlock; +} + +module.exports = sb2import; diff --git a/src/import/sb2specmap.js b/src/import/sb2specmap.js new file mode 100644 index 000000000..1cf0620fc --- /dev/null +++ b/src/import/sb2specmap.js @@ -0,0 +1,1388 @@ +/** + * @fileoverview + * The specMap below handles a few pieces of "translation" work between + * the SB2 JSON format and the data we need to run a project + * in the Scratch 3.0 VM. + * Notably: + * - Map 2.0 and 1.4 opcodes (forward:) into 3.0-format (motion_movesteps). + * - Map ordered, unnamed args to unordered, named inputs and fields. + * Keep this up-to-date as 3.0 blocks are renamed, changed, etc. + * Originally this was generated largely by a hand-guided scripting process. + * The relevant data lives here: + * https://github.com/LLK/scratch-flash/blob/master/src/Specs.as + * (for the old opcode and argument order). + * and here: + * https://github.com/LLK/scratch-blocks/tree/develop/blocks_vertical + * (for the new opcodes and argument names). + * and here: + * https://github.com/LLK/scratch-blocks/blob/develop/tests/ + * (for the shadow blocks created for each block). + * I started with the `commands` array in Specs.as, and discarded irrelevant + * properties. By hand, I matched the opcode name to the 3.0 opcode. + * Finally, I filled in the expected arguments as below. + */ +var specMap = { + 'forward:':{ + 'opcode':'motion_movesteps', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'STEPS' + } + ] + }, + 'turnRight:':{ + 'opcode':'motion_turnright', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'DEGREES' + } + ] + }, + 'turnLeft:':{ + 'opcode':'motion_turnleft', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'DEGREES' + } + ] + }, + 'heading:':{ + 'opcode':'motion_pointindirection', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_angle', + 'inputName':'DIRECTION' + } + ] + }, + 'pointTowards:':{ + 'opcode':'motion_pointtowards', + 'argMap':[ + { + 'type':'input', + 'inputOp':'motion_pointtowards_menu', + 'inputName':'TOWARDS' + } + ] + }, + 'gotoX:y:':{ + 'opcode':'motion_gotoxy', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'X' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'Y' + } + ] + }, + 'gotoSpriteOrMouse:':{ + 'opcode':'motion_goto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'motion_goto_menu', + 'inputName':'TO' + } + ] + }, + 'glideSecs:toX:y:elapsed:from:':{ + 'opcode':'motion_glidesecstoxy', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'SECS' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'X' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'Y' + } + ] + }, + 'changeXposBy:':{ + 'opcode':'motion_changexby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'DX' + } + ] + }, + 'xpos:':{ + 'opcode':'motion_setx', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'X' + } + ] + }, + 'changeYposBy:':{ + 'opcode':'motion_changeyby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'DY' + } + ] + }, + 'ypos:':{ + 'opcode':'motion_sety', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'Y' + } + ] + }, + 'bounceOffEdge':{ + 'opcode':'motion_ifonedgebounce', + 'argMap':[ + ] + }, + 'setRotationStyle':{ + 'opcode':'motion_setrotationstyle', + 'argMap':[ + { + 'type':'input', + 'inputOp':'motion_setrotationstyle_menu', + 'inputName':'STYLE' + } + ] + }, + 'xpos':{ + 'opcode':'motion_xposition', + 'argMap':[ + ] + }, + 'ypos':{ + 'opcode':'motion_yposition', + 'argMap':[ + ] + }, + 'heading':{ + 'opcode':'motion_direction', + 'argMap':[ + ] + }, + 'say:duration:elapsed:from:':{ + 'opcode':'looks_sayforsecs', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'MESSAGE' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'SECS' + } + ] + }, + 'say:':{ + 'opcode':'looks_say', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'MESSAGE' + } + ] + }, + 'think:duration:elapsed:from:':{ + 'opcode':'looks_thinkforsecs', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'MESSAGE' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'SECS' + } + ] + }, + 'think:':{ + 'opcode':'looks_think', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'MESSAGE' + } + ] + }, + 'show':{ + 'opcode':'looks_show', + 'argMap':[ + ] + }, + 'hide':{ + 'opcode':'looks_hide', + 'argMap':[ + ] + }, + 'lookLike:':{ + 'opcode':'looks_switchcostumeto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'looks_costume', + 'inputName':'COSTUME' + } + ] + }, + 'nextCostume':{ + 'opcode':'looks_nextcostume', + 'argMap':[ + ] + }, + 'startScene':{ + 'opcode':'looks_switchbackdropto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'looks_backdrops', + 'inputName':'BACKDROP' + } + ] + }, + 'changeGraphicEffect:by:':{ + 'opcode':'looks_changeeffectby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'looks_effectmenu', + 'inputName':'EFFECT' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'CHANGE' + } + ] + }, + 'setGraphicEffect:to:':{ + 'opcode':'looks_seteffectto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'looks_effectmenu', + 'inputName':'EFFECT' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'VALUE' + } + ] + }, + 'filterReset':{ + 'opcode':'looks_cleargraphiceffects', + 'argMap':[ + ] + }, + 'changeSizeBy:':{ + 'opcode':'looks_changesizeby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'CHANGE' + } + ] + }, + 'setSizeTo:':{ + 'opcode':'looks_setsizeto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'SIZE' + } + ] + }, + 'comeToFront':{ + 'opcode':'looks_gotofront', + 'argMap':[ + ] + }, + 'goBackByLayers:':{ + 'opcode':'looks_gobacklayers', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_integer', + 'inputName':'NUM' + } + ] + }, + 'costumeIndex':{ + 'opcode':'looks_costumeorder', + 'argMap':[ + ] + }, + 'sceneName':{ + 'opcode':'looks_backdropname', + 'argMap':[ + ] + }, + 'scale':{ + 'opcode':'looks_size', + 'argMap':[ + ] + }, + 'startSceneAndWait':{ + 'opcode':'looks_switchbackdroptoandwait', + 'argMap':[ + { + 'type':'input', + 'inputOp':'looks_backdrops', + 'inputName':'BACKDROP' + } + ] + }, + 'nextScene':{ + 'opcode':'looks_nextbackdrop', + 'argMap':[ + ] + }, + 'backgroundIndex':{ + 'opcode':'looks_backdroporder', + 'argMap':[ + ] + }, + 'playSound:':{ + 'opcode':'sound_play', + 'argMap':[ + { + 'type':'input', + 'inputOp':'sound_sounds_option', + 'inputName':'SOUND_MENU' + } + ] + }, + 'doPlaySoundAndWait':{ + 'opcode':'sound_playuntildone', + 'argMap':[ + { + 'type':'input', + 'inputOp':'sound_sounds_option', + 'inputName':'SOUND_MENU' + } + ] + }, + 'stopAllSounds':{ + 'opcode':'sound_stopallsounds', + 'argMap':[ + ] + }, + 'playDrum':{ + 'opcode':'sound_playdrumforbeats', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'DRUMTYPE' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'BEATS' + } + ] + }, + 'rest:elapsed:from:':{ + 'opcode':'sound_restforbeats', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'BEATS' + } + ] + }, + 'noteOn:duration:elapsed:from:':{ + 'opcode':'sound_playnoteforbeats', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NOTE' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'BEATS' + } + ] + }, + 'instrument:':{ + 'opcode':'sound_setinstrumentto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'INSTRUMENT' + } + ] + }, + 'changeVolumeBy:':{ + 'opcode':'sound_changevolumeby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'VOLUME' + } + ] + }, + 'setVolumeTo:':{ + 'opcode':'sound_setvolumeto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'VOLUME' + } + ] + }, + 'volume':{ + 'opcode':'sound_volume', + 'argMap':[ + ] + }, + 'changeTempoBy:':{ + 'opcode':'sound_changetempoby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'TEMPO' + } + ] + }, + 'setTempoTo:':{ + 'opcode':'sound_settempotobpm', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'TEMPO' + } + ] + }, + 'tempo':{ + 'opcode':'sound_tempo', + 'argMap':[ + ] + }, + 'clearPenTrails':{ + 'opcode':'pen_clear', + 'argMap':[ + ] + }, + 'stampCostume':{ + 'opcode':'pen_stamp', + 'argMap':[ + ] + }, + 'putPenDown':{ + 'opcode':'pen_pendown', + 'argMap':[ + ] + }, + 'putPenUp':{ + 'opcode':'pen_penup', + 'argMap':[ + ] + }, + 'penColor:':{ + 'opcode':'pen_setpencolortocolor', + 'argMap':[ + { + 'type':'input', + 'inputOp':'colour_picker', + 'inputName':'COLOR' + } + ] + }, + 'changePenHueBy:':{ + 'opcode':'pen_changepencolorby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'COLOR' + } + ] + }, + 'setPenHueTo:':{ + 'opcode':'pen_setpencolortonum', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'COLOR' + } + ] + }, + 'changePenShadeBy:':{ + 'opcode':'pen_changepenshadeby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'SHADE' + } + ] + }, + 'setPenShadeTo:':{ + 'opcode':'pen_changepenshadeby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'SHADE' + } + ] + }, + 'changePenSizeBy:':{ + 'opcode':'pen_changepensizeby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'SIZE' + } + ] + }, + 'penSize:':{ + 'opcode':'pen_setpensizeto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'SIZE' + } + ] + }, + 'whenGreenFlag':{ + 'opcode':'event_whenflagclicked', + 'argMap':[ + ] + }, + 'whenKeyPressed':{ + 'opcode':'event_whenkeypressed', + 'argMap':[ + { + 'type':'field', + 'fieldName':'KEY_OPTION' + } + ] + }, + 'whenClicked':{ + 'opcode':'event_whenthisspriteclicked', + 'argMap':[ + ] + }, + 'whenSceneStarts':{ + 'opcode':'event_whenbackdropswitchesto', + 'argMap':[ + { + 'type':'field', + 'fieldName':'BACKDROP' + } + ] + }, + 'whenSensorGreaterThan':{ + 'opcode':'event_whengreaterthan', + 'argMap':[ + { + 'type':'field', + 'fieldName':'WHENGREATERTHANMENU' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'VALUE' + } + ] + }, + 'whenIReceive':{ + 'opcode':'event_whenbroadcastreceived', + 'argMap':[ + { + 'type':'field', + 'fieldName':'BROADCAST_OPTION' + } + ] + }, + 'broadcast:':{ + 'opcode':'event_broadcast', + 'argMap':[ + { + 'type':'input', + 'inputOp':'event_broadcast_menu', + 'inputName':'BROADCAST_OPTION' + } + ] + }, + 'doBroadcastAndWait':{ + 'opcode':'event_broadcastandwait', + 'argMap':[ + { + 'type':'input', + 'inputOp':'event_broadcast_menu', + 'inputName':'BROADCAST_OPTION' + } + ] + }, + 'wait:elapsed:from:':{ + 'opcode':'control_wait', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_positive_number', + 'inputName':'DURATION' + } + ] + }, + 'doRepeat':{ + 'opcode':'control_repeat', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_whole_number', + 'inputName':'TIMES' + }, + { + 'type':'input', + 'inputName': 'SUBSTACK' + } + ] + }, + 'doForever':{ + 'opcode':'control_forever', + 'argMap':[ + { + 'type':'input', + 'inputName':'SUBSTACK' + } + ] + }, + 'doIf':{ + 'opcode':'control_if', + 'argMap':[ + { + 'type':'input', + 'inputName':'CONDITION' + }, + { + 'type':'input', + 'inputName':'SUBSTACK' + } + ] + }, + 'doIfElse':{ + 'opcode':'control_if_else', + 'argMap':[ + { + 'type':'input', + 'inputName':'CONDITION' + }, + { + 'type':'input', + 'inputName':'SUBSTACK' + }, + { + 'type':'input', + 'inputName':'SUBSTACK2' + } + ] + }, + 'doWaitUntil':{ + 'opcode':'control_wait_until', + 'argMap':[ + { + 'type':'input', + 'inputName':'CONDITION' + } + ] + }, + 'doUntil':{ + 'opcode':'control_repeat_until', + 'argMap':[ + { + 'type':'input', + 'inputName':'CONDITION' + }, + { + 'type':'input', + 'inputName':'SUBSTACK' + } + ] + }, + 'stopScripts':{ + 'opcode':'control_stop', + 'argMap':[ + { + 'type':'field', + 'fieldName':'STOP_OPTION' + } + ] + }, + 'whenCloned':{ + 'opcode':'control_start_as_clone', + 'argMap':[ + ] + }, + 'createCloneOf':{ + 'opcode':'control_create_clone_of', + 'argMap':[ + { + 'type':'input', + 'inputOp':'control_create_clone_of_menu', + 'inputName':'CLONE_OPTION' + } + ] + }, + 'deleteClone':{ + 'opcode':'control_delete_this_clone', + 'argMap':[ + ] + }, + 'touching:':{ + 'opcode':'sensing_touchingobject', + 'argMap':[ + { + 'type':'input', + 'inputOp':'sensing_touchingobjectmenu', + 'inputName':'TOUCHINGOBJECTMENU' + } + ] + }, + 'touchingColor:':{ + 'opcode':'sensing_touchingcolor', + 'argMap':[ + { + 'type':'input', + 'inputOp':'colour_picker', + 'inputName':'COLOR' + } + ] + }, + 'color:sees:':{ + 'opcode':'sensing_coloristouchingcolor', + 'argMap':[ + { + 'type':'input', + 'inputOp':'colour_picker', + 'inputName':'COLOR' + }, + { + 'type':'input', + 'inputOp':'colour_picker', + 'inputName':'COLOR2' + } + ] + }, + 'distanceTo:':{ + 'opcode':'sensing_distanceto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'sensing_distancetomenu', + 'inputName':'DISTANCETOMENU' + } + ] + }, + 'doAsk':{ + 'opcode':'sensing_askandwait', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'QUESTION' + } + ] + }, + 'answer':{ + 'opcode':'sensing_answer', + 'argMap':[ + ] + }, + 'keyPressed:':{ + 'opcode':'sensing_keypressed', + 'argMap':[ + { + 'type':'input', + 'inputOp':'sensing_keyoptions', + 'inputName':'KEY_OPTION' + } + ] + }, + 'mousePressed':{ + 'opcode':'sensing_mousedown', + 'argMap':[ + ] + }, + 'mouseX':{ + 'opcode':'sensing_mousex', + 'argMap':[ + ] + }, + 'mouseY':{ + 'opcode':'sensing_mousey', + 'argMap':[ + ] + }, + 'soundLevel':{ + 'opcode':'sensing_loudness', + 'argMap':[ + ] + }, + 'senseVideoMotion':{ + 'opcode':'sensing_videoon', + 'argMap':[ + { + 'type':'input', + 'inputOp':'sensing_videoonmenuone', + 'inputName':'VIDEOONMENU1' + }, + { + 'type':'input', + 'inputOp':'sensing_videoonmenutwo', + 'inputName':'VIDEOONMENU2' + } + ] + }, + 'setVideoState':{ + 'opcode':'sensing_videotoggle', + 'argMap':[ + { + 'type':'input', + 'inputOp':'sensing_videotogglemenu', + 'inputName':'VIDEOTOGGLEMENU' + } + ] + }, + 'setVideoTransparency':{ + 'opcode':'sensing_setvideotransparency', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'TRANSPARENCY' + } + ] + }, + 'timer':{ + 'opcode':'sensing_timer', + 'argMap':[ + ] + }, + 'timerReset':{ + 'opcode':'sensing_resettimer', + 'argMap':[ + ] + }, + 'getAttribute:of:':{ + 'opcode':'sensing_of', + 'argMap':[ + { + 'type':'input', + 'inputOp':'sensing_of_property_menu', + 'inputName':'PROPERTY' + }, + { + 'type':'input', + 'inputOp':'sensing_of_object_menu', + 'inputName':'OBJECT' + } + ] + }, + 'timeAndDate':{ + 'opcode':'sensing_current', + 'argMap':[ + { + 'type':'input', + 'inputOp':'sensing_currentmenu', + 'inputName':'CURRENTMENU' + } + ] + }, + 'timestamp':{ + 'opcode':'sensing_dayssince2000', + 'argMap':[ + ] + }, + 'getUserName':{ + 'opcode':'sensing_username', + 'argMap':[ + ] + }, + '+':{ + 'opcode':'operator_add', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM1' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM2' + } + ] + }, + '-':{ + 'opcode':'operator_subtract', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM1' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM2' + } + ] + }, + '*':{ + 'opcode':'operator_multiply', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM1' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM2' + } + ] + }, + '/':{ + 'opcode':'operator_divide', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM1' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM2' + } + ] + }, + 'randomFrom:to:':{ + 'opcode':'operator_random', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'FROM' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'TO' + } + ] + }, + '<':{ + 'opcode':'operator_lt', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'OPERAND1' + }, + { + 'type':'input', + 'inputOp':'text', + 'inputName':'OPERAND2' + } + ] + }, + '=':{ + 'opcode':'operator_equals', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'OPERAND1' + }, + { + 'type':'input', + 'inputOp':'text', + 'inputName':'OPERAND2' + } + ] + }, + '>':{ + 'opcode':'operator_gt', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'OPERAND1' + }, + { + 'type':'input', + 'inputOp':'text', + 'inputName':'OPERAND2' + } + ] + }, + '&':{ + 'opcode':'operator_and', + 'argMap':[ + { + 'type':'input', + 'inputName':'OPERAND1' + }, + { + 'type':'input', + 'inputName':'OPERAND2' + } + ] + }, + '|':{ + 'opcode':'operator_or', + 'argMap':[ + { + 'type':'input', + 'inputName':'OPERAND1' + }, + { + 'type':'input', + 'inputName':'OPERAND2' + } + ] + }, + 'not':{ + 'opcode':'operator_not', + 'argMap':[ + { + 'type':'input', + 'inputName':'OPERAND' + } + ] + }, + 'concatenate:with:':{ + 'opcode':'operator_join', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'STRING1' + }, + { + 'type':'input', + 'inputOp':'text', + 'inputName':'STRING2' + } + ] + }, + 'letter:of:':{ + 'opcode':'operator_letter_of', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_whole_number', + 'inputName':'LETTER' + }, + { + 'type':'input', + 'inputOp':'text', + 'inputName':'STRING' + } + ] + }, + 'stringLength:':{ + 'opcode':'operator_length', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'STRING' + } + ] + }, + '%':{ + 'opcode':'operator_mod', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM1' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM2' + } + ] + }, + 'rounded':{ + 'opcode':'operator_round', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM' + } + ] + }, + 'computeFunction:of:':{ + 'opcode':'operator_mathop', + 'argMap':[ + { + 'type':'input', + 'inputOp':'operator_mathop_menu', + 'inputName':'OPERATOR' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'NUM' + } + ] + }, + 'readVariable':{ + 'opcode':'data_variable', + 'argMap':[ + { + 'type':'input', + 'inputOp':'data_variablemenu', + 'inputName':'VARIABLE' + } + ] + }, + 'setVar:to:':{ + 'opcode':'data_setvariableto', + 'argMap':[ + { + 'type':'input', + 'inputOp':'data_variablemenu', + 'inputName':'VARIABLE' + }, + { + 'type':'input', + 'inputOp':'text', + 'inputName':'VALUE' + } + ] + }, + 'changeVar:by:':{ + 'opcode':'data_changevariableby', + 'argMap':[ + { + 'type':'input', + 'inputOp':'data_variablemenu', + 'inputName':'VARIABLE' + }, + { + 'type':'input', + 'inputOp':'math_number', + 'inputName':'VALUE' + } + ] + }, + 'showVariable:':{ + 'opcode':'data_showvariable', + 'argMap':[ + { + 'type':'input', + 'inputOp':'data_variablemenu', + 'inputName':'VARIABLE' + } + ] + }, + 'hideVariable:':{ + 'opcode':'data_hidevariable', + 'argMap':[ + { + 'type':'input', + 'inputOp':'data_variablemenu', + 'inputName':'VARIABLE' + } + ] + }, + 'contentsOfList:':{ + 'opcode':'data_list', + 'argMap':[ + { + 'type':'field', + 'fieldName':'LIST' + } + ] + }, + 'append:toList:':{ + 'opcode':'data_addtolist', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'ITEM' + }, + { + 'type':'field', + 'fieldName':'LIST' + } + ] + }, + 'deleteLine:ofList:':{ + 'opcode':'data_deleteoflist', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_integer', + 'inputName':'INDEX' + }, + { + 'type':'field', + 'fieldName':'LIST' + } + ] + }, + 'insert:at:ofList:':{ + 'opcode':'data_insertatlist', + 'argMap':[ + { + 'type':'input', + 'inputOp':'text', + 'inputName':'ITEM' + }, + { + 'type':'input', + 'inputOp':'math_integer', + 'inputName':'INDEX' + }, + { + 'type':'field', + 'fieldName':'LIST' + } + ] + }, + 'setLine:ofList:to:':{ + 'opcode':'data_replaceitemoflist', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_integer', + 'inputName':'INDEX' + }, + { + 'type':'field', + 'fieldName':'LIST' + }, + { + 'type':'input', + 'inputOp':'text', + 'inputName':'ITEM' + } + ] + }, + 'getLine:ofList:':{ + 'opcode':'data_itemoflist', + 'argMap':[ + { + 'type':'input', + 'inputOp':'math_integer', + 'inputName':'INDEX' + }, + { + 'type':'field', + 'fieldName':'LIST' + } + ] + }, + 'lineCountOfList:':{ + 'opcode':'data_lengthoflist', + 'argMap':[ + { + 'type':'field', + 'fieldName':'LIST' + } + ] + }, + 'list:contains:':{ + 'opcode':'data_listcontainsitem', + 'argMap':[ + { + 'type':'field', + 'fieldName':'LIST' + }, + { + 'type':'input', + 'inputOp':'text', + 'inputName':'ITEM' + } + ] + }, + 'showList:':{ + 'opcode':'data_showlist', + 'argMap':[ + { + 'type':'field', + 'fieldName':'LIST' + } + ] + }, + 'hideList:':{ + 'opcode':'data_hidelist', + 'argMap':[ + { + 'type':'field', + 'fieldName':'LIST' + } + ] + }, + 'procDef':{ + 'opcode':'procedures_defnoreturn', + 'argMap':[] + }, + 'getParam':{ + 'opcode':'procedures_param', + 'argMap':[] + }, + 'call':{ + 'opcode':'procedures_callnoreturn', + 'argMap':[] + } +}; +module.exports = specMap; diff --git a/src/index.js b/src/index.js index d6e05e970..014dc2b23 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,9 @@ var EventEmitter = require('events'); var util = require('util'); var Runtime = require('./engine/runtime'); -var adapter = require('./engine/adapter'); +var sb2import = require('./import/sb2import'); +var Sprite = require('./sprites/sprite'); +var Blocks = require('./engine/blocks'); /** * Handles connections between blocks, stage, and extensions. @@ -11,73 +13,38 @@ var adapter = require('./engine/adapter'); */ function VirtualMachine () { var instance = this; - // Bind event emitter and runtime to VM instance - // @todo Post message (Web Worker) polyfill EventEmitter.call(instance); - instance.runtime = new Runtime(); - /** - * Event listener for blocks. Handles validation and serves as a generic - * adapter between the blocks and the runtime interface. - * - * @param {Object} Blockly "block" event + * VM runtime, to store blocks, I/O devices, sprites/targets, etc. + * @type {!Runtime} */ - instance.blockListener = function (e) { - // Validate event - if (typeof e !== 'object') return; - if (typeof e.blockId !== 'string') return; + instance.runtime = new Runtime(); + /** + * The "currently editing"/selected target ID for the VM. + * Block events from any Blockly workspace are routed to this target. + * @type {!string} + */ + instance.editingTarget = null; + // Runtime emits are passed along as VM emits. + instance.runtime.on(Runtime.SCRIPT_GLOW_ON, function (id) { + instance.emit(Runtime.SCRIPT_GLOW_ON, {id: id}); + }); + instance.runtime.on(Runtime.SCRIPT_GLOW_OFF, function (id) { + instance.emit(Runtime.SCRIPT_GLOW_OFF, {id: id}); + }); + instance.runtime.on(Runtime.BLOCK_GLOW_ON, function (id) { + instance.emit(Runtime.BLOCK_GLOW_ON, {id: id}); + }); + instance.runtime.on(Runtime.BLOCK_GLOW_OFF, function (id) { + instance.emit(Runtime.BLOCK_GLOW_OFF, {id: id}); + }); + instance.runtime.on(Runtime.VISUAL_REPORT, function (id, value) { + instance.emit(Runtime.VISUAL_REPORT, {id: id, value: value}); + }); - // Blocks - switch (e.type) { - case 'create': - instance.runtime.createBlock(adapter(e), false); - break; - case 'change': - instance.runtime.changeBlock({ - id: e.blockId, - element: e.element, - name: e.name, - value: e.newValue - }); - break; - case 'move': - instance.runtime.moveBlock({ - id: e.blockId, - oldParent: e.oldParentId, - oldField: e.oldInputName, - newParent: e.newParentId, - newField: e.newInputName - }); - break; - case 'delete': - instance.runtime.deleteBlock({ - id: e.blockId - }); - break; - } - }; - - instance.flyoutBlockListener = function (e) { - switch (e.type) { - case 'create': - instance.runtime.createBlock(adapter(e), true); - break; - case 'change': - instance.runtime.changeBlock({ - id: e.blockId, - element: e.element, - name: e.name, - value: e.newValue - }); - break; - case 'delete': - instance.runtime.deleteBlock({ - id: e.blockId - }); - break; - } - }; + this.blockListener = this.blockListener.bind(this); + this.flyoutBlockListener = this.flyoutBlockListener.bind(this); } /** @@ -86,7 +53,259 @@ function VirtualMachine () { util.inherits(VirtualMachine, EventEmitter); /** - * Export and bind to `window` + * Start running the VM - do this before anything else. */ +VirtualMachine.prototype.start = function () { + this.runtime.start(); +}; + +/** + * "Green flag" handler - start all threads starting with a green flag. + */ +VirtualMachine.prototype.greenFlag = function () { + this.runtime.greenFlag(); +}; + +/** + * Set whether the VM is in "turbo mode." + * When true, loops don't yield to redraw. + * @param {Boolean} turboModeOn Whether turbo mode should be set. + */ +VirtualMachine.prototype.setTurboMode = function (turboModeOn) { + this.runtime.turboMode = !!turboModeOn; +}; + +/** + * Set whether the VM is in "pause mode." + * When true, nothing is stepped. + * @param {Boolean} pauseModeOn Whether pause mode should be set. + */ +VirtualMachine.prototype.setPauseMode = function (pauseModeOn) { + this.runtime.setPauseMode(!!pauseModeOn); +}; + +/** + * Set whether the VM is in 2.0 "compatibility mode." + * When true, ticks go at 2.0 speed (30 TPS). + * @param {Boolean} compatibilityModeOn Whether compatibility mode is set. + */ +VirtualMachine.prototype.setCompatibilityMode = function (compatibilityModeOn) { + this.runtime.setCompatibilityMode(!!compatibilityModeOn); +}; + +/** + * Set whether the VM is in "single stepping mode." + * When true, blocks execute slowly and are highlighted visually. + * @param {Boolean} singleSteppingOn Whether single-stepping mode is set. + */ +VirtualMachine.prototype.setSingleSteppingMode = function (singleSteppingOn) { + this.runtime.setSingleSteppingMode(!!singleSteppingOn); +}; + + +/** + * Set single-stepping mode speed. + * When in single-stepping mode, adjusts the speed of execution. + * @param {Number} speed Interval length in ms. + */ +VirtualMachine.prototype.setSingleSteppingSpeed = function (speed) { + this.runtime.setSingleSteppingSpeed(speed); +}; + + +/** + * Stop all threads and running activities. + */ +VirtualMachine.prototype.stopAll = function () { + this.runtime.stopAll(); +}; + +/** + * Clear out current running project data. + */ +VirtualMachine.prototype.clear = function () { + this.runtime.dispose(); + this.editingTarget = null; + this.emitTargetsUpdate(); +}; + +/** + * Get data for playground. Data comes back in an emitted event. + */ +VirtualMachine.prototype.getPlaygroundData = function () { + var instance = this; + // Only send back thread data for the current editingTarget. + var threadData = this.runtime.threads.filter(function(thread) { + return thread.target == instance.editingTarget; + }); + // Remove the target key, since it's a circular reference. + var filteredThreadData = JSON.stringify(threadData, function(key, value) { + if (key == 'target') return undefined; + return value; + }, 2); + this.emit('playgroundData', { + blocks: this.editingTarget.blocks, + threads: filteredThreadData + }); +}; + +/** + * Handle an animation frame. + */ +VirtualMachine.prototype.animationFrame = function () { + this.runtime.animationFrame(); +}; + +/** + * Post I/O data to the virtual devices. + * @param {?string} device Name of virtual I/O device. + * @param {Object} data Any data object to post to the I/O device. + */ +VirtualMachine.prototype.postIOData = function (device, data) { + if (this.runtime.ioDevices[device]) { + this.runtime.ioDevices[device].postData(data); + } +}; + +/** + * Load a project from a Scratch 2.0 JSON representation. + * @param {?string} json JSON string representing the project. + */ +VirtualMachine.prototype.loadProject = function (json) { + this.clear(); + // @todo: Handle other formats, e.g., Scratch 1.4, Scratch 3.0. + sb2import(json, this.runtime); + // Select the first target for editing, e.g., the stage. + this.editingTarget = this.runtime.targets[0]; + // Update the VM user's knowledge of targets and blocks on the workspace. + this.emitTargetsUpdate(); + this.emitWorkspaceUpdate(); + this.runtime.setEditingTarget(this.editingTarget); +}; + +/** + * Temporary way to make an empty project, in case the desired project + * cannot be loaded from the online server. + */ +VirtualMachine.prototype.createEmptyProject = function () { + // Stage. + var blocks2 = new Blocks(); + var stage = new Sprite(blocks2, this.runtime); + stage.name = 'Stage'; + stage.costumes.push({ + skin: './assets/stage.png', + name: 'backdrop1', + bitmapResolution: 2, + rotationCenterX: 480, + rotationCenterY: 360 + }); + var target2 = stage.createClone(); + this.runtime.targets.push(target2); + target2.x = 0; + target2.y = 0; + target2.direction = 90; + target2.size = 200; + target2.visible = true; + target2.isStage = true; + // Sprite1 (cat). + var blocks1 = new Blocks(); + var sprite = new Sprite(blocks1, this.runtime); + sprite.name = 'Sprite1'; + sprite.costumes.push({ + skin: './assets/scratch_cat.svg', + name: 'costume1', + bitmapResolution: 1, + rotationCenterX: 47, + rotationCenterY: 55 + }); + var target1 = sprite.createClone(); + this.runtime.targets.push(target1); + target1.x = 0; + target1.y = 0; + target1.direction = 90; + target1.size = 100; + target1.visible = true; + this.editingTarget = this.runtime.targets[0]; + this.emitTargetsUpdate(); + this.emitWorkspaceUpdate(); +}; + +/** + * Set the renderer for the VM/runtime + * @param {!RenderWebGL} renderer The renderer to attach + */ +VirtualMachine.prototype.attachRenderer = function (renderer) { + this.runtime.attachRenderer(renderer); +}; + +/** + * Handle a Blockly event for the current editing target. + * @param {!Blockly.Event} e Any Blockly event. + */ +VirtualMachine.prototype.blockListener = function (e) { + if (this.editingTarget) { + this.editingTarget.blocks.blocklyListen(e, this.runtime); + } +}; + +/** + * Handle a Blockly event for the flyout. + * @param {!Blockly.Event} e Any Blockly event. + */ +VirtualMachine.prototype.flyoutBlockListener = function (e) { + this.runtime.flyoutBlocks.blocklyListen(e, this.runtime); +}; + +/** + * Set an editing target. An editor UI can use this function to switch + * between editing different targets, sprites, etc. + * After switching the editing target, the VM may emit updates + * to the list of targets and any attached workspace blocks + * (see `emitTargetsUpdate` and `emitWorkspaceUpdate`). + * @param {string} targetId Id of target to set as editing. + */ +VirtualMachine.prototype.setEditingTarget = function (targetId) { + // Has the target id changed? If not, exit. + if (targetId == this.editingTarget.id) { + return; + } + var target = this.runtime.getTargetById(targetId); + if (target) { + this.editingTarget = target; + // Emit appropriate UI updates. + this.emitTargetsUpdate(); + this.emitWorkspaceUpdate(); + this.runtime.setEditingTarget(target); + } +}; + +/** + * Emit metadata about available targets. + * An editor UI could use this to display a list of targets and show + * the currently editing one. + */ +VirtualMachine.prototype.emitTargetsUpdate = function () { + this.emit('targetsUpdate', { + // [[target id, human readable target name], ...]. + targetList: this.runtime.targets.filter(function (target) { + // Don't report clones. + return !target.hasOwnProperty('isOriginal') || target.isOriginal; + }).map(function(target) { + return [target.id, target.getName()]; + }), + // Currently editing target id. + editingTarget: this.editingTarget ? this.editingTarget.id : null + }); +}; + +/** + * Emit an Blockly/scratch-blocks compatible XML representation + * of the current editing target's blocks. + */ +VirtualMachine.prototype.emitWorkspaceUpdate = function () { + this.emit('workspaceUpdate', { + 'xml': this.editingTarget.blocks.toXML() + }); +}; + module.exports = VirtualMachine; -if (typeof window !== 'undefined') window.VirtualMachine = module.exports; diff --git a/src/io/clock.js b/src/io/clock.js new file mode 100644 index 000000000..ce4c8f553 --- /dev/null +++ b/src/io/clock.js @@ -0,0 +1,37 @@ +var Timer = require('../util/timer'); + +function Clock (runtime) { + this._projectTimer = new Timer(); + this._projectTimer.start(); + this._pausedTime = null; + this._paused = false; + /** + * Reference to the owning Runtime. + * @type{!Runtime} + */ + this.runtime = runtime; +} + +Clock.prototype.projectTimer = function () { + if (this._paused) { + return this._pausedTime / 1000; + } + return this._projectTimer.timeElapsed() / 1000; +}; + +Clock.prototype.pause = function () { + this._paused = true; + this._pausedTime = this._projectTimer.timeElapsed(); +}; + +Clock.prototype.resume = function () { + this._paused = false; + var dt = this._projectTimer.timeElapsed() - this._pausedTime; + this._projectTimer.startTime += dt; +}; + +Clock.prototype.resetProjectTimer = function () { + this._projectTimer.start(); +}; + +module.exports = Clock; diff --git a/src/io/keyboard.js b/src/io/keyboard.js new file mode 100644 index 000000000..ea423fd40 --- /dev/null +++ b/src/io/keyboard.js @@ -0,0 +1,85 @@ +var Cast = require('../util/cast'); + +function Keyboard (runtime) { + /** + * List of currently pressed keys. + * @type{Array.<number>} + */ + this._keysPressed = []; + /** + * Reference to the owning Runtime. + * Can be used, for example, to activate hats. + * @type{!Runtime} + */ + this.runtime = runtime; +} + +/** + * Convert a Scratch key name to a DOM keyCode. + * @param {Any} keyName Scratch key argument. + * @return {number} Key code corresponding to a DOM event. + */ +Keyboard.prototype._scratchKeyToKeyCode = function (keyName) { + if (typeof keyName == 'number') { + // Key codes placed in with number blocks. + return keyName; + } + var keyString = Cast.toString(keyName); + switch (keyString) { + case 'space': return 32; + case 'left arrow': return 37; + case 'up arrow': return 38; + case 'right arrow': return 39; + case 'down arrow': return 40; + // @todo: Consider adding other special keys here. + } + // Keys reported by DOM keyCode are upper case. + return keyString.toUpperCase().charCodeAt(0); +}; + +Keyboard.prototype._keyCodeToScratchKey = function (keyCode) { + if (keyCode >= 48 && keyCode <= 90) { + // Standard letter. + return String.fromCharCode(keyCode).toLowerCase(); + } + switch (keyCode) { + case 32: return 'space'; + case 37: return 'left arrow'; + case 38: return 'up arrow'; + case 39: return 'right arrow'; + case 40: return 'down arrow'; + } + return null; +}; + +Keyboard.prototype.postData = function (data) { + if (data.keyCode) { + var index = this._keysPressed.indexOf(data.keyCode); + if (data.isDown) { + // If not already present, add to the list. + if (index < 0) { + this._keysPressed.push(data.keyCode); + } + // Always trigger hats, even if it was already pressed. + this.runtime.startHats('event_whenkeypressed', { + 'KEY_OPTION': this._keyCodeToScratchKey(data.keyCode) + }); + this.runtime.startHats('event_whenkeypressed', { + 'KEY_OPTION': 'any' + }); + } else if (index > -1) { + // If already present, remove from the list. + this._keysPressed.splice(index, 1); + } + } +}; + +Keyboard.prototype.getKeyIsDown = function (key) { + if (key == 'any') { + return this._keysPressed.length > 0; + } + var keyCode = this._scratchKeyToKeyCode(key); + return this._keysPressed.indexOf(keyCode) > -1; +}; + +module.exports = Keyboard; diff --git a/src/io/mouse.js b/src/io/mouse.js new file mode 100644 index 000000000..6b9860ee7 --- /dev/null +++ b/src/io/mouse.js @@ -0,0 +1,57 @@ +var MathUtil = require('../util/math-util'); + +function Mouse (runtime) { + this._x = 0; + this._y = 0; + this._isDown = false; + /** + * Reference to the owning Runtime. + * Can be used, for example, to activate hats. + * @type{!Runtime} + */ + this.runtime = runtime; +} + +Mouse.prototype.postData = function(data) { + if (data.x) { + this._x = data.x - data.canvasWidth / 2; + } + if (data.y) { + this._y = data.y - data.canvasHeight / 2; + } + if (typeof data.isDown !== 'undefined') { + this._isDown = data.isDown; + if (this._isDown) { + this._activateClickHats(data.x, data.y); + } + } +}; + +Mouse.prototype._activateClickHats = function (x, y) { + if (this.runtime.renderer) { + var drawableID = this.runtime.renderer.pick(x, y); + for (var i = 0; i < this.runtime.targets.length; i++) { + var target = this.runtime.targets[i]; + if (target.hasOwnProperty('drawableID') && + target.drawableID == drawableID) { + this.runtime.startHats('event_whenthisspriteclicked', + null, target); + return; + } + } + } +}; + +Mouse.prototype.getX = function () { + return MathUtil.clamp(this._x, -240, 240); +}; + +Mouse.prototype.getY = function () { + return MathUtil.clamp(-this._y, -180, 180); +}; + +Mouse.prototype.getIsDown = function () { + return this._isDown; +}; + +module.exports = Mouse; diff --git a/src/sprites/clone.js b/src/sprites/clone.js new file mode 100644 index 000000000..13d9434a9 --- /dev/null +++ b/src/sprites/clone.js @@ -0,0 +1,588 @@ +var util = require('util'); +var MathUtil = require('../util/math-util'); +var Target = require('../engine/target'); + +/** + * Clone (instance) of a sprite. + * @param {!Sprite} sprite Reference to the sprite. + * @param {Runtime} runtime Reference to the runtime. + * @constructor + */ +function Clone(sprite, runtime) { + Target.call(this, sprite.blocks); + this.runtime = runtime; + /** + * Reference to the sprite that this is a clone of. + * @type {!Sprite} + */ + this.sprite = sprite; + /** + * Reference to the global renderer for this VM, if one exists. + * @type {?RenderWebGLWorker} + */ + this.renderer = null; + if (this.runtime) { + this.renderer = this.runtime.renderer; + } + /** + * ID of the drawable for this clone returned by the renderer, if rendered. + * @type {?Number} + */ + this.drawableID = null; + + /** + * Map of current graphic effect values. + * @type {!Object.<string, number>} + */ + this.effects = { + 'color': 0, + 'fisheye': 0, + 'whirl': 0, + 'pixelate': 0, + 'mosaic': 0, + 'brightness': 0, + 'ghost': 0 + }; +} +util.inherits(Clone, Target); + +/** + * Create a clone's drawable with the this.renderer. + */ +Clone.prototype.initDrawable = function () { + if (this.renderer) { + this.drawableID = this.renderer.createDrawable(); + } + // If we're a clone, start the hats. + if (!this.isOriginal) { + this.runtime.startHats( + 'control_start_as_clone', null, this + ); + } +}; + +// Clone-level properties. +/** + * Whether this represents an "original" clone, i.e., created by the editor + * and not clone blocks. In interface terms, this true for a "sprite." + * @type {boolean} + */ +Clone.prototype.isOriginal = true; + +/** + * Whether this clone represents the Scratch stage. + * @type {boolean} + */ +Clone.prototype.isStage = false; + +/** + * Scratch X coordinate. Currently should range from -240 to 240. + * @type {Number} + */ +Clone.prototype.x = 0; + +/** + * Scratch Y coordinate. Currently should range from -180 to 180. + * @type {number} + */ +Clone.prototype.y = 0; + +/** + * Scratch direction. Currently should range from -179 to 180. + * @type {number} + */ +Clone.prototype.direction = 90; + +/** + * Whether the clone is currently visible. + * @type {boolean} + */ +Clone.prototype.visible = true; + +/** + * Size of clone as a percent of costume size. Ranges from 5% to 535%. + * @type {number} + */ +Clone.prototype.size = 100; + +/** + * Currently selected costume index. + * @type {number} + */ +Clone.prototype.currentCostume = 0; + +/** + * Rotation style for "all around"/spinning. + * @enum + */ +Clone.ROTATION_STYLE_ALL_AROUND = 'all around'; + +/** + * Rotation style for "left-right"/flipping. + * @enum + */ +Clone.ROTATION_STYLE_LEFT_RIGHT = 'left-right'; + +/** + * Rotation style for "no rotation." + * @enum + */ +Clone.ROTATION_STYLE_NONE = 'don\'t rotate'; + +/** + * Current rotation style. + * @type {!string} + */ +Clone.prototype.rotationStyle = Clone.ROTATION_STYLE_ALL_AROUND; + +// End clone-level properties. + +/** + * Set the X and Y coordinates of a clone. + * @param {!number} x New X coordinate of clone, in Scratch coordinates. + * @param {!number} y New Y coordinate of clone, in Scratch coordinates. + */ +Clone.prototype.setXY = function (x, y) { + if (this.isStage) { + return; + } + this.x = x; + this.y = y; + if (this.renderer) { + this.renderer.updateDrawableProperties(this.drawableID, { + position: [this.x, this.y] + }); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +/** + * Get the rendered direction and scale, after applying rotation style. + * @return {Object<string, number>} Direction and scale to render. + */ +Clone.prototype._getRenderedDirectionAndScale = function () { + // Default: no changes to `this.direction` or `this.scale`. + var finalDirection = this.direction; + var finalScale = [this.size, this.size]; + if (this.rotationStyle == Clone.ROTATION_STYLE_NONE) { + // Force rendered direction to be 90. + finalDirection = 90; + } else if (this.rotationStyle === Clone.ROTATION_STYLE_LEFT_RIGHT) { + // Force rendered direction to be 90, and flip drawable if needed. + finalDirection = 90; + var scaleFlip = (this.direction < 0) ? -1 : 1; + finalScale = [scaleFlip * this.size, this.size]; + } + return {direction: finalDirection, scale: finalScale}; +}; + +/** + * Set the direction of a clone. + * @param {!number} direction New direction of clone. + */ +Clone.prototype.setDirection = function (direction) { + if (this.isStage) { + return; + } + // Keep direction between -179 and +180. + this.direction = MathUtil.wrapClamp(direction, -179, 180); + if (this.renderer) { + var renderedDirectionScale = this._getRenderedDirectionAndScale(); + this.renderer.updateDrawableProperties(this.drawableID, { + direction: renderedDirectionScale.direction, + scale: renderedDirectionScale.scale + }); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +/** + * Set a say bubble on this clone. + * @param {?string} type Type of say bubble: "say", "think", or null. + * @param {?string} message Message to put in say bubble. + */ +Clone.prototype.setSay = function (type, message) { + if (this.isStage) { + return; + } + // @todo: Render to stage. + if (!type || !message) { + console.log('Clearing say bubble'); + return; + } + console.log('Setting say bubble:', type, message); +}; + +/** + * Set visibility of the clone; i.e., whether it's shown or hidden. + * @param {!boolean} visible True if the sprite should be shown. + */ +Clone.prototype.setVisible = function (visible) { + if (this.isStage) { + return; + } + this.visible = visible; + if (this.renderer) { + this.renderer.updateDrawableProperties(this.drawableID, { + visible: this.visible + }); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +/** + * Set size of the clone, as a percentage of the costume size. + * @param {!number} size Size of clone, from 5 to 535. + */ +Clone.prototype.setSize = function (size) { + if (this.isStage) { + return; + } + // Keep size between 5% and 535%. + this.size = MathUtil.clamp(size, 5, 535); + if (this.renderer) { + var renderedDirectionScale = this._getRenderedDirectionAndScale(); + this.renderer.updateDrawableProperties(this.drawableID, { + direction: renderedDirectionScale.direction, + scale: renderedDirectionScale.scale + }); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +/** + * Set a particular graphic effect on this clone. + * @param {!string} effectName Name of effect (see `Clone.prototype.effects`). + * @param {!number} value Numerical magnitude of effect. + */ +Clone.prototype.setEffect = function (effectName, value) { + if (!this.effects.hasOwnProperty(effectName)) return; + this.effects[effectName] = value; + if (this.renderer) { + var props = {}; + props[effectName] = this.effects[effectName]; + this.renderer.updateDrawableProperties(this.drawableID, props); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +/** + * Clear all graphic effects on this clone. + */ +Clone.prototype.clearEffects = function () { + for (var effectName in this.effects) { + this.effects[effectName] = 0; + } + if (this.renderer) { + this.renderer.updateDrawableProperties(this.drawableID, this.effects); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +/** + * Set the current costume of this clone. + * @param {number} index New index of costume. + */ +Clone.prototype.setCostume = function (index) { + // Keep the costume index within possible values. + index = Math.round(index); + this.currentCostume = MathUtil.wrapClamp( + index, 0, this.sprite.costumes.length - 1 + ); + if (this.renderer) { + this.renderer.updateDrawableProperties(this.drawableID, { + skin: this.sprite.costumes[this.currentCostume].skin + }); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +/** + * Update the rotation style for this clone. + * @param {!string} rotationStyle New rotation style. + */ +Clone.prototype.setRotationStyle = function (rotationStyle) { + if (rotationStyle == Clone.ROTATION_STYLE_NONE) { + this.rotationStyle = Clone.ROTATION_STYLE_NONE; + } else if (rotationStyle == Clone.ROTATION_STYLE_ALL_AROUND) { + this.rotationStyle = Clone.ROTATION_STYLE_ALL_AROUND; + } else if (rotationStyle == Clone.ROTATION_STYLE_LEFT_RIGHT) { + this.rotationStyle = Clone.ROTATION_STYLE_LEFT_RIGHT; + } + if (this.renderer) { + var renderedDirectionScale = this._getRenderedDirectionAndScale(); + this.renderer.updateDrawableProperties(this.drawableID, { + direction: renderedDirectionScale.direction, + scale: renderedDirectionScale.scale + }); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +/** + * Get a costume index of this clone, by name of the costume. + * @param {?string} costumeName Name of a costume. + * @return {number} Index of the named costume, or -1 if not present. + */ +Clone.prototype.getCostumeIndexByName = function (costumeName) { + for (var i = 0; i < this.sprite.costumes.length; i++) { + if (this.sprite.costumes[i].name == costumeName) { + return i; + } + } + return -1; +}; + +/** + * Update all drawable properties for this clone. + * Use when a batch has changed, e.g., when the drawable is first created. + */ +Clone.prototype.updateAllDrawableProperties = function () { + if (this.renderer) { + var renderedDirectionScale = this._getRenderedDirectionAndScale(); + this.renderer.updateDrawableProperties(this.drawableID, { + position: [this.x, this.y], + direction: renderedDirectionScale.direction, + scale: renderedDirectionScale.scale, + visible: this.visible, + skin: this.sprite.costumes[this.currentCostume].skin + }); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +/** + * Return the human-readable name for this clone, i.e., the sprite's name. + * @override + * @returns {string} Human-readable name for the clone. + */ +Clone.prototype.getName = function () { + return this.sprite.name; +}; + +/** + * Return the clone's tight bounding box. + * Includes top, left, bottom, right attributes in Scratch coordinates. + * @return {?Object} Tight bounding box of clone, or null. + */ +Clone.prototype.getBounds = function () { + if (this.renderer) { + return this.runtime.renderer.getBounds(this.drawableID); + } + return null; +}; + +/** + * Return whether the clone is touching a point. + * @param {number} x X coordinate of test point. + * @param {number} y Y coordinate of test point. + * @return {Boolean} True iff the clone is touching the point. + */ +Clone.prototype.isTouchingPoint = function (x, y) { + if (this.renderer) { + // @todo: Update once pick is in Scratch coordinates. + // Limits test to this Drawable, so this will return true + // even if the clone is obscured by another Drawable. + var pickResult = this.runtime.renderer.pick( + x + this.runtime.constructor.STAGE_WIDTH / 2, + -y + this.runtime.constructor.STAGE_HEIGHT / 2, + null, null, + [this.drawableID] + ); + return pickResult === this.drawableID; + } + return false; +}; + +/** + * Return whether the clone is touching a stage edge. + * @return {Boolean} True iff the clone is touching the stage edge. + */ +Clone.prototype.isTouchingEdge = function () { + if (this.renderer) { + var stageWidth = this.runtime.constructor.STAGE_WIDTH; + var stageHeight = this.runtime.constructor.STAGE_HEIGHT; + var bounds = this.getBounds(); + if (bounds.left < -stageWidth / 2 || + bounds.right > stageWidth / 2 || + bounds.top > stageHeight / 2 || + bounds.bottom < -stageHeight / 2) { + return true; + } + } + return false; +}; + +/** + * Return whether the clone is touching a named sprite. + * @param {string} spriteName Name fo the sprite. + * @return {Boolean} True iff the clone is touching a clone of the sprite. + */ +Clone.prototype.isTouchingSprite = function (spriteName) { + var firstClone = this.runtime.getSpriteTargetByName(spriteName); + if (!firstClone || !this.renderer) { + return false; + } + var drawableCandidates = firstClone.sprite.clones.map(function(clone) { + return clone.drawableID; + }); + return this.renderer.isTouchingDrawables( + this.drawableID, drawableCandidates); +}; + +/** + * Return whether the clone is touching a color. + * @param {Array.<number>} rgb [r,g,b], values between 0-255. + * @return {Promise.<Boolean>} True iff the clone is touching the color. + */ +Clone.prototype.isTouchingColor = function (rgb) { + if (this.renderer) { + return this.renderer.isTouchingColor(this.drawableID, rgb); + } + return false; +}; + +/** + * Return whether the clone's color is touching a color. + * @param {Object} targetRgb {Array.<number>} [r,g,b], values between 0-255. + * @param {Object} maskRgb {Array.<number>} [r,g,b], values between 0-255. + * @return {Promise.<Boolean>} True iff the clone's color is touching the color. + */ +Clone.prototype.colorIsTouchingColor = function (targetRgb, maskRgb) { + if (this.renderer) { + return this.renderer.isTouchingColor( + this.drawableID, + targetRgb, + maskRgb + ); + } + return false; +}; + +/** + * Move clone to the front layer. + */ +Clone.prototype.goToFront = function () { + if (this.renderer) { + this.renderer.setDrawableOrder(this.drawableID, Infinity); + } +}; + +/** + * Move clone back a number of layers. + * @param {number} nLayers How many layers to go back. + */ +Clone.prototype.goBackLayers = function (nLayers) { + if (this.renderer) { + this.renderer.setDrawableOrder(this.drawableID, -nLayers, true, 1); + } +}; + +/** + * Keep a desired position within a fence. + * @param {number} newX New desired X position. + * @param {number} newY New desired Y position. + * @param {Object=} opt_fence Optional fence with left, right, top bottom. + * @return {Array.<number>} Fenced X and Y coordinates. + */ +Clone.prototype.keepInFence = function (newX, newY, opt_fence) { + var fence = opt_fence; + if (!fence) { + fence = { + left: -this.runtime.constructor.STAGE_WIDTH / 2, + right: this.runtime.constructor.STAGE_WIDTH / 2, + top: this.runtime.constructor.STAGE_HEIGHT / 2, + bottom: -this.runtime.constructor.STAGE_HEIGHT / 2 + }; + } + var bounds = this.getBounds(); + if (!bounds) return; + // Adjust the known bounds to the target position. + bounds.left += (newX - this.x); + bounds.right += (newX - this.x); + bounds.top += (newY - this.y); + bounds.bottom += (newY - this.y); + // Find how far we need to move the target position. + var dx = 0; + var dy = 0; + if (bounds.left < fence.left) { + dx += fence.left - bounds.left; + } + if (bounds.right > fence.right) { + dx += fence.right - bounds.right; + } + if (bounds.top > fence.top) { + dy += fence.top - bounds.top; + } + if (bounds.bottom < fence.bottom) { + dy += fence.bottom - bounds.bottom; + } + return [newX + dx, newY + dy]; +}; + +/** + * Make a clone of this clone, copying any run-time properties. + * If we've hit the global clone limit, returns null. + * @return {!Clone} New clone object. + */ +Clone.prototype.makeClone = function () { + if (!this.runtime.clonesAvailable()) { + return; // Hit max clone limit. + } + this.runtime.changeCloneCounter(1); + var newClone = this.sprite.createClone(); + newClone.x = this.x; + newClone.y = this.y; + newClone.direction = this.direction; + newClone.visible = this.visible; + newClone.size = this.size; + newClone.currentCostume = this.currentCostume; + newClone.rotationStyle = this.rotationStyle; + newClone.effects = JSON.parse(JSON.stringify(this.effects)); + newClone.variables = JSON.parse(JSON.stringify(this.variables)); + newClone.lists = JSON.parse(JSON.stringify(this.lists)); + newClone.initDrawable(); + newClone.updateAllDrawableProperties(); + return newClone; +}; + +/** + * Called when the project receives a "green flag." + * For a clone, this clears graphic effects. + */ +Clone.prototype.onGreenFlag = function () { + this.clearEffects(); +}; + +/** + * Dispose of this clone, destroying any run-time properties. + */ +Clone.prototype.dispose = function () { + this.runtime.changeCloneCounter(-1); + if (this.renderer && this.drawableID !== null) { + this.renderer.destroyDrawable(this.drawableID); + if (this.visible) { + this.runtime.requestRedraw(); + } + } +}; + +module.exports = Clone; diff --git a/src/sprites/sprite.js b/src/sprites/sprite.js new file mode 100644 index 000000000..2afb25e5e --- /dev/null +++ b/src/sprites/sprite.js @@ -0,0 +1,57 @@ +var Clone = require('./clone'); +var Blocks = require('../engine/blocks'); + +/** + * Sprite to be used on the Scratch stage. + * All clones of a sprite have shared blocks, shared costumes, shared variables. + * @param {?Blocks} blocks Shared blocks object for all clones of sprite. + * @param {Runtime} runtime Reference to the runtime. + * @constructor + */ +function Sprite (blocks, runtime) { + this.runtime = runtime; + if (!blocks) { + // Shared set of blocks for all clones. + blocks = new Blocks(); + } + this.blocks = blocks; + /** + * Human-readable name for this sprite (and all clones). + * @type {string} + */ + this.name = ''; + /** + * List of costumes for this sprite. + * Each entry is an object, e.g., + * { + * skin: "costume.svg", + * name: "Costume Name", + * bitmapResolution: 2, + * rotationCenterX: 0, + * rotationCenterY: 0 + * } + * @type {Array.<!Object>} + */ + this.costumes = []; + /** + * List of clones for this sprite, including the original. + * @type {Array.<!Clone>} + */ + this.clones = []; +} + +/** + * Create a clone of this sprite. + * @returns {!Clone} Newly created clone. + */ +Sprite.prototype.createClone = function () { + var newClone = new Clone(this, this.runtime); + newClone.isOriginal = this.clones.length == 0; + this.clones.push(newClone); + if (newClone.isOriginal) { + newClone.initDrawable(); + } + return newClone; +}; + +module.exports = Sprite; diff --git a/src/util/cast.js b/src/util/cast.js new file mode 100644 index 000000000..dda55bf8e --- /dev/null +++ b/src/util/cast.js @@ -0,0 +1,163 @@ +var Color = require('../util/color'); + +function Cast () {} + +/** + * @fileoverview + * Utilities for casting and comparing Scratch data-types. + * Scratch behaves slightly differently from JavaScript in many respects, + * and these differences should be encapsulated below. + * For example, in Scratch, add(1, join("hello", world")) -> 1. + * This is because "hello world" is cast to 0. + * In JavaScript, 1 + Number("hello" + "world") would give you NaN. + * Use when coercing a value before computation. + */ + +/** + * Scratch cast to number. + * Treats NaN as 0. + * In Scratch 2.0, this is captured by `interp.numArg.` + * @param {*} value Value to cast to number. + * @return {number} The Scratch-casted number value. + */ +Cast.toNumber = function (value) { + var n = Number(value); + if (isNaN(n)) { + // Scratch treats NaN as 0, when needed as a number. + // E.g., 0 + NaN -> 0. + return 0; + } + return n; +}; + +/** + * Scratch cast to boolean. + * In Scratch 2.0, this is captured by `interp.boolArg.` + * Treats some string values differently from JavaScript. + * @param {*} value Value to cast to boolean. + * @return {boolean} The Scratch-casted boolean value. + */ +Cast.toBoolean = function (value) { + // Already a boolean? + if (typeof value === 'boolean') { + return value; + } + if (typeof value === 'string') { + // These specific strings are treated as false in Scratch. + if ((value == '') || + (value == '0') || + (value.toLowerCase() == 'false')) { + return false; + } + // All other strings treated as true. + return true; + } + // Coerce other values and numbers. + return Boolean(value); +}; + +/** + * Scratch cast to string. + * @param {*} value Value to cast to string. + * @return {string} The Scratch-casted string value. + */ +Cast.toString = function (value) { + return String(value); +}; + +/** + * Cast any Scratch argument to an RGB color object to be used for the renderer. + * @param {*} value Value to convert to RGB color object. + * @return {Array.<number>} [r,g,b], values between 0-255. + */ +Cast.toRgbColorList = function (value) { + var color; + if (typeof value == 'string' && value.substring(0, 1) == '#') { + color = Color.hexToRgb(value); + } else { + color = Color.decimalToRgb(Cast.toNumber(value)); + } + return [color.r, color.g, color.b]; +}; + +/** + * Compare two values, using Scratch cast, case-insensitive string compare, etc. + * In Scratch 2.0, this is captured by `interp.compare.` + * @param {*} v1 First value to compare. + * @param {*} v2 Second value to compare. + * @returns {Number} Negative number if v1 < v2; 0 if equal; positive otherwise. + */ +Cast.compare = function (v1, v2) { + var n1 = Number(v1); + var n2 = Number(v2); + if (isNaN(n1) || isNaN(n2)) { + // At least one argument can't be converted to a number. + // Scratch compares strings as case insensitive. + var s1 = String(v1).toLowerCase(); + var s2 = String(v2).toLowerCase(); + return s1.localeCompare(s2); + } else { + // Compare as numbers. + return n1 - n2; + } +}; + +/** + * Determine if a Scratch argument number represents a round integer. + * @param {*} val Value to check. + * @return {boolean} True if number looks like an integer. + */ +Cast.isInt = function (val) { + // Values that are already numbers. + if (typeof val === 'number') { + if (isNaN(val)) { // NaN is considered an integer. + return true; + } + // True if it's "round" (e.g., 2.0 and 2). + return val == parseInt(val); + } else if (typeof val === 'boolean') { + // `True` and `false` always represent integer after Scratch cast. + return true; + } else if (typeof val === 'string') { + // If it contains a decimal point, don't consider it an int. + return val.indexOf('.') < 0; + } + return false; +}; + +Cast.LIST_INVALID = 'INVALID'; +Cast.LIST_ALL = 'ALL'; +/** + * Compute a 1-based index into a list, based on a Scratch argument. + * Two special cases may be returned: + * LIST_ALL: if the block is referring to all of the items in the list. + * LIST_INVALID: if the index was invalid in any way. + * @param {*} index Scratch arg, including 1-based numbers or special cases. + * @param {number} length Length of the list. + * @return {(number|string)} 1-based index for list, LIST_ALL, or LIST_INVALID. + */ +Cast.toListIndex = function (index, length) { + if (typeof index !== 'number') { + if (index == 'all') { + return Cast.LIST_ALL; + } + if (index == 'last') { + if (length > 0) { + return length; + } + return Cast.LIST_INVALID; + } else if (index == 'random' || index == 'any') { + if (length > 0) { + return 1 + Math.floor(Math.random() * length); + } + return Cast.LIST_INVALID; + } + } + index = Math.floor(Cast.toNumber(index)); + if (index < 1 || index > length) { + return Cast.LIST_INVALID; + } + return index; +}; + +module.exports = Cast; diff --git a/src/util/color.js b/src/util/color.js new file mode 100644 index 000000000..2635c1b6c --- /dev/null +++ b/src/util/color.js @@ -0,0 +1,76 @@ +function Color () {} + +/** + * Convert a Scratch decimal color to a hex string, #RRGGBB. + * @param {number} decimal RGB color as a decimal. + * @return {string} RGB color as #RRGGBB hex string. + */ +Color.decimalToHex = function (decimal) { + if (decimal < 0) { + decimal += 0xFFFFFF + 1; + } + var hex = Number(decimal).toString(16); + hex = '#' + '000000'.substr(0, 6 - hex.length) + hex; + return hex; +}; + +/** + * Convert a Scratch decimal color to an RGB color object. + * @param {number} decimal RGB color as decimal. + * @returns {Object} {r: R, g: G, b: B}, values between 0-255 + */ +Color.decimalToRgb = function (decimal) { + var r = (decimal >> 16) & 0xFF; + var g = (decimal >> 8) & 0xFF; + var b = decimal & 0xFF; + return {r: r, g: g, b: b}; +}; + +/** + * Convert a hex color (e.g., F00, #03F, #0033FF) to an RGB color object. + * CC-BY-SA Tim Down: + * https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb + * @param {!string} hex Hex representation of the color. + * @return {Object} {r: R, g: G, b: B}, 0-255, or null. + */ +Color.hexToRgb = function (hex) { + var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + hex = hex.replace(shorthandRegex, function(m, r, g, b) { + return r + r + g + g + b + b; + }); + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +}; + +/** + * Convert an RGB color object to a hex color. + * @param {Object} rgb {r: R, g: G, b: B}, values between 0-255. + * @return {!string} Hex representation of the color. + */ +Color.rgbToHex = function (rgb) { + return Color.decimalToHex(Color.rgbToDecimal(rgb)); +}; + +/** + * Convert an RGB color object to a Scratch decimal color. + * @param {Object} rgb {r: R, g: G, b: B}, values between 0-255. + * @return {!number} Number representing the color. + */ +Color.rgbToDecimal = function (rgb) { + return (rgb.r << 16) + (rgb.g << 8) + rgb.b; +}; + +/** +* Convert a hex color (e.g., F00, #03F, #0033FF) to a decimal color number. +* @param {!string} hex Hex representation of the color. +* @return {!number} Number representing the color. +*/ +Color.hexToDecimal = function (hex) { + return Color.rgbToDecimal(Color.hexToRgb(hex)); +}; + +module.exports = Color; diff --git a/src/util/math-util.js b/src/util/math-util.js new file mode 100644 index 000000000..14ebb450e --- /dev/null +++ b/src/util/math-util.js @@ -0,0 +1,48 @@ +function MathUtil () {} + +/** + * Convert a value from degrees to radians. + * @param {!number} deg Value in degrees. + * @return {!number} Equivalent value in radians. + */ +MathUtil.degToRad = function (deg) { + return deg * Math.PI / 180; +}; + +/** + * Convert a value from radians to degrees. + * @param {!number} rad Value in radians. + * @return {!number} Equivalent value in degrees. + */ +MathUtil.radToDeg = function (rad) { + return rad * 180 / Math.PI; +}; + +/** + * Clamp a number between two limits. + * If n < min, return min. If n > max, return max. Else, return n. + * @param {!number} n Number to clamp. + * @param {!number} min Minimum limit. + * @param {!number} max Maximum limit. + * @return {!number} Value of n clamped to min and max. + */ +MathUtil.clamp = function (n, min, max) { + return Math.min(Math.max(n, min), max); +}; + +/** + * Keep a number between two limits, wrapping "extra" into the range. + * e.g., wrapClamp(7, 1, 5) == 2 + * wrapClamp(0, 1, 5) == 5 + * wrapClamp(-11, -10, 6) == 6, etc. + * @param {!number} n Number to wrap. + * @param {!number} min Minimum limit. + * @param {!number} max Maximum limit. + * @return {!number} Value of n wrapped between min and max. + */ +MathUtil.wrapClamp = function (n, min, max) { + var range = (max - min) + 1; + return n - Math.floor((n - min) / range) * range; +}; + +module.exports = MathUtil; diff --git a/src/util/timer.js b/src/util/timer.js index 10a5b3241..48dd223d5 100644 --- a/src/util/timer.js +++ b/src/util/timer.js @@ -1,20 +1,70 @@ /** - * Constructor + * @fileoverview + * A utility for accurately measuring time. + * To use: + * --- + * var timer = new Timer(); + * timer.start(); + * ... pass some time ... + * var timeDifference = timer.timeElapsed(); + * --- + * Or, you can use the `time` and `relativeTime` + * to do some measurement yourself. */ -function Timer () { - this.startTime = 0; -} +/** + * @constructor + */ +function Timer () {} + +/** + * Used to store the start time of a timer action. + * Updated when calling `timer.start`. + */ +Timer.prototype.startTime = 0; + +/** + * Return the currently known absolute time, in ms precision. + * @returns {number} ms elapsed since 1 January 1970 00:00:00 UTC. + */ Timer.prototype.time = function () { - return Date.now(); + if (Date.now) { + return Date.now(); + } else { + return new Date().getTime(); + } }; +/** + * Returns a time accurate relative to other times produced by this function. + * If possible, will use sub-millisecond precision. + * If not, will use millisecond precision. + * Not guaranteed to produce the same absolute values per-system. + * @returns {number} ms-scale accurate time relative to other relative times. + */ +Timer.prototype.relativeTime = function () { + if (typeof self !== 'undefined' && + self.performance && 'now' in self.performance) { + return self.performance.now(); + } else { + return this.time(); + } +}; + +/** + * Start a timer for measuring elapsed time, + * at the most accurate precision possible. + */ Timer.prototype.start = function () { - this.startTime = this.time(); + this.startTime = this.relativeTime(); }; +/** + * Check time elapsed since `timer.start` was called. + * @returns {number} Time elapsed, in ms (possibly sub-ms precision). + */ Timer.prototype.timeElapsed = function () { - return this.time() - this.startTime; + return this.relativeTime() - this.startTime; }; module.exports = Timer; diff --git a/src/util/uid.js b/src/util/uid.js new file mode 100644 index 000000000..532f9e9bf --- /dev/null +++ b/src/util/uid.js @@ -0,0 +1,29 @@ +/** + * @fileoverview UID generator, from Blockly. + */ + +/** + * Legal characters for the unique ID. + * Should be all on a US keyboard. No XML special characters or control codes. + * Removed $ due to issue 251. + * @private + */ +var soup_ = '!#%()*+,-./:;=?@[]^_`{|}~' + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + +/** + * Generate a unique ID, from Blockly. This should be globally unique. + * 87 characters ^ 20 length > 128 bits (better than a UUID). + * @return {string} A globally unique ID string. + */ +var uid = function () { + var length = 20; + var soupLength = soup_.length; + var id = []; + for (var i = 0; i < length; i++) { + id[i] = soup_.charAt(Math.random() * soupLength); + } + return id.join(''); +}; + +module.exports = uid; diff --git a/src/util/xml-escape.js b/src/util/xml-escape.js new file mode 100644 index 000000000..00ce5bff6 --- /dev/null +++ b/src/util/xml-escape.js @@ -0,0 +1,21 @@ +/** + * Escape a string to be safe to use in XML content. + * CC-BY-SA: hgoebl + * https://stackoverflow.com/questions/7918868/ + * how-to-escape-xml-entities-in-javascript + * @param {!string} unsafe Unsafe string. + * @return {string} XML-escaped string, for use within an XML tag. + */ +var xmlEscape = function (unsafe) { + return unsafe.replace(/[<>&'"]/g, function (c) { + switch (c) { + case '<': return '<'; + case '>': return '>'; + case '&': return '&'; + case '\'': return '''; + case '"': return '"'; + } + }); +}; + +module.exports = xmlEscape; diff --git a/src/util/yieldtimers.js b/src/util/yieldtimers.js deleted file mode 100644 index 45e244eaf..000000000 --- a/src/util/yieldtimers.js +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @fileoverview Timers that are synchronized with the Scratch sequencer. - */ -var Timer = require('./timer'); - -function YieldTimers () {} - -/** - * Shared collection of timers. - * Each timer is a [Function, number] with the callback - * and absolute time for it to run. - * @type {Object.<number,Array>} - */ -YieldTimers.timers = {}; - -/** - * Monotonically increasing timer ID. - * @type {number} - */ -YieldTimers.timerId = 0; - -/** - * Utility for measuring time. - * @type {!Timer} - */ -YieldTimers.globalTimer = new Timer(); - -/** - * The timeout function is passed to primitives and is intended - * as a convenient replacement for window.setTimeout. - * The sequencer will attempt to resolve the timer every time - * the yielded thread would have been stepped. - * @param {!Function} callback To be called when the timer is done. - * @param {number} timeDelta Time to wait, in ms. - * @return {number} Timer ID to be used with other methods. - */ -YieldTimers.timeout = function (callback, timeDelta) { - var id = ++YieldTimers.timerId; - YieldTimers.timers[id] = [ - callback, - YieldTimers.globalTimer.time() + timeDelta - ]; - return id; -}; - -/** - * Attempt to resolve a timeout. - * If the time has passed, call the callback. - * Otherwise, do nothing. - * @param {number} id Timer ID to resolve. - * @return {boolean} True if the timer has resolved. - */ -YieldTimers.resolve = function (id) { - var timer = YieldTimers.timers[id]; - if (!timer) { - // No such timer. - return false; - } - var callback = timer[0]; - var time = timer[1]; - if (YieldTimers.globalTimer.time() < time) { - // Not done yet. - return false; - } - // Execute the callback and remove the timer. - callback(); - delete YieldTimers.timers[id]; - return true; -}; - -/** - * Reject a timer so the callback never executes. - * @param {number} id Timer ID to reject. - */ -YieldTimers.reject = function (id) { - if (YieldTimers.timers[id]) { - delete YieldTimers.timers[id]; - } -}; - -/** - * Reject all timers currently stored. - * Especially useful for a Scratch "stop." - */ -YieldTimers.rejectAll = function () { - YieldTimers.timers = {}; - YieldTimers.timerId = 0; -}; - -module.exports = YieldTimers; diff --git a/test/fixtures/default.json b/test/fixtures/default.json new file mode 100644 index 000000000..af478a4e2 --- /dev/null +++ b/test/fixtures/default.json @@ -0,0 +1,71 @@ +{ + "objName": "Stage", + "sounds": [{ + "soundName": "pop", + "soundID": -1, + "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", + "sampleCount": 258, + "rate": 11025, + "format": "" + }], + "costumes": [{ + "costumeName": "backdrop1", + "baseLayerID": -1, + "baseLayerMD5": "739b5e2a2435f6e1ec2993791b423146.png", + "bitmapResolution": 1, + "rotationCenterX": 240, + "rotationCenterY": 180 + }], + "currentCostumeIndex": 0, + "penLayerMD5": "5c81a336fab8be57adc039a8a2b33ca9.png", + "penLayerID": -1, + "tempoBPM": 60, + "videoAlpha": 0.5, + "children": [{ + "objName": "Sprite1", + "sounds": [{ + "soundName": "meow", + "soundID": -1, + "md5": "83c36d806dc92327b9e7049a565c6bff.wav", + "sampleCount": 18688, + "rate": 22050, + "format": "" + }], + "costumes": [{ + "costumeName": "costume1", + "baseLayerID": -1, + "baseLayerMD5": "09dc888b0b7df19f70d81588ae73420e.svg", + "bitmapResolution": 1, + "rotationCenterX": 47, + "rotationCenterY": 55 + }, + { + "costumeName": "costume2", + "baseLayerID": -1, + "baseLayerMD5": "3696356a03a8d938318876a593572843.svg", + "bitmapResolution": 1, + "rotationCenterX": 47, + "rotationCenterY": 55 + }], + "currentCostumeIndex": 0, + "scratchX": 0, + "scratchY": 0, + "scale": 1, + "direction": 90, + "rotationStyle": "normal", + "isDraggable": false, + "indexInLibrary": 1, + "visible": true, + "spriteInfo": { + } + }], + "info": { + "videoOn": false, + "userAgent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/50.0.2661.102 Safari\/537.36", + "swfVersion": "v446", + "scriptCount": 0, + "spriteCount": 1, + "hasCloudData": false, + "flashVersion": "MAC 21,0,0,242" + } +} diff --git a/test/fixtures/demo.json b/test/fixtures/demo.json new file mode 100644 index 000000000..b10376ec7 --- /dev/null +++ b/test/fixtures/demo.json @@ -0,0 +1,359 @@ +{ + "objName": "Stage", + "variables": [{ + "name": "x", + "value": "1", + "isPersistent": false + }, + { + "name": "y", + "value": "1", + "isPersistent": false + }, + { + "name": "z", + "value": "1", + "isPersistent": false + }, + { + "name": "d", + "value": "1", + "isPersistent": false + }, + { + "name": "a", + "value": 4, + "isPersistent": false + }], + "lists": [{ + "listName": "D# Minor Pentatonic", + "contents": ["78", + "75", + "73", + "75", + "70", + "78", + "73", + "75", + "75", + "78", + "75", + "73", + "75", + "70", + "75", + "78", + "73", + "75", + "78", + "75", + "73", + "75", + "70", + "73", + "68", + "70", + "66", + "68", + "63"], + "isPersistent": false, + "x": 5, + "y": 32, + "width": 125, + "height": 206, + "visible": true + }], + "scripts": [[52, + 8, + [["whenIReceive", "start"], + ["setVar:to:", "a", "1"], + ["doRepeat", + ["lineCountOfList:", "D# Minor Pentatonic"], + [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "a"], "D# Minor Pentatonic"], 0.5], ["changeVar:by:", "a", 1]]]]], + [53, + 186, + [["whenIReceive", "start"], + ["setVar:to:", "x", "1"], + ["rest:elapsed:from:", 7.25], + ["doRepeat", + ["lineCountOfList:", "D# Minor Pentatonic"], + [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "x"], "D# Minor Pentatonic"], 0.25], ["changeVar:by:", "x", 1]]]]], + [48, + 557, + [["whenIReceive", "start"], + ["setVar:to:", "z", "1"], + ["rest:elapsed:from:", 13], + ["doRepeat", + ["lineCountOfList:", "D# Minor Pentatonic"], + [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "z"], "D# Minor Pentatonic"], 0.0625], ["changeVar:by:", "z", 1]]]]], + [49, + 368, + [["whenIReceive", "start"], + ["setVar:to:", "y", "1"], + ["rest:elapsed:from:", 11], + ["doRepeat", + ["lineCountOfList:", "D# Minor Pentatonic"], + [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "y"], "D# Minor Pentatonic"], 0.125], ["changeVar:by:", "y", 1]]]]], + [52, + 745, + [["whenIReceive", "start"], + ["setVar:to:", "d", "1"], + ["rest:elapsed:from:", 13.5], + ["doRepeat", + ["lineCountOfList:", "D# Minor Pentatonic"], + [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "d"], "D# Minor Pentatonic"], 0.03125], ["changeVar:by:", "d", 1]]]]]], + "sounds": [{ + "soundName": "pop", + "soundID": 0, + "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", + "sampleCount": 258, + "rate": 11025, + "format": "" + }], + "costumes": [{ + "costumeName": "backdrop1", + "baseLayerID": 4, + "baseLayerMD5": "b61b1077b0ea1931abee9dbbfa7903ff.png", + "bitmapResolution": 2, + "rotationCenterX": 480, + "rotationCenterY": 360 + }], + "currentCostumeIndex": 0, + "penLayerMD5": "5c81a336fab8be57adc039a8a2b33ca9.png", + "penLayerID": 0, + "tempoBPM": 60, + "videoAlpha": 0.5, + "children": [{ + "objName": "Indicator", + "scripts": [[247.85, + 32.8, + [["procDef", "foo %n", ["bar"], [1], false], + ["hide"], + ["clearPenTrails"], + ["penColor:", 5968094], + ["say:", ["getParam", "bar", "r"]], + ["stopScripts", "this script"]]], + [41, 36, [["whenGreenFlag"], ["call", "foo %n", 1]]]], + "sounds": [{ + "soundName": "pop", + "soundID": 0, + "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", + "sampleCount": 258, + "rate": 11025, + "format": "" + }], + "costumes": [{ + "costumeName": "costume1", + "baseLayerID": 1, + "baseLayerMD5": "d36f6603ec293d2c2198d3ea05109fe0.png", + "bitmapResolution": 2, + "rotationCenterX": 0, + "rotationCenterY": 0 + }], + "currentCostumeIndex": 0, + "scratchX": 22, + "scratchY": -26, + "scale": 1, + "direction": 90, + "rotationStyle": "normal", + "isDraggable": false, + "indexInLibrary": 3, + "visible": false, + "spriteInfo": { + } + }, + { + "target": "Stage", + "cmd": "timer", + "param": null, + "color": 2926050, + "label": "timer", + "mode": 1, + "sliderMin": 0, + "sliderMax": 100, + "isDiscrete": true, + "x": 5, + "y": 5, + "visible": false + }, + { + "target": "Stage", + "cmd": "getVar:", + "param": "x", + "color": 15629590, + "label": "x", + "mode": 1, + "sliderMin": 0, + "sliderMax": 100, + "isDiscrete": true, + "x": 5, + "y": 268, + "visible": true + }, + { + "target": "Stage", + "cmd": "getVar:", + "param": "y", + "color": 15629590, + "label": "y", + "mode": 1, + "sliderMin": 0, + "sliderMax": 100, + "isDiscrete": true, + "x": 5, + "y": 295, + "visible": true + }, + { + "target": "Stage", + "cmd": "getVar:", + "param": "z", + "color": 15629590, + "label": "z", + "mode": 1, + "sliderMin": 0, + "sliderMax": 100, + "isDiscrete": true, + "x": 78, + "y": 268, + "visible": true + }, + { + "objName": "Play", + "scripts": [[32, 33, [["whenClicked"], ["broadcast:", "start"]]]], + "sounds": [{ + "soundName": "pop", + "soundID": 0, + "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", + "sampleCount": 258, + "rate": 11025, + "format": "" + }], + "costumes": [{ + "costumeName": "costume1", + "baseLayerID": 2, + "baseLayerMD5": "30f811366ae3a53e6447932cc7f0212d.png", + "bitmapResolution": 2, + "rotationCenterX": 68, + "rotationCenterY": 115 + }], + "currentCostumeIndex": 0, + "scratchX": 2, + "scratchY": -48, + "scale": 1, + "direction": 90, + "rotationStyle": "normal", + "isDraggable": false, + "indexInLibrary": 1, + "visible": true, + "spriteInfo": { + } + }, + { + "target": "Stage", + "cmd": "getVar:", + "param": "d", + "color": 15629590, + "label": "d", + "mode": 1, + "sliderMin": 0, + "sliderMax": 100, + "isDiscrete": true, + "x": 5, + "y": 241, + "visible": true + }, + { + "target": "Stage", + "cmd": "getVar:", + "param": "a", + "color": 15629590, + "label": "a", + "mode": 1, + "sliderMin": 0, + "sliderMax": 100, + "isDiscrete": true, + "x": 78, + "y": 241, + "visible": true + }, + { + "objName": "Stop", + "scripts": [[45, 104, [["whenClicked"], ["stopScripts", "all"]]]], + "sounds": [{ + "soundName": "pop", + "soundID": 0, + "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", + "sampleCount": 258, + "rate": 11025, + "format": "" + }], + "costumes": [{ + "costumeName": "costume1", + "baseLayerID": 3, + "baseLayerMD5": "3de406f265b8d664406adf7c70762514.png", + "bitmapResolution": 2, + "rotationCenterX": 68, + "rotationCenterY": 70 + }], + "currentCostumeIndex": 0, + "scratchX": 121, + "scratchY": -33, + "scale": 1, + "direction": 90, + "rotationStyle": "normal", + "isDraggable": false, + "indexInLibrary": 2, + "visible": true, + "spriteInfo": { + } + }, + { + "listName": "D# Minor Pentatonic", + "contents": ["78", + "75", + "73", + "75", + "70", + "78", + "73", + "75", + "75", + "78", + "75", + "73", + "75", + "70", + "75", + "78", + "73", + "75", + "78", + "75", + "73", + "75", + "70", + "73", + "68", + "70", + "66", + "68", + "63"], + "isPersistent": false, + "x": 5, + "y": 32, + "width": 125, + "height": 206, + "visible": true + }], + "info": { + "spriteCount": 3, + "projectID": "118381369", + "videoOn": false, + "hasCloudData": false, + "userAgent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/53.0.2785.143 Safari\/537.36", + "scriptCount": 9, + "flashVersion": "MAC 23,0,0,185", + "swfVersion": "v450.1" + } +} diff --git a/test/fixtures/events.json b/test/fixtures/events.json index fca8693ff..d91370f6e 100644 --- a/test/fixtures/events.json +++ b/test/fixtures/events.json @@ -1,20 +1,69 @@ { "create": { - "blockId": "z!+#Nqr,_(V=xz0y7a@d", "workspaceId": "7Luws3lyb*Z98~Kk+IG|", "group": ";OswyM#@%`%,xOrhOXC=", "recordUndo": true, + "name": "block", "xml": { - "attributes": { - "type": { - "value": "wedo_motorclockwise" - } - }, - "innerHTML": "<value name=\"DURATION\"><shadow type=\"math_number\" id=\"!6Ahqg4f}Ljl}X5Hws?Z\"><field name=\"NUM\">10</field></shadow></value>" + "outerHTML": "<block type=\"wedo_motorclockwise\" id=\"z!+#Nqr,_(V=xz0y7a@d\"><value name=\"DURATION\"><shadow type=\"math_number\" id=\"!6Ahqg4f}Ljl}X5Hws?Z\"><field name=\"NUM\">10</field></shadow></value></block>" }, "ids": [ "z!+#Nqr,_(V=xz0y7a@d", "!6Ahqg4f}Ljl}X5Hws?Z" ] + }, + "createbranch": { + "name": "block", + "xml": { + "outerHTML": "<block type=\"control_forever\" id=\"r9`RpL74T6*SXPKv7}Dq\" x=\"61\" y=\"90\"><statement name=\"SUBSTACK\"><block type=\"control_wait\" id=\"{Rwt[LFtD1-JPAi-qf:.\"><value name=\"DURATION\"><shadow type=\"math_number\" id=\"VMDxt_9SYe5{*eNRe5dZ\"><field name=\"NUM\">1</field></shadow></value></block></statement></block>" + } + }, + "createtwobranches": { + "name": "block", + "xml": { + "outerHTML": "<block type=\"control_if_else\" id=\"8W?lmIY!Tgnh)~0!G#9-\" x=\"87\" y=\"159\"><statement name=\"SUBSTACK\"><block type=\"event_broadcast\" id=\"lgU2GGtwlREuasCB02Vr\"></block></statement><statement name=\"SUBSTACK2\"><block type=\"event_broadcast\" id=\"Gb]N,2P;|J%F?pxSwz(2\"></block></statement></block>" + } + }, + "createtoplevelshadow": { + "name": "shadow", + "xml": { + "outerHTML": "<shadow type=\"math_number\" id=\"z9d57=IUI5se;DBbyug)\"><field name=\"NUM\">4</field></shadow>" + } + }, + "createwithnext": { + "name": "block", + "xml": { + "outerHTML": "<block type=\"wedo_setcolor\" id=\"*CT)7+UKjQIEtUw.OGT6\" x=\"89\" y=\"48\"><next><block type=\"wedo_motorspeed\" id=\"Er*:^o7yYL#dX+5)R^xq\"></block></next></block>" + } + }, + "createinvalid": { + "name": "whatever", + "xml": { + "outerHTML": "<xml></xml>" + } + }, + "createinvalidgrandchild": { + "name": "block", + "xml": { + "outerHTML": "<block type=\"control_forever\" id=\"r9`RpL74T6*SXPKv7}Dq\" x=\"61\" y=\"90\"><next><invalidgrandchild>xxx</invalidgrandchild></next></block>" + } + }, + "createbadxml": { + "name": "whatever", + "xml": { + "outerHTML": "></xml>" + } + }, + "createemptyfield": { + "name": "block", + "xml": { + "outerHTML": "<block type='operator_equals' id='l^H_{8[DDyDW?m)HIt@b' x='100' y='362'><value name='OPERAND1'><shadow type='text' id='Ud@4y]bc./]uv~te?brb'><field name='TEXT'></field></shadow></value><value name='OPERAND2'><shadow type='text' id='p8[y..,[K;~G,k7]N;08'><field name='TEXT'></field></shadow></value></block>" + } + }, + "createobscuredshadow": { + "name": "block", + "xml": { + "outerHTML": "<block type='operator_add' id='D;MqidqmaN}Dft)y#Bf`' x='80' y='98'><value name='NUM1'><shadow type='math_number' id='F[IFAdLbq8!q25+Nio@i'><field name='NUM'></field></shadow><block type='sensing_answer' id='D~ZQ|BYb1)xw4)8ziI%.'></block</value><value name='NUM2'><shadow type='math_number' id='|Sjv4!*X6;wj?QaCE{-9'><field name='NUM'></field></shadow></value></block>" + } } } diff --git a/test/integration/index.js b/test/integration/index.js index c98e44651..06bdcf37b 100644 --- a/test/integration/index.js +++ b/test/integration/index.js @@ -6,7 +6,6 @@ test('spec', function (t) { t.type(VirtualMachine, 'function'); t.type(vm, 'object'); - t.type(vm.blockListener, 'function'); t.end(); }); diff --git a/test/unit/adapter.js b/test/unit/adapter.js deleted file mode 100644 index 547e0b9b0..000000000 --- a/test/unit/adapter.js +++ /dev/null @@ -1,20 +0,0 @@ -var test = require('tap').test; -var adapter = require('../../src/engine/adapter'); -var events = require('../fixtures/events.json'); - -test('spec', function (t) { - t.type(adapter, 'function'); - t.end(); -}); - -test('create event', function (t) { - var result = adapter(events.create); - - t.type(result, 'object'); - t.type(result.id, 'string'); - t.type(result.opcode, 'string'); - t.type(result.fields, 'object'); - t.type(result.fields['DURATION'], 'object'); - - t.end(); -}); diff --git a/test/unit/blocks_operators.js b/test/unit/blocks_operators.js new file mode 100644 index 000000000..f7befa063 --- /dev/null +++ b/test/unit/blocks_operators.js @@ -0,0 +1,175 @@ +var test = require('tap').test; +var Operators = require('../../src/blocks/scratch3_operators'); + +var blocks = new Operators(null); + +test('getPrimitives', function (t) { + t.type(blocks.getPrimitives(), 'object'); + t.end(); +}); + +test('add', function (t) { + t.strictEqual(blocks.add({NUM1:'1', NUM2:'1'}), 2); + t.strictEqual(blocks.add({NUM1:'foo', NUM2:'bar'}), 0); + t.end(); +}); + +test('subtract', function (t) { + t.strictEqual(blocks.subtract({NUM1:'1', NUM2:'1'}), 0); + t.strictEqual(blocks.subtract({NUM1:'foo', NUM2:'bar'}), 0); + t.end(); +}); + +test('multiply', function (t) { + t.strictEqual(blocks.multiply({NUM1:'2', NUM2:'2'}), 4); + t.strictEqual(blocks.multiply({NUM1:'foo', NUM2:'bar'}), 0); + t.end(); +}); + +test('divide', function (t) { + t.strictEqual(blocks.divide({NUM1:'2', NUM2:'2'}), 1); + t.strictEqual(blocks.divide({NUM1:'1', NUM2:'0'}), Infinity); // @todo + t.ok(isNaN(blocks.divide({NUM1:'foo', NUM2:'bar'}))); // @todo + t.end(); +}); + +test('lt', function (t) { + t.strictEqual(blocks.lt({OPERAND1:'1', OPERAND2:'2'}), true); + t.strictEqual(blocks.lt({OPERAND1:'2', OPERAND2:'1'}), false); + t.strictEqual(blocks.lt({OPERAND1:'1', OPERAND2:'1'}), false); + t.end(); +}); + +test('equals', function (t) { + t.strictEqual(blocks.equals({OPERAND1:'1', OPERAND2:'2'}), false); + t.strictEqual(blocks.equals({OPERAND1:'2', OPERAND2:'1'}), false); + t.strictEqual(blocks.equals({OPERAND1:'1', OPERAND2:'1'}), true); + t.end(); +}); + +test('gt', function (t) { + t.strictEqual(blocks.gt({OPERAND1:'1', OPERAND2:'2'}), false); + t.strictEqual(blocks.gt({OPERAND1:'2', OPERAND2:'1'}), true); + t.strictEqual(blocks.gt({OPERAND1:'1', OPERAND2:'1'}), false); + t.end(); +}); + +test('and', function (t) { + t.strictEqual(blocks.and({OPERAND1:true, OPERAND2:true}), true); + t.strictEqual(blocks.and({OPERAND1:true, OPERAND2:false}), false); + t.strictEqual(blocks.and({OPERAND1:false, OPERAND2:false}), false); + t.end(); +}); + +test('or', function (t) { + t.strictEqual(blocks.or({OPERAND1:true, OPERAND2:true}), true); + t.strictEqual(blocks.or({OPERAND1:true, OPERAND2:false}), true); + t.strictEqual(blocks.or({OPERAND1:false, OPERAND2:false}), false); + t.end(); +}); + +test('not', function (t) { + t.strictEqual(blocks.not({OPERAND:true}), false); + t.strictEqual(blocks.not({OPERAND:false}), true); + t.end(); +}); + +test('random', function (t) { + var min = 0; + var max = 100; + var result = blocks.random({FROM:min, TO:max}); + t.ok(result >= min); + t.ok(result <= max); + t.end(); +}); + +test('random - equal', function (t) { + var min = 1; + var max = 1; + t.strictEqual(blocks.random({FROM:min, TO:max}), min); + t.end(); +}); + +test('random - decimal', function (t) { + var min = 0.1; + var max = 10; + var result = blocks.random({FROM:min, TO:max}); + t.ok(result >= min); + t.ok(result <= max); + t.end(); +}); + +test('random - int', function (t) { + var min = 0; + var max = 10; + var result = blocks.random({FROM:min, TO:max}); + t.ok(result >= min); + t.ok(result <= max); + t.end(); +}); + +test('random - reverse', function (t) { + var min = 0; + var max = 10; + var result = blocks.random({FROM:max, TO:min}); + t.ok(result >= min); + t.ok(result <= max); + t.end(); +}); + +test('join', function (t) { + t.strictEqual(blocks.join({STRING1:'foo', STRING2:'bar'}), 'foobar'); + t.strictEqual(blocks.join({STRING1:'1', STRING2:'2'}), '12'); + t.end(); +}); + +test('letterOf', function (t) { + t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:0}), ''); + t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:1}), 'f'); + t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:2}), 'o'); + t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:3}), 'o'); + t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:4}), ''); + t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:'bar'}), ''); + t.end(); +}); + +test('length', function (t) { + t.strictEqual(blocks.length({STRING:''}), 0); + t.strictEqual(blocks.length({STRING:'foo'}), 3); + t.strictEqual(blocks.length({STRING:'1'}), 1); + t.strictEqual(blocks.length({STRING:'100'}), 3); + t.end(); +}); + +test('mod', function (t) { + t.strictEqual(blocks.mod({NUM1:1, NUM2:1}), 0); + t.strictEqual(blocks.mod({NUM1:3, NUM2:6}), 3); + t.strictEqual(blocks.mod({NUM1:-3, NUM2:6}), 3); + t.end(); +}); + +test('round', function (t) { + t.strictEqual(blocks.round({NUM:1}), 1); + t.strictEqual(blocks.round({NUM:1.1}), 1); + t.strictEqual(blocks.round({NUM:1.5}), 2); + t.end(); +}); + +test('mathop', function (t) { + t.strictEqual(blocks.mathop({OPERATOR:'abs', NUM:-1}), 1); + t.strictEqual(blocks.mathop({OPERATOR:'floor', NUM:1.5}), 1); + t.strictEqual(blocks.mathop({OPERATOR:'ceiling', NUM:0.1}), 1); + t.strictEqual(blocks.mathop({OPERATOR:'sqrt', NUM:1}), 1); + t.strictEqual(blocks.mathop({OPERATOR:'sin', NUM:1}), 0.01745240643728351); + t.strictEqual(blocks.mathop({OPERATOR:'cos', NUM:1}), 0.9998476951563913); + t.strictEqual(blocks.mathop({OPERATOR:'tan', NUM:1}), 0.017455064928217585); + t.strictEqual(blocks.mathop({OPERATOR:'asin', NUM:1}), 90); + t.strictEqual(blocks.mathop({OPERATOR:'acos', NUM:1}), 0); + t.strictEqual(blocks.mathop({OPERATOR:'atan', NUM:1}), 45); + t.strictEqual(blocks.mathop({OPERATOR:'ln', NUM:1}), 0); + t.strictEqual(blocks.mathop({OPERATOR:'log', NUM:1}), 0); + t.strictEqual(blocks.mathop({OPERATOR:'e ^', NUM:1}), 2.718281828459045); + t.strictEqual(blocks.mathop({OPERATOR:'10 ^', NUM:1}), 10); + t.strictEqual(blocks.mathop({OPERATOR:'undefined', NUM:1}), 0); + t.end(); +}); diff --git a/test/unit/engine_adapter.js b/test/unit/engine_adapter.js new file mode 100644 index 000000000..19289dacd --- /dev/null +++ b/test/unit/engine_adapter.js @@ -0,0 +1,187 @@ +var test = require('tap').test; +var adapter = require('../../src/engine/adapter'); +var events = require('../fixtures/events.json'); + +test('spec', function (t) { + t.type(adapter, 'function'); + t.end(); +}); + +test('invalid inputs', function(t) { + var nothing = adapter('not an object'); + t.type(nothing, 'undefined'); + nothing = adapter({noxmlproperty:true}); + t.type(nothing, 'undefined'); + t.end(); +}); + +test('create event', function (t) { + var result = adapter(events.create); + + t.ok(Array.isArray(result)); + t.equal(result.length, 2); + + // Outer block + t.type(result[0].id, 'string'); + t.type(result[0].opcode, 'string'); + t.type(result[0].fields, 'object'); + t.type(result[0].inputs, 'object'); + t.type(result[0].inputs['DURATION'], 'object'); + t.type(result[0].topLevel, 'boolean'); + t.equal(result[0].topLevel, true); + + // Enclosed shadow block + t.type(result[1].id, 'string'); + t.type(result[1].opcode, 'string'); + t.type(result[1].fields, 'object'); + t.type(result[1].inputs, 'object'); + t.type(result[1].fields['NUM'], 'object'); + t.type(result[1].fields['NUM'].value, '10'); + t.type(result[1].topLevel, 'boolean'); + t.equal(result[1].topLevel, false); + + t.end(); +}); + +test('create with branch', function (t) { + var result = adapter(events.createbranch); + // Outer block + t.type(result[0].id, 'string'); + t.type(result[0].opcode, 'string'); + t.type(result[0].fields, 'object'); + t.type(result[0].inputs, 'object'); + t.type(result[0].inputs['SUBSTACK'], 'object'); + t.type(result[0].topLevel, 'boolean'); + t.equal(result[0].topLevel, true); + // In branch + var branchBlockId = result[0].inputs['SUBSTACK']['block']; + var branchShadowId = result[0].inputs['SUBSTACK']['shadow']; + t.type(branchBlockId, 'string'); + t.equal(branchShadowId, null); + // Find actual branch block + var branchBlock = null; + for (var i = 0; i < result.length; i++) { + if (result[i].id == branchBlockId) { + branchBlock = result[i]; + } + } + t.type(branchBlock, 'object'); + t.end(); +}); + +test('create with two branches', function (t) { + var result = adapter(events.createtwobranches); + // Outer block + t.type(result[0].id, 'string'); + t.type(result[0].opcode, 'string'); + t.type(result[0].fields, 'object'); + t.type(result[0].inputs, 'object'); + t.type(result[0].inputs['SUBSTACK'], 'object'); + t.type(result[0].inputs['SUBSTACK2'], 'object'); + t.type(result[0].topLevel, 'boolean'); + t.equal(result[0].topLevel, true); + // In branchs + var firstBranchBlockId = result[0].inputs['SUBSTACK']['block']; + var secondBranchBlockId = result[0].inputs['SUBSTACK2']['block']; + t.type(firstBranchBlockId, 'string'); + t.type(secondBranchBlockId, 'string'); + var firstBranchShadowBlockId = result[0].inputs['SUBSTACK']['shadow']; + var secondBranchShadowBlockId = result[0].inputs['SUBSTACK2']['shadow']; + t.equal(firstBranchShadowBlockId, null); + t.equal(secondBranchShadowBlockId, null); + // Find actual branch blocks + var firstBranchBlock = null; + var secondBranchBlock = null; + for (var i = 0; i < result.length; i++) { + if (result[i].id == firstBranchBlockId) { + firstBranchBlock = result[i]; + } + if (result[i].id == secondBranchBlockId) { + secondBranchBlock = result[i]; + } + } + t.type(firstBranchBlock, 'object'); + t.type(secondBranchBlock, 'object'); + t.end(); +}); + +test('create with top-level shadow', function (t) { + var result = adapter(events.createtoplevelshadow); + t.ok(Array.isArray(result)); + t.equal(result.length, 1); + + // Outer block + t.type(result[0].id, 'string'); + t.type(result[0].opcode, 'string'); + t.type(result[0].fields, 'object'); + t.type(result[0].inputs, 'object'); + t.type(result[0].topLevel, 'boolean'); + t.equal(result[0].topLevel, true); + t.end(); +}); + +test('create with next connection', function (t) { + var result = adapter(events.createwithnext); + + t.ok(Array.isArray(result)); + t.equal(result.length, 2); + + // First block + t.type(result[0].id, 'string'); + t.type(result[0].opcode, 'string'); + t.type(result[0].fields, 'object'); + t.type(result[0].inputs, 'object'); + t.type(result[0].topLevel, 'boolean'); + t.equal(result[0].topLevel, true); + t.type(result[0].next, 'string'); + t.equal(result[0].next, result[1].id); + + // Second block + t.type(result[1].id, 'string'); + t.type(result[1].opcode, 'string'); + t.type(result[1].fields, 'object'); + t.type(result[1].inputs, 'object'); + t.type(result[1].topLevel, 'boolean'); + t.equal(result[1].topLevel, false); + t.equal(result[1].next, null); + + t.end(); +}); + +test('create with obscured shadow', function (t) { + var result = adapter(events.createobscuredshadow); + t.ok(Array.isArray(result)); + t.equal(result.length, 4); + t.end(); +}); + +test('create with invalid block xml', function (t) { + // Entirely invalid block XML + var result = adapter(events.createinvalid); + t.ok(Array.isArray(result)); + t.equal(result.length, 0); + + // Invalid grandchild tag + var result2 = adapter(events.createinvalidgrandchild); + t.ok(Array.isArray(result2)); + t.equal(result2.length, 1); + t.type(result2[0].id, 'string'); + t.equal(Object.keys(result2[0].inputs).length, 0); + t.equal(Object.keys(result2[0].fields).length, 0); + + t.end(); +}); + +test('create with invalid xml', function (t) { + var result = adapter(events.createbadxml); + t.ok(Array.isArray(result)); + t.equal(result.length, 0); + t.end(); +}); + +test('create with empty field', function (t) { + var result = adapter(events.createemptyfield); + t.ok(Array.isArray(result)); + t.equal(result.length, 3); + t.end(); +}); diff --git a/test/unit/engine_blocks.js b/test/unit/engine_blocks.js new file mode 100644 index 000000000..2c9f8f13e --- /dev/null +++ b/test/unit/engine_blocks.js @@ -0,0 +1,544 @@ +var test = require('tap').test; +var Blocks = require('../../src/engine/blocks'); + +test('spec', function (t) { + var b = new Blocks(); + + t.type(Blocks, 'function'); + t.type(b, 'object'); + t.ok(b instanceof Blocks); + + t.type(b._blocks, 'object'); + t.type(b._scripts, 'object'); + t.ok(Array.isArray(b._scripts)); + + t.type(b.createBlock, 'function'); + t.type(b.moveBlock, 'function'); + t.type(b.changeBlock, 'function'); + t.type(b.deleteBlock, 'function'); + t.type(b.getBlock, 'function'); + t.type(b.getScripts, 'function'); + t.type(b.getNextBlock, 'function'); + t.type(b.getBranch, 'function'); + t.type(b.getOpcode, 'function'); + + + t.end(); +}); + +// Getter tests +test('getBlock', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + var block = b.getBlock('foo'); + t.type(block, 'object'); + var notBlock = b.getBlock('?'); + t.type(notBlock, 'undefined'); + t.end(); +}); + +test('getScripts', function (t) { + var b = new Blocks(); + var scripts = b.getScripts(); + t.type(scripts, 'object'); + t.equals(scripts.length, 0); + // Create two top-level blocks and one not. + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + b.createBlock({ + id: 'foo2', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + b.createBlock({ + id: 'foo3', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: false + }); + + scripts = b.getScripts(); + t.type(scripts, 'object'); + t.equals(scripts.length, 2); + t.ok(scripts.indexOf('foo') > -1); + t.ok(scripts.indexOf('foo2') > -1); + t.equals(scripts.indexOf('foo3'), -1); + t.end(); + +}); + +test('getNextBlock', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + + var next = b.getNextBlock('foo'); + t.equals(next, null); + + // Add a block with "foo" as its next. + b.createBlock({ + id: 'foo2', + opcode: 'TEST_BLOCK', + next: 'foo', + fields: {}, + inputs: {}, + topLevel: true + }); + + next = b.getNextBlock('foo2'); + t.equals(next, 'foo'); + + // Block that doesn't exist. + var noBlock = b.getNextBlock('?'); + t.equals(noBlock, null); + + t.end(); +}); + +test('getBranch', function (t) { + var b = new Blocks(); + // Single branch + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: { + SUBSTACK: { + name: 'SUBSTACK', + block: 'foo2', + shadow: null + } + }, + topLevel: true + }); + b.createBlock({ + id: 'foo2', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: false + }); + + var branch = b.getBranch('foo'); + t.equals(branch, 'foo2'); + + var notBranch = b.getBranch('?'); + t.equals(notBranch, null); + + t.end(); +}); + +test('getBranch2', function (t) { + var b = new Blocks(); + // Second branch + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: { + SUBSTACK: { + name: 'SUBSTACK', + block: 'foo2', + shadow: null + }, + SUBSTACK2: { + name: 'SUBSTACK2', + block: 'foo3', + shadow: null + } + }, + topLevel: true + }); + b.createBlock({ + id: 'foo2', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: false + }); + b.createBlock({ + id: 'foo3', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: false + }); + + var branch1 = b.getBranch('foo', 1); + var branch2 = b.getBranch('foo', 2); + t.equals(branch1, 'foo2'); + t.equals(branch2, 'foo3'); + + t.end(); +}); + +test('getBranch with none', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + var noBranch = b.getBranch('foo'); + t.equals(noBranch, null); + t.end(); +}); + +test('getOpcode', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + var opcode = b.getOpcode('foo'); + t.equals(opcode, 'TEST_BLOCK'); + var notOpcode = b.getOpcode('?'); + t.equals(notOpcode, null); + t.end(); +}); + +// Block events tests +test('create', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + + t.type(b._blocks['foo'], 'object'); + t.equal(b._blocks['foo'].opcode, 'TEST_BLOCK'); + t.notEqual(b._scripts.indexOf('foo'), -1); + t.end(); +}); + +test('move', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + b.createBlock({ + id: 'bar', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + + // Attach 'bar' to the end of 'foo' + b.moveBlock({ + id: 'bar', + newParent: 'foo' + }); + t.equal(b._scripts.length, 1); + t.equal(Object.keys(b._blocks).length, 2); + t.equal(b._blocks['foo'].next, 'bar'); + + // Detach 'bar' from 'foo' + b.moveBlock({ + id: 'bar', + oldParent: 'foo' + }); + t.equal(b._scripts.length, 2); + t.equal(Object.keys(b._blocks).length, 2); + t.equal(b._blocks['foo'].next, null); + + t.end(); +}); + +test('move into empty', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + b.createBlock({ + id: 'bar', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + b.moveBlock({ + id: 'bar', + newInput: 'fooInput', + newParent: 'foo' + }); + t.equal(b._blocks['foo'].inputs['fooInput'].block, 'bar'); + t.end(); +}); + +test('move no obscure shadow', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: { + 'fooInput': { + name: 'fooInput', + block: 'x', + shadow: 'y' + } + }, + topLevel: true + }); + b.createBlock({ + id: 'bar', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + b.moveBlock({ + id: 'bar', + newInput: 'fooInput', + newParent: 'foo' + }); + t.equal(b._blocks['foo'].inputs['fooInput'].block, 'bar'); + t.equal(b._blocks['foo'].inputs['fooInput'].shadow, 'y'); + t.end(); +}); + +test('change', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: { + someField: { + name: 'someField', + value: 'initial-value' + } + }, + inputs: {}, + topLevel: true + }); + + // Test that the field is updated + t.equal(b._blocks['foo'].fields.someField.value, 'initial-value'); + + b.changeBlock({ + element: 'field', + id: 'foo', + name: 'someField', + value: 'final-value' + }); + + t.equal(b._blocks['foo'].fields.someField.value, 'final-value'); + + // Invalid cases + // No `element` + b.changeBlock({ + id: 'foo', + name: 'someField', + value: 'invalid-value' + }); + t.equal(b._blocks['foo'].fields.someField.value, 'final-value'); + + // No block ID + b.changeBlock({ + element: 'field', + name: 'someField', + value: 'invalid-value' + }); + t.equal(b._blocks['foo'].fields.someField.value, 'final-value'); + + // No such field + b.changeBlock({ + element: 'field', + id: 'foo', + name: 'someWrongField', + value: 'final-value' + }); + t.equal(b._blocks['foo'].fields.someField.value, 'final-value'); + + t.end(); +}); + +test('delete', function (t) { + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: true + }); + b.deleteBlock({ + id: 'foo' + }); + + t.type(b._blocks['foo'], 'undefined'); + t.equal(b._scripts.indexOf('foo'), -1); + t.end(); +}); + +test('delete chain', function (t) { + // Create a chain of connected blocks and delete the top one. + // All of them should be deleted. + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: 'foo2', + fields: {}, + inputs: {}, + topLevel: true + }); + b.createBlock({ + id: 'foo2', + opcode: 'TEST_BLOCK', + next: 'foo3', + fields: {}, + inputs: {}, + topLevel: false + }); + b.createBlock({ + id: 'foo3', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: false + }); + b.deleteBlock({ + id: 'foo' + }); + t.type(b._blocks['foo'], 'undefined'); + t.type(b._blocks['foo2'], 'undefined'); + t.type(b._blocks['foo3'], 'undefined'); + t.equal(b._scripts.indexOf('foo'), -1); + t.equal(Object.keys(b._blocks).length, 0); + t.equal(b._scripts.length, 0); + t.end(); +}); + +test('delete inputs', function (t) { + // Create a block with two inputs, one of which has its own input. + // Delete the block - all of them should be deleted. + var b = new Blocks(); + b.createBlock({ + id: 'foo', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: { + input1: { + name: 'input1', + block: 'foo2', + shadow: 'foo2' + }, + SUBSTACK: { + name: 'SUBSTACK', + block: 'foo3', + shadow: null + } + }, + topLevel: true + }); + b.createBlock({ + id: 'foo2', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: false + }); + b.createBlock({ + id: 'foo5', + opcode: 'TEST_OBSCURED_SHADOW', + next: null, + fields: {}, + inputs: {}, + topLevel: false + }); + b.createBlock({ + id: 'foo3', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: { + subinput: { + name: 'subinput', + block: 'foo4', + shadow: 'foo5' + } + }, + topLevel: false + }); + b.createBlock({ + id: 'foo4', + opcode: 'TEST_BLOCK', + next: null, + fields: {}, + inputs: {}, + topLevel: false + }); + b.deleteBlock({ + id: 'foo' + }); + t.type(b._blocks['foo'], 'undefined'); + t.type(b._blocks['foo2'], 'undefined'); + t.type(b._blocks['foo3'], 'undefined'); + t.type(b._blocks['foo4'], 'undefined'); + t.type(b._blocks['foo5'], 'undefined'); + t.equal(b._scripts.indexOf('foo'), -1); + t.equal(Object.keys(b._blocks).length, 0); + t.equal(b._scripts.length, 0); + t.end(); +}); diff --git a/test/unit/engine_runtime.js b/test/unit/engine_runtime.js new file mode 100644 index 000000000..40757c054 --- /dev/null +++ b/test/unit/engine_runtime.js @@ -0,0 +1,12 @@ +var test = require('tap').test; +var Runtime = require('../../src/engine/runtime'); + +test('spec', function (t) { + var r = new Runtime(); + + t.type(Runtime, 'function'); + t.type(r, 'object'); + t.ok(r instanceof Runtime); + + t.end(); +}); diff --git a/test/unit/sequencer.js b/test/unit/engine_sequencer.js similarity index 100% rename from test/unit/sequencer.js rename to test/unit/engine_sequencer.js diff --git a/test/unit/thread.js b/test/unit/engine_thread.js similarity index 100% rename from test/unit/thread.js rename to test/unit/engine_thread.js diff --git a/test/unit/import_sb2.js b/test/unit/import_sb2.js new file mode 100644 index 000000000..be4d62864 --- /dev/null +++ b/test/unit/import_sb2.js @@ -0,0 +1,88 @@ +var fs = require('fs'); +var path = require('path'); +var test = require('tap').test; + +var clone = require('../../src/sprites/clone'); +var runtime = require('../../src/engine/runtime'); +var sb2 = require('../../src/import/sb2import'); + +test('spec', function (t) { + t.type(sb2, 'function'); + t.end(); +}); + +test('default', function (t) { + // Get SB2 JSON (string) + var uri = path.resolve(__dirname, '../fixtures/default.json'); + var file = fs.readFileSync(uri, 'utf8'); + + // Create runtime instance & load SB2 into it + var rt = new runtime(); + sb2(file, rt); + + // Test + t.type(file, 'string'); + t.type(rt, 'object'); + t.type(rt.targets, 'object'); + + t.ok(rt.targets[0] instanceof clone); + t.type(rt.targets[0].id, 'string'); + t.type(rt.targets[0].blocks, 'object'); + t.type(rt.targets[0].variables, 'object'); + t.type(rt.targets[0].lists, 'object'); + + t.equal(rt.targets[0].isOriginal, true); + t.equal(rt.targets[0].currentCostume, 0); + t.equal(rt.targets[0].isOriginal, true); + t.equal(rt.targets[0].isStage, true); + + t.ok(rt.targets[1] instanceof clone); + t.type(rt.targets[1].id, 'string'); + t.type(rt.targets[1].blocks, 'object'); + t.type(rt.targets[1].variables, 'object'); + t.type(rt.targets[1].lists, 'object'); + + t.equal(rt.targets[1].isOriginal, true); + t.equal(rt.targets[1].currentCostume, 0); + t.equal(rt.targets[1].isOriginal, true); + t.equal(rt.targets[1].isStage, false); + t.end(); +}); + +test('demo', function (t) { + // Get SB2 JSON (string) + var uri = path.resolve(__dirname, '../fixtures/demo.json'); + var file = fs.readFileSync(uri, 'utf8'); + + // Create runtime instance & load SB2 into it + var rt = new runtime(); + sb2(file, rt); + + // Test + t.type(file, 'string'); + t.type(rt, 'object'); + t.type(rt.targets, 'object'); + + t.ok(rt.targets[0] instanceof clone); + t.type(rt.targets[0].id, 'string'); + t.type(rt.targets[0].blocks, 'object'); + t.type(rt.targets[0].variables, 'object'); + t.type(rt.targets[0].lists, 'object'); + + t.equal(rt.targets[0].isOriginal, true); + t.equal(rt.targets[0].currentCostume, 0); + t.equal(rt.targets[0].isOriginal, true); + t.equal(rt.targets[0].isStage, true); + + t.ok(rt.targets[1] instanceof clone); + t.type(rt.targets[1].id, 'string'); + t.type(rt.targets[1].blocks, 'object'); + t.type(rt.targets[1].variables, 'object'); + t.type(rt.targets[1].lists, 'object'); + + t.equal(rt.targets[1].isOriginal, true); + t.equal(rt.targets[1].currentCostume, 0); + t.equal(rt.targets[1].isOriginal, true); + t.equal(rt.targets[1].isStage, false); + t.end(); +}); diff --git a/test/unit/runtime.js b/test/unit/runtime.js deleted file mode 100644 index 0e41ed5be..000000000 --- a/test/unit/runtime.js +++ /dev/null @@ -1,89 +0,0 @@ -var test = require('tap').test; -var Runtime = require('../../src/engine/runtime'); - -test('spec', function (t) { - var r = new Runtime(); - - t.type(Runtime, 'function'); - t.type(r, 'object'); - t.ok(r instanceof Runtime); - - t.type(r.blocks, 'object'); - t.type(r.stacks, 'object'); - t.ok(Array.isArray(r.stacks)); - - t.type(r.createBlock, 'function'); - t.type(r.moveBlock, 'function'); - t.type(r.changeBlock, 'function'); - t.type(r.deleteBlock, 'function'); - - t.end(); -}); - -test('create', function (t) { - var r = new Runtime(); - r.createBlock({ - id: 'foo', - opcode: 'TEST_BLOCK', - next: null, - fields: {} - }); - - t.type(r.blocks['foo'], 'object'); - t.equal(r.blocks['foo'].opcode, 'TEST_BLOCK'); - t.notEqual(r.stacks.indexOf('foo'), -1); - t.end(); -}); - -test('move', function (t) { - var r = new Runtime(); - r.createBlock({ - id: 'foo', - opcode: 'TEST_BLOCK', - next: null, - fields: {} - }); - r.createBlock({ - id: 'bar', - opcode: 'TEST_BLOCK', - next: null, - fields: {} - }); - - // Attach 'bar' to the end of 'foo' - r.moveBlock({ - id: 'bar', - newParent: 'foo' - }); - t.equal(r.stacks.length, 1); - t.equal(Object.keys(r.blocks).length, 2); - t.equal(r.blocks['foo'].next, 'bar'); - - // Detach 'bar' from 'foo' - r.moveBlock({ - id: 'bar', - oldParent: 'foo' - }); - t.equal(r.stacks.length, 2); - t.equal(Object.keys(r.blocks).length, 2); - t.equal(r.blocks['foo'].next, null); - - t.end(); -}); - -test('delete', function (t) { - var r = new Runtime(); - r.createBlock({ - id: 'foo', - opcode: 'TEST_BLOCK', - next: null, - fields: {} - }); - r.deleteBlock({ - id: 'foo' - }); - - t.type(r.blocks['foo'], 'undefined'); - t.equal(r.stacks.indexOf('foo'), -1); - t.end(); -}); diff --git a/test/unit/sprites_clone.js b/test/unit/sprites_clone.js new file mode 100644 index 000000000..246e1b955 --- /dev/null +++ b/test/unit/sprites_clone.js @@ -0,0 +1,13 @@ +var test = require('tap').test; +var Clone = require('../../src/sprites/clone'); +var Sprite = require('../../src/sprites/sprite'); + +test('clone effects', function (t) { + // Create two clones and ensure they have different graphic effect objects. + // Regression test for Github issue #224 + var spr = new Sprite(); + var a = new Clone(spr, null); + var b = new Clone(spr, null); + t.ok(a.effects !== b.effects); + t.end(); +}); diff --git a/test/unit/util_cast.js b/test/unit/util_cast.js new file mode 100644 index 000000000..1d372213e --- /dev/null +++ b/test/unit/util_cast.js @@ -0,0 +1,179 @@ +var test = require('tap').test; +var cast = require('../../src/util/cast'); + +test('toNumber', function (t) { + // Numeric + t.strictEqual(cast.toNumber(0), 0); + t.strictEqual(cast.toNumber(1), 1); + t.strictEqual(cast.toNumber(3.14), 3.14); + + // String + t.strictEqual(cast.toNumber('0'), 0); + t.strictEqual(cast.toNumber('1'), 1); + t.strictEqual(cast.toNumber('3.14'), 3.14); + t.strictEqual(cast.toNumber('0.1e10'), 1000000000); + t.strictEqual(cast.toNumber('foobar'), 0); + + // Boolean + t.strictEqual(cast.toNumber(true), 1); + t.strictEqual(cast.toNumber(false), 0); + t.strictEqual(cast.toNumber('true'), 0); + t.strictEqual(cast.toNumber('false'), 0); + + // Undefined & object + t.strictEqual(cast.toNumber(undefined), 0); + t.strictEqual(cast.toNumber({}), 0); + t.strictEqual(cast.toNumber(NaN), 0); + t.end(); +}); + +test('toBoolean', function (t) { + // Numeric + t.strictEqual(cast.toBoolean(0), false); + t.strictEqual(cast.toBoolean(1), true); + t.strictEqual(cast.toBoolean(3.14), true); + + // String + t.strictEqual(cast.toBoolean('0'), false); + t.strictEqual(cast.toBoolean('1'), true); + t.strictEqual(cast.toBoolean('3.14'), true); + t.strictEqual(cast.toBoolean('0.1e10'), true); + t.strictEqual(cast.toBoolean('foobar'), true); + + // Boolean + t.strictEqual(cast.toBoolean(true), true); + t.strictEqual(cast.toBoolean(false), false); + + // Undefined & object + t.strictEqual(cast.toBoolean(undefined), false); + t.strictEqual(cast.toBoolean({}), true); + t.end(); +}); + +test('toString', function (t) { + // Numeric + t.strictEqual(cast.toString(0), '0'); + t.strictEqual(cast.toString(1), '1'); + t.strictEqual(cast.toString(3.14), '3.14'); + + // String + t.strictEqual(cast.toString('0'), '0'); + t.strictEqual(cast.toString('1'), '1'); + t.strictEqual(cast.toString('3.14'), '3.14'); + t.strictEqual(cast.toString('0.1e10'), '0.1e10'); + t.strictEqual(cast.toString('foobar'), 'foobar'); + + // Boolean + t.strictEqual(cast.toString(true), 'true'); + t.strictEqual(cast.toString(false), 'false'); + + // Undefined & object + t.strictEqual(cast.toString(undefined), 'undefined'); + t.strictEqual(cast.toString({}), '[object Object]'); + t.end(); +}); + +test('toRbgColorList', function (t) { + // Hex (minimal, see "color" util tests) + t.deepEqual(cast.toRgbColorList('#000'), [0,0,0]); + t.deepEqual(cast.toRgbColorList('#000000'), [0,0,0]); + t.deepEqual(cast.toRgbColorList('#fff'), [255,255,255]); + t.deepEqual(cast.toRgbColorList('#ffffff'), [255,255,255]); + + // Decimal (minimal, see "color" util tests) + t.deepEqual(cast.toRgbColorList(0), [0,0,0]); + t.deepEqual(cast.toRgbColorList(1), [0,0,1]); + t.deepEqual(cast.toRgbColorList(16777215), [255,255,255]); + + // Malformed + t.deepEqual(cast.toRgbColorList('ffffff'), [0,0,0]); + t.deepEqual(cast.toRgbColorList('foobar'), [0,0,0]); + t.end(); +}); + +test('compare', function (t) { + // Numeric + t.strictEqual(cast.compare(0, 0), 0); + t.strictEqual(cast.compare(1, 0), 1); + t.strictEqual(cast.compare(0, 1), -1); + t.strictEqual(cast.compare(1, 1), 0); + + // String + t.strictEqual(cast.compare('0', '0'), 0); + t.strictEqual(cast.compare('0.1e10', '1000000000'), 0); + t.strictEqual(cast.compare('foobar', 'FOOBAR'), 0); + t.ok(cast.compare('dog', 'cat') > 0); + + // Boolean + t.strictEqual(cast.compare(true, true), 0); + t.strictEqual(cast.compare(true, false), 1); + t.strictEqual(cast.compare(false, true), -1); + t.strictEqual(cast.compare(true, true), 0); + + // Undefined & object + t.strictEqual(cast.compare(undefined, undefined), 0); + t.strictEqual(cast.compare(undefined, 'undefined'), 0); + t.strictEqual(cast.compare({}, {}), 0); + t.strictEqual(cast.compare({}, '[object Object]'), 0); + t.end(); +}); + +test('isInt', function (t) { + // Numeric + t.strictEqual(cast.isInt(0), true); + t.strictEqual(cast.isInt(1), true); + t.strictEqual(cast.isInt(0.0), true); + t.strictEqual(cast.isInt(3.14), false); + t.strictEqual(cast.isInt(NaN), true); + + // String + t.strictEqual(cast.isInt('0'), true); + t.strictEqual(cast.isInt('1'), true); + t.strictEqual(cast.isInt('0.0'), false); + t.strictEqual(cast.isInt('0.1e10'), false); + t.strictEqual(cast.isInt('3.14'), false); + + // Boolean + t.strictEqual(cast.isInt(true), true); + t.strictEqual(cast.isInt(false), true); + + // Undefined & object + t.strictEqual(cast.isInt(undefined), false); + t.strictEqual(cast.isInt({}), false); + t.end(); +}); + +test('toListIndex', function (t) { + var list = [0,1,2,3,4,5]; + var empty = []; + + // Valid + t.strictEqual(cast.toListIndex(1, list.length), 1); + t.strictEqual(cast.toListIndex(6, list.length), 6); + + // Invalid + t.strictEqual(cast.toListIndex(-1, list.length), cast.LIST_INVALID); + t.strictEqual(cast.toListIndex(0.1, list.length), cast.LIST_INVALID); + t.strictEqual(cast.toListIndex(0, list.length), cast.LIST_INVALID); + t.strictEqual(cast.toListIndex(7, list.length), cast.LIST_INVALID); + + // "all" + t.strictEqual(cast.toListIndex('all', list.length), cast.LIST_ALL); + + // "last" + t.strictEqual(cast.toListIndex('last', list.length), list.length); + t.strictEqual(cast.toListIndex('last', empty.length), cast.LIST_INVALID); + + // "random" + var random = cast.toListIndex('random', list.length); + t.ok(random <= list.length); + t.ok(random > 0); + t.strictEqual(cast.toListIndex('random', empty.length), cast.LIST_INVALID); + + // "any" (alias for "random") + var any = cast.toListIndex('any', list.length); + t.ok(any <= list.length); + t.ok(any > 0); + t.strictEqual(cast.toListIndex('any', empty.length), cast.LIST_INVALID); + t.end(); +}); diff --git a/test/unit/util_color.js b/test/unit/util_color.js new file mode 100644 index 000000000..ba7fa059c --- /dev/null +++ b/test/unit/util_color.js @@ -0,0 +1,62 @@ +var test = require('tap').test; +var color = require('../../src/util/color'); + +test('decimalToHex', function (t) { + t.strictEqual(color.decimalToHex(0), '#000000'); + t.strictEqual(color.decimalToHex(1), '#000001'); + t.strictEqual(color.decimalToHex(16777215), '#ffffff'); + t.strictEqual(color.decimalToHex(-16777215), '#000001'); + t.strictEqual(color.decimalToHex(99999999), '#5f5e0ff'); + t.end(); +}); + +test('decimalToRgb', function (t) { + t.deepEqual(color.decimalToRgb(0), {r:0,g:0,b:0}); + t.deepEqual(color.decimalToRgb(1), {r:0,g:0,b:1}); + t.deepEqual(color.decimalToRgb(16777215), {r:255,g:255,b:255}); + t.deepEqual(color.decimalToRgb(-16777215), {r:0,g:0,b:1}); + t.deepEqual(color.decimalToRgb(99999999), {r:245,g:224,b:255}); + t.end(); +}); + +test('hexToRgb', function (t) { + t.deepEqual(color.hexToRgb('#000'), {r:0,g:0,b:0}); + t.deepEqual(color.hexToRgb('#000000'), {r:0,g:0,b:0}); + t.deepEqual(color.hexToRgb('#fff'), {r:255,g:255,b:255}); + t.deepEqual(color.hexToRgb('#ffffff'), {r:255,g:255,b:255}); + t.deepEqual(color.hexToRgb('#0fa'), {r:0,g:255,b:170}); + t.deepEqual(color.hexToRgb('#00ffaa'), {r:0,g:255,b:170}); + + t.deepEqual(color.hexToRgb('000'), {r:0,g:0,b:0}); + t.deepEqual(color.hexToRgb('fff'), {r:255,g:255,b:255}); + t.deepEqual(color.hexToRgb('00ffaa'), {r:0,g:255,b:170}); + + t.deepEqual(color.hexToRgb('0'), null); + t.deepEqual(color.hexToRgb('hello world'), null); + + t.end(); +}); + +test('rgbToHex', function (t) { + t.strictEqual(color.rgbToHex({r:0,g:0,b:0}), '#000000'); + t.strictEqual(color.rgbToHex({r:255,g:255,b:255}), '#ffffff'); + t.strictEqual(color.rgbToHex({r:0,g:255,b:170}), '#00ffaa'); + t.end(); +}); + +test('rgbToDecimal', function (t) { + t.strictEqual(color.rgbToDecimal({r:0,g:0,b:0}), 0); + t.strictEqual(color.rgbToDecimal({r:255,g:255,b:255}), 16777215); + t.strictEqual(color.rgbToDecimal({r:0,g:255,b:170}), 65450); + t.end(); +}); + +test('hexToDecimal', function (t) { + t.strictEqual(color.hexToDecimal('#000'), 0); + t.strictEqual(color.hexToDecimal('#000000'), 0); + t.strictEqual(color.hexToDecimal('#fff'), 16777215); + t.strictEqual(color.hexToDecimal('#ffffff'), 16777215); + t.strictEqual(color.hexToDecimal('#0fa'), 65450); + t.strictEqual(color.hexToDecimal('#00ffaa'), 65450); + t.end(); +}); diff --git a/test/unit/util_math.js b/test/unit/util_math.js new file mode 100644 index 000000000..b198ef1d3 --- /dev/null +++ b/test/unit/util_math.js @@ -0,0 +1,36 @@ +var test = require('tap').test; +var math = require('../../src/util/math-util'); + +test('degToRad', function (t) { + t.strictEqual(math.degToRad(0), 0); + t.strictEqual(math.degToRad(1), 0.017453292519943295); + t.strictEqual(math.degToRad(180), Math.PI); + t.strictEqual(math.degToRad(360), 2 * Math.PI); + t.strictEqual(math.degToRad(720), 4 * Math.PI); + t.end(); +}); + +test('radToDeg', function (t) { + t.strictEqual(math.radToDeg(0), 0); + t.strictEqual(math.radToDeg(1), 57.29577951308232); + t.strictEqual(math.radToDeg(180), 10313.240312354817); + t.strictEqual(math.radToDeg(360), 20626.480624709635); + t.strictEqual(math.radToDeg(720), 41252.96124941927); + t.end(); +}); + +test('clamp', function (t) { + t.strictEqual(math.clamp(0, 0, 10), 0); + t.strictEqual(math.clamp(1, 0, 10), 1); + t.strictEqual(math.clamp(-10, 0, 10), 0); + t.strictEqual(math.clamp(100, 0, 10), 10); + t.end(); +}); + +test('wrapClamp', function (t) { + t.strictEqual(math.wrapClamp(0, 0, 10), 0); + t.strictEqual(math.wrapClamp(1, 0, 10), 1); + t.strictEqual(math.wrapClamp(-10, 0, 10), 1); + t.strictEqual(math.wrapClamp(100, 0, 10), 1); + t.end(); +}); diff --git a/test/unit/timer.js b/test/unit/util_timer.js similarity index 100% rename from test/unit/timer.js rename to test/unit/util_timer.js diff --git a/test/unit/util_xml.js b/test/unit/util_xml.js new file mode 100644 index 000000000..1906a2ab6 --- /dev/null +++ b/test/unit/util_xml.js @@ -0,0 +1,9 @@ +var test = require('tap').test; +var xml = require('../../src/util/xml-escape'); + +test('escape', function (t) { + var input = '<foo bar="he & llo \'"></foo>'; + var output = '<foo bar="he & llo '"></foo>'; + t.strictEqual(xml(input), output); + t.end(); +}); diff --git a/vm.js b/vm.js deleted file mode 100644 index fb2523c87..000000000 --- a/vm.js +++ /dev/null @@ -1,13805 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - var EventEmitter = __webpack_require__(1); - var util = __webpack_require__(2); - - var Runtime = __webpack_require__(6); - var adapter = __webpack_require__(13); - - /** - * Handles connections between blocks, stage, and extensions. - * - * @author Andrew Sliwinski <ascii@media.mit.edu> - */ - function VirtualMachine () { - var instance = this; - - // Bind event emitter and runtime to VM instance - // @todo Post message (Web Worker) polyfill - EventEmitter.call(instance); - instance.runtime = new Runtime(); - - /** - * Event listener for blocks. Handles validation and serves as a generic - * adapter between the blocks and the runtime interface. - * - * @param {Object} Blockly "block" event - */ - instance.blockListener = function (e) { - // Validate event - if (typeof e !== 'object') return; - if (typeof e.blockId !== 'string') return; - - // Blocks - switch (e.type) { - case 'create': - instance.runtime.createBlock(adapter(e), false); - break; - case 'change': - instance.runtime.changeBlock({ - id: e.blockId, - element: e.element, - name: e.name, - value: e.newValue - }); - break; - case 'move': - instance.runtime.moveBlock({ - id: e.blockId, - oldParent: e.oldParentId, - oldField: e.oldInputName, - newParent: e.newParentId, - newField: e.newInputName - }); - break; - case 'delete': - instance.runtime.deleteBlock({ - id: e.blockId - }); - break; - } - }; - - instance.flyoutBlockListener = function (e) { - switch (e.type) { - case 'create': - instance.runtime.createBlock(adapter(e), true); - break; - case 'change': - instance.runtime.changeBlock({ - id: e.blockId, - element: e.element, - name: e.name, - value: e.newValue - }); - break; - case 'delete': - instance.runtime.deleteBlock({ - id: e.blockId - }); - break; - } - }; - } - - /** - * Inherit from EventEmitter - */ - util.inherits(VirtualMachine, EventEmitter); - - /** - * Export and bind to `window` - */ - module.exports = VirtualMachine; - if (typeof window !== 'undefined') window.VirtualMachine = module.exports; - - -/***/ }, -/* 1 */ -/***/ function(module, exports) { - - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; - } - module.exports = EventEmitter; - - // Backwards-compat with node 0.10.x - EventEmitter.EventEmitter = EventEmitter; - - EventEmitter.prototype._events = undefined; - EventEmitter.prototype._maxListeners = undefined; - - // By default EventEmitters will print a warning if more than 10 listeners are - // added to it. This is a useful default which helps finding memory leaks. - EventEmitter.defaultMaxListeners = 10; - - // Obviously not all Emitters should be limited to 10. This function allows - // that to be increased. Set to zero for unlimited. - EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; - }; - - EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } - throw TypeError('Uncaught, unspecified "error" event.'); - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - } else if (isObject(handler)) { - args = Array.prototype.slice.call(arguments, 1); - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; - }; - - EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; - }; - - EventEmitter.prototype.on = EventEmitter.prototype.addListener; - - EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; - }; - - // emits a 'removeListener' event iff the listener was removed - EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; - }; - - EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; - }; - - EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; - }; - - EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - - if (isFunction(evlistener)) - return 1; - else if (evlistener) - return evlistener.length; - } - return 0; - }; - - EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); - }; - - function isFunction(arg) { - return typeof arg === 'function'; - } - - function isNumber(arg) { - return typeof arg === 'number'; - } - - function isObject(arg) { - return typeof arg === 'object' && arg !== null; - } - - function isUndefined(arg) { - return arg === void 0; - } - - -/***/ }, -/* 2 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - var formatRegExp = /%[sdj%]/g; - exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; - }; - - - // Mark that a method should not be used. - // Returns a modified function which warns once by default. - // If --no-deprecation is set, then it is a no-op. - exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } - - if (process.noDeprecation === true) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - - return deprecated; - }; - - - var debugs = {}; - var debugEnviron; - exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; - }; - - - /** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ - /* legacy: obj, showHidden, depth, colors*/ - function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); - } - exports.inspect = inspect; - - - // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics - inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] - }; - - // Don't use 'blue' not visible on cmd.exe - inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' - }; - - - function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } - } - - - function stylizeNoColor(str, styleType) { - return str; - } - - - function arrayToHash(array) { - var hash = {}; - - array.forEach(function(val, idx) { - hash[val] = true; - }); - - return hash; - } - - - function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); - } - - - function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); - } - - - function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; - } - - - function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; - } - - - function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; - } - - - function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; - } - - - // NOTE: These type checking functions intentionally don't use `instanceof` - // because it is fragile and can be easily faked with `Object.create()`. - function isArray(ar) { - return Array.isArray(ar); - } - exports.isArray = isArray; - - function isBoolean(arg) { - return typeof arg === 'boolean'; - } - exports.isBoolean = isBoolean; - - function isNull(arg) { - return arg === null; - } - exports.isNull = isNull; - - function isNullOrUndefined(arg) { - return arg == null; - } - exports.isNullOrUndefined = isNullOrUndefined; - - function isNumber(arg) { - return typeof arg === 'number'; - } - exports.isNumber = isNumber; - - function isString(arg) { - return typeof arg === 'string'; - } - exports.isString = isString; - - function isSymbol(arg) { - return typeof arg === 'symbol'; - } - exports.isSymbol = isSymbol; - - function isUndefined(arg) { - return arg === void 0; - } - exports.isUndefined = isUndefined; - - function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; - } - exports.isRegExp = isRegExp; - - function isObject(arg) { - return typeof arg === 'object' && arg !== null; - } - exports.isObject = isObject; - - function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; - } - exports.isDate = isDate; - - function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); - } - exports.isError = isError; - - function isFunction(arg) { - return typeof arg === 'function'; - } - exports.isFunction = isFunction; - - function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; - } - exports.isPrimitive = isPrimitive; - - exports.isBuffer = __webpack_require__(4); - - function objectToString(o) { - return Object.prototype.toString.call(o); - } - - - function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); - } - - - var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - - // 26 Feb 16:19:34 - function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); - } - - - // log is just a thin wrapper to console.log that prepends a timestamp - exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); - }; - - - /** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ - exports.inherits = __webpack_require__(5); - - exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; - }; - - function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); - } - - /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(3))) - -/***/ }, -/* 3 */ -/***/ function(module, exports) { - - // shim for using process in browser - - var process = module.exports = {}; - var queue = []; - var draining = false; - var currentQueue; - var queueIndex = -1; - - function cleanUpNextTick() { - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } - } - - function drainQueue() { - if (draining) { - return; - } - var timeout = setTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - clearTimeout(timeout); - } - - process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - setTimeout(drainQueue, 0); - } - }; - - // v8 likes predictible objects - function Item(fun, array) { - this.fun = fun; - this.array = array; - } - Item.prototype.run = function () { - this.fun.apply(null, this.array); - }; - process.title = 'browser'; - process.browser = true; - process.env = {}; - process.argv = []; - process.version = ''; // empty string to avoid regexp issues - process.versions = {}; - - function noop() {} - - process.on = noop; - process.addListener = noop; - process.once = noop; - process.off = noop; - process.removeListener = noop; - process.removeAllListeners = noop; - process.emit = noop; - - process.binding = function (name) { - throw new Error('process.binding is not supported'); - }; - - process.cwd = function () { return '/' }; - process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); - }; - process.umask = function() { return 0; }; - - -/***/ }, -/* 4 */ -/***/ function(module, exports) { - - module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; - } - -/***/ }, -/* 5 */ -/***/ function(module, exports) { - - if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; - } else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } - } - - -/***/ }, -/* 6 */ -/***/ function(module, exports, __webpack_require__) { - - var EventEmitter = __webpack_require__(1); - var Sequencer = __webpack_require__(7); - var Thread = __webpack_require__(9); - var util = __webpack_require__(2); - - var defaultBlockPackages = { - 'scratch3': __webpack_require__(11), - 'wedo2': __webpack_require__(12) - }; - - /** - * Manages blocks, stacks, and the sequencer. - */ - function Runtime () { - // Bind event emitter - EventEmitter.call(this); - - // State for the runtime - /** - * All blocks in the workspace. - * Keys are block IDs, values are metadata about the block. - * @type {Object.<string, Object>} - */ - this.blocks = {}; - - /** - * All stacks in the workspace. - * A list of block IDs that represent stacks (first block in stack). - * @type {Array.<String>} - */ - this.stacks = []; - - /** - * A list of threads that are currently running in the VM. - * Threads are added when execution starts and pruned when execution ends. - * @type {Array.<Thread>} - */ - this.threads = []; - - /** @type {!Sequencer} */ - this.sequencer = new Sequencer(this); - - /** - * Map to look up a block primitive's implementation function by its opcode. - * This is a two-step lookup: package name first, then primitive name. - * @type {Object.<string, Function>} - */ - this._primitives = {}; - this._registerBlockPackages(); - } - - /** - * Event name for glowing a stack - * @const {string} - */ - Runtime.STACK_GLOW_ON = 'STACK_GLOW_ON'; - - /** - * Event name for unglowing a stack - * @const {string} - */ - Runtime.STACK_GLOW_OFF = 'STACK_GLOW_OFF'; - - /** - * Event name for glowing a block - * @const {string} - */ - Runtime.BLOCK_GLOW_ON = 'BLOCK_GLOW_ON'; - - /** - * Event name for unglowing a block - * @const {string} - */ - Runtime.BLOCK_GLOW_OFF = 'BLOCK_GLOW_OFF'; - - /** - * Inherit from EventEmitter - */ - util.inherits(Runtime, EventEmitter); - - /** - * How rapidly we try to step threads, in ms. - */ - Runtime.THREAD_STEP_INTERVAL = 1000 / 30; - - /** - * Block management: create blocks and stacks from a `create` event - * @param {!Object} block Blockly create event to be processed - */ - Runtime.prototype.createBlock = function (block, opt_isFlyoutBlock) { - // Create new block - this.blocks[block.id] = block; - - // Walk each field and add any shadow blocks - // @todo Expand this to cover vertical / nested blocks - for (var i in block.fields) { - var shadows = block.fields[i].blocks; - for (var y in shadows) { - var shadow = shadows[y]; - this.blocks[shadow.id] = shadow; - } - } - - // Push block id to stacks array. New blocks are always a stack even if only - // momentary. If the new block is added to an existing stack this stack will - // be removed by the `moveBlock` method below. - if (!opt_isFlyoutBlock) { - this.stacks.push(block.id); - } - }; - - /** - * Block management: change block field values - * @param {!Object} args Blockly change event to be processed - */ - Runtime.prototype.changeBlock = function (args) { - // Validate - if (args.element !== 'field') return; - if (typeof this.blocks[args.id] === 'undefined') return; - if (typeof this.blocks[args.id].fields[args.name] === 'undefined') return; - - // Update block value - this.blocks[args.id].fields[args.name].value = args.value; - }; - - /** - * Block management: move blocks from parent to parent - * @param {!Object} e Blockly move event to be processed - */ - Runtime.prototype.moveBlock = function (e) { - var _this = this; - - // Block was removed from parent - if (e.newParent === undefined && e.oldParent !== undefined) { - // Add stack - _this.stacks.push(e.id); - - // Update old parent - if (e.oldField === undefined) { - _this.blocks[e.oldParent].next = null; - } else { - delete _this.blocks[e.oldParent].fields[e.oldField]; - } - } else if (e.newParent !== undefined) { - // Block was moved to a new parent - // Either happens because it was previously parentless - // (e.oldParent === undefined) - // or because a block was moved in front of it. - - // Remove stack - _this._deleteStack(e.id); - - // Update new parent - if (e.newField === undefined) { - _this.blocks[e.newParent].next = e.id; - } else { - _this.blocks[e.newParent].fields[e.newField] = { - name: e.newField, - value: e.id, - blocks: {} - }; - } - } - }; - - /** - * Block management: delete blocks and their associated stacks - * @param {!Object} e Blockly delete event to be processed - */ - Runtime.prototype.deleteBlock = function (e) { - // @todo Stop threads running on this stack - - // Get block - var block = this.blocks[e.id]; - - // Delete children - if (block.next !== null) { - this.deleteBlock({id: block.next}); - } - - // Delete substacks and fields - for (var field in block.fields) { - if (field === 'SUBSTACK') { - this.deleteBlock({id: block.fields[field].value}); - } else { - for (var shadow in block.fields[field].blocks) { - this.deleteBlock({id: shadow}); - } - } - } - - // Delete stack - this._deleteStack(e.id); - - // Delete block - delete this.blocks[e.id]; - }; - - // ----------------------------------------------------------------------------- - // ----------------------------------------------------------------------------- - - /** - * Register default block packages with this runtime. - * @todo Prefix opcodes with package name. - * @private - */ - Runtime.prototype._registerBlockPackages = function () { - for (var packageName in defaultBlockPackages) { - if (defaultBlockPackages.hasOwnProperty(packageName)) { - // @todo pass a different runtime depending on package privilege? - var packageObject = new (defaultBlockPackages[packageName])(this); - var packageContents = packageObject.getPrimitives(); - for (var op in packageContents) { - if (packageContents.hasOwnProperty(op)) { - this._primitives[op] = - packageContents[op].bind(packageObject); - } - } - } - } - }; - - /** - * Retrieve the function associated with the given opcode. - * @param {!string} opcode The opcode to look up. - * @return {Function} The function which implements the opcode. - */ - Runtime.prototype.getOpcodeFunction = function (opcode) { - return this._primitives[opcode]; - }; - - // ----------------------------------------------------------------------------- - // ----------------------------------------------------------------------------- - - /** - * Create a thread and push it to the list of threads. - * @param {!string} id ID of block that starts the stack - */ - Runtime.prototype._pushThread = function (id) { - this.emit(Runtime.STACK_GLOW_ON, id); - var thread = new Thread(id); - this.threads.push(thread); - }; - - /** - * Remove a thread from the list of threads. - * @param {?Thread} thread Thread object to remove from actives - */ - Runtime.prototype._removeThread = function (thread) { - var i = this.threads.indexOf(thread); - if (i > -1) { - this.emit(Runtime.STACK_GLOW_OFF, thread.topBlock); - this.threads.splice(i, 1); - } - }; - - /** - * Toggle a stack - * @param {!string} stackId ID of block that starts the stack - */ - Runtime.prototype.toggleStack = function (stackId) { - // Remove any existing thread - for (var i = 0; i < this.threads.length; i++) { - if (this.threads[i].topBlock == stackId) { - this._removeThread(this.threads[i]); - return; - } - } - // Otherwise add it - this._pushThread(stackId); - }; - - /** - * Green flag, which stops currently running threads - * and adds all top-level stacks that start with the green flag - */ - Runtime.prototype.greenFlag = function () { - // Remove all existing threads - for (var i = 0; i < this.threads.length; i++) { - this._removeThread(this.threads[i]); - } - // Add all top stacks with green flag - for (var j = 0; j < this.stacks.length; j++) { - var topBlock = this.stacks[j]; - if (this.blocks[topBlock].opcode === 'event_whenflagclicked') { - this._pushThread(this.stacks[j]); - } - } - }; - - /** - * Distance sensor hack - */ - Runtime.prototype.startDistanceSensors = function () { - // Add all top stacks with distance sensor - for (var j = 0; j < this.stacks.length; j++) { - var topBlock = this.stacks[j]; - if (this.blocks[topBlock].opcode === 'wedo_whendistanceclose') { - var alreadyRunning = false; - for (var k = 0; k < this.threads.length; k++) { - if (this.threads[k].topBlock === topBlock) { - alreadyRunning = true; - } - } - if (!alreadyRunning) { - this._pushThread(this.stacks[j]); - } - } - } - }; - - /** - * Stop "everything" - */ - Runtime.prototype.stopAll = function () { - var threadsCopy = this.threads.slice(); - while (threadsCopy.length > 0) { - this._removeThread(threadsCopy.pop()); - } - // @todo call stop function in all extensions/packages/WeDo stub - if (window.native) { - window.native.motorStop(); - } - }; - - /** - * Repeatedly run `sequencer.stepThreads` and filter out - * inactive threads after each iteration. - */ - Runtime.prototype._step = function () { - var inactiveThreads = this.sequencer.stepThreads(this.threads); - for (var i = 0; i < inactiveThreads.length; i++) { - this._removeThread(inactiveThreads[i]); - } - }; - - /** - * Emit feedback for block glowing (used in the sequencer). - * @param {?string} blockId ID for the block to update glow - * @param {boolean} isGlowing True to turn on glow; false to turn off. - */ - Runtime.prototype.glowBlock = function (blockId, isGlowing) { - if (isGlowing) { - this.emit(Runtime.BLOCK_GLOW_ON, blockId); - } else { - this.emit(Runtime.BLOCK_GLOW_OFF, blockId); - } - }; - - /** - * Set up timers to repeatedly step in a browser - */ - Runtime.prototype.start = function () { - if (!window.setInterval) return; - window.setInterval(function() { - this._step(); - }.bind(this), Runtime.THREAD_STEP_INTERVAL); - }; - - // ----------------------------------------------------------------------------- - // ----------------------------------------------------------------------------- - - /** - * Helper to remove a stack from `this.stacks` - * @param {?string} id ID of block that starts the stack - */ - Runtime.prototype._deleteStack = function (id) { - var i = this.stacks.indexOf(id); - if (i > -1) this.stacks.splice(i, 1); - }; - - /** - * Helper to get the next block for a particular block - * @param {?string} id ID of block to get the next block for - * @return {?string} ID of next block in the sequence - */ - Runtime.prototype._getNextBlock = function (id) { - if (typeof this.blocks[id] === 'undefined') return null; - return this.blocks[id].next; - }; - - /** - * Helper to get the substack for a particular C-shaped block - * @param {?string} id ID for block to get the substack for - * @return {?string} ID of block in the substack - */ - Runtime.prototype._getSubstack = function (id) { - if (typeof this.blocks[id] === 'undefined') return null; - return this.blocks[id].fields['SUBSTACK']; - }; - - /** - * Helper to get the opcode for a particular block - * @param {?string} id ID of block to query - * @return {?string} the opcode corresponding to that block - */ - Runtime.prototype._getOpcode = function (id) { - if (typeof this.blocks[id] === 'undefined') return null; - return this.blocks[id].opcode; - }; - - module.exports = Runtime; - - -/***/ }, -/* 7 */ -/***/ function(module, exports, __webpack_require__) { - - var Timer = __webpack_require__(8); - var Thread = __webpack_require__(9); - var YieldTimers = __webpack_require__(10); - - function Sequencer (runtime) { - /** - * A utility timer for timing thread sequencing. - * @type {!Timer} - */ - this.timer = new Timer(); - - /** - * Reference to the runtime owning this sequencer. - * @type {!Runtime} - */ - this.runtime = runtime; - } - - /** - * The sequencer does as much work as it can within WORK_TIME milliseconds, - * then yields. This is essentially a rate-limiter for blocks. - * In Scratch 2.0, this is set to 75% of the target stage frame-rate (30fps). - * @const {!number} - */ - Sequencer.WORK_TIME = 10; - - /** - * Step through all threads in `this.threads`, running them in order. - * @return {Array.<Thread>} All threads which have finished in this iteration. - */ - Sequencer.prototype.stepThreads = function (threads) { - // Start counting toward WORK_TIME - this.timer.start(); - // List of threads which have been killed by this step. - var inactiveThreads = []; - // If all of the threads are yielding, we should yield. - var numYieldingThreads = 0; - // While there are still threads to run and we are within WORK_TIME, - // continue executing threads. - while (threads.length > 0 && - threads.length > numYieldingThreads && - this.timer.timeElapsed() < Sequencer.WORK_TIME) { - // New threads at the end of the iteration. - var newThreads = []; - // Attempt to run each thread one time - for (var i = 0; i < threads.length; i++) { - var activeThread = threads[i]; - if (activeThread.status === Thread.STATUS_RUNNING) { - // Normal-mode thread: step. - this.stepThread(activeThread); - } else if (activeThread.status === Thread.STATUS_YIELD) { - // Yield-mode thread: check if the time has passed. - YieldTimers.resolve(activeThread.yieldTimerId); - numYieldingThreads++; - } else if (activeThread.status === Thread.STATUS_DONE) { - // Moved to a done state - finish up - activeThread.status = Thread.STATUS_RUNNING; - // @todo Deal with the return value - } - // First attempt to pop from the stack - if (activeThread.stack.length > 0 && - activeThread.nextBlock === null && - activeThread.status === Thread.STATUS_DONE) { - activeThread.nextBlock = activeThread.stack.pop(); - // Don't pop stack frame - we need the data. - // A new one won't be created when we execute. - if (activeThread.nextBlock !== null) { - activeThread.status === Thread.STATUS_RUNNING; - } - } - if (activeThread.nextBlock === null && - activeThread.status === Thread.STATUS_DONE) { - // Finished with this thread - tell runtime to clean it up. - inactiveThreads.push(activeThread); - } else { - // Keep this thead in the loop. - newThreads.push(activeThread); - } - } - // Effectively filters out threads that have stopped. - threads = newThreads; - } - return inactiveThreads; - }; - - /** - * Step the requested thread - * @param {!Thread} thread Thread object to step - */ - Sequencer.prototype.stepThread = function (thread) { - // Save the yield timer ID, in case a primitive makes a new one - // @todo hack - perhaps patch this to allow more than one timer per - // primitive, for example... - var oldYieldTimerId = YieldTimers.timerId; - - // Save the current block and set the nextBlock. - // If the primitive would like to do control flow, - // it can overwrite nextBlock. - var currentBlock = thread.nextBlock; - if (!currentBlock || !this.runtime.blocks[currentBlock]) { - thread.status = Thread.STATUS_DONE; - return; - } - thread.nextBlock = this.runtime._getNextBlock(currentBlock); - - var opcode = this.runtime._getOpcode(currentBlock); - - // Push the current block to the stack - thread.stack.push(currentBlock); - // Push an empty stack frame, if we need one. - // Might not, if we just popped the stack. - if (thread.stack.length > thread.stackFrames.length) { - thread.stackFrames.push({}); - } - var currentStackFrame = thread.stackFrames[thread.stackFrames.length - 1]; - - /** - * A callback for the primitive to indicate its thread should yield. - * @type {Function} - */ - var threadYieldCallback = function () { - thread.status = Thread.STATUS_YIELD; - }; - - /** - * A callback for the primitive to indicate its thread is finished - * @type {Function} - */ - var instance = this; - var threadDoneCallback = function () { - thread.status = Thread.STATUS_DONE; - // Refresh nextBlock in case it has changed during a yield. - thread.nextBlock = instance.runtime._getNextBlock(currentBlock); - // Pop the stack and stack frame - thread.stack.pop(); - thread.stackFrames.pop(); - }; - - /** - * A callback for the primitive to start hats. - * @todo very hacked... - */ - var startHats = function(callback) { - for (var i = 0; i < instance.runtime.stacks.length; i++) { - var stack = instance.runtime.stacks[i]; - var stackBlock = instance.runtime.blocks[stack]; - var result = callback(stackBlock); - if (result) { - // Check if the stack is already running - var stackRunning = false; - - for (var j = 0; j < instance.runtime.threads.length; j++) { - if (instance.runtime.threads[j].topBlock == stack) { - stackRunning = true; - break; - } - } - if (!stackRunning) { - instance.runtime._pushThread(stack); - } - } - } - }; - - /** - * Record whether we have switched stack, - * to avoid proceeding the thread automatically. - * @type {boolean} - */ - var switchedStack = false; - /** - * A callback for a primitive to start a substack. - * @type {Function} - */ - var threadStartSubstack = function () { - // Set nextBlock to the start of the substack - var substack = instance.runtime._getSubstack(currentBlock); - if (substack && substack.value) { - thread.nextBlock = substack.value; - } else { - thread.nextBlock = null; - } - switchedStack = true; - }; - - // @todo extreme hack to get the single argument value for prototype - var argValues = []; - var blockInputs = this.runtime.blocks[currentBlock].fields; - for (var bi in blockInputs) { - var outer = blockInputs[bi]; - for (var b in outer.blocks) { - var block = outer.blocks[b]; - var fields = block.fields; - for (var f in fields) { - var field = fields[f]; - argValues.push(field.value); - } - } - } - - if (!opcode) { - console.warn('Could not get opcode for block: ' + currentBlock); - } - else { - var blockFunction = this.runtime.getOpcodeFunction(opcode); - if (!blockFunction) { - console.warn('Could not get implementation for opcode: ' + opcode); - } - else { - try { - // @todo deal with the return value - blockFunction(argValues, { - yield: threadYieldCallback, - done: threadDoneCallback, - timeout: YieldTimers.timeout, - stackFrame: currentStackFrame, - startSubstack: threadStartSubstack, - startHats: startHats - }); - } - catch(e) { - console.error( - 'Exception calling block function for opcode: ' + - opcode + '\n' + e); - } finally { - // Update if the thread has set a yield timer ID - // @todo hack - if (YieldTimers.timerId > oldYieldTimerId) { - thread.yieldTimerId = YieldTimers.timerId; - } - if (thread.status === Thread.STATUS_RUNNING && !switchedStack) { - // Thread executed without yielding - move to done - threadDoneCallback(); - } - } - } - } - - }; - - module.exports = Sequencer; - - -/***/ }, -/* 8 */ -/***/ function(module, exports) { - - /** - * Constructor - */ - function Timer () { - this.startTime = 0; - } - - Timer.prototype.time = function () { - return Date.now(); - }; - - Timer.prototype.start = function () { - this.startTime = this.time(); - }; - - Timer.prototype.timeElapsed = function () { - return this.time() - this.startTime; - }; - - module.exports = Timer; - - -/***/ }, -/* 9 */ -/***/ function(module, exports) { - - /** - * A thread is a running stack context and all the metadata needed. - * @param {?string} firstBlock First block to execute in the thread. - * @constructor - */ - function Thread (firstBlock) { - /** - * ID of top block of the thread - * @type {!string} - */ - this.topBlock = firstBlock; - /** - * ID of next block that the thread will execute, or null if none. - * @type {?string} - */ - this.nextBlock = firstBlock; - /** - * Stack for the thread. When the sequencer enters a control structure, - * the block is pushed onto the stack so we know where to exit. - * @type {Array.<string>} - */ - this.stack = []; - - /** - * Stack frames for the thread. Store metadata for the executing blocks. - * @type {Array.<Object>} - */ - this.stackFrames = []; - - /** - * Status of the thread, one of three states (below) - * @type {number} - */ - this.status = 0; /* Thread.STATUS_RUNNING */ - - /** - * Yield timer ID (for checking when the thread should unyield). - * @type {number} - */ - this.yieldTimerId = -1; - } - - /** - * Thread status for initialized or running thread. - * Threads are in this state when the primitive is called for the first time. - * @const - */ - Thread.STATUS_RUNNING = 0; - - /** - * Thread status for a yielded thread. - * Threads are in this state when a primitive has yielded. - * @const - */ - Thread.STATUS_YIELD = 1; - - /** - * Thread status for a finished/done thread. - * Thread is moved to this state when the interpreter - * can proceed with execution. - * @const - */ - Thread.STATUS_DONE = 2; - - module.exports = Thread; - - -/***/ }, -/* 10 */ -/***/ function(module, exports, __webpack_require__) { - - /** - * @fileoverview Timers that are synchronized with the Scratch sequencer. - */ - var Timer = __webpack_require__(8); - - function YieldTimers () {} - - /** - * Shared collection of timers. - * Each timer is a [Function, number] with the callback - * and absolute time for it to run. - * @type {Object.<number,Array>} - */ - YieldTimers.timers = {}; - - /** - * Monotonically increasing timer ID. - * @type {number} - */ - YieldTimers.timerId = 0; - - /** - * Utility for measuring time. - * @type {!Timer} - */ - YieldTimers.globalTimer = new Timer(); - - /** - * The timeout function is passed to primitives and is intended - * as a convenient replacement for window.setTimeout. - * The sequencer will attempt to resolve the timer every time - * the yielded thread would have been stepped. - * @param {!Function} callback To be called when the timer is done. - * @param {number} timeDelta Time to wait, in ms. - * @return {number} Timer ID to be used with other methods. - */ - YieldTimers.timeout = function (callback, timeDelta) { - var id = ++YieldTimers.timerId; - YieldTimers.timers[id] = [ - callback, - YieldTimers.globalTimer.time() + timeDelta - ]; - return id; - }; - - /** - * Attempt to resolve a timeout. - * If the time has passed, call the callback. - * Otherwise, do nothing. - * @param {number} id Timer ID to resolve. - * @return {boolean} True if the timer has resolved. - */ - YieldTimers.resolve = function (id) { - var timer = YieldTimers.timers[id]; - if (!timer) { - // No such timer. - return false; - } - var callback = timer[0]; - var time = timer[1]; - if (YieldTimers.globalTimer.time() < time) { - // Not done yet. - return false; - } - // Execute the callback and remove the timer. - callback(); - delete YieldTimers.timers[id]; - return true; - }; - - /** - * Reject a timer so the callback never executes. - * @param {number} id Timer ID to reject. - */ - YieldTimers.reject = function (id) { - if (YieldTimers.timers[id]) { - delete YieldTimers.timers[id]; - } - }; - - /** - * Reject all timers currently stored. - * Especially useful for a Scratch "stop." - */ - YieldTimers.rejectAll = function () { - YieldTimers.timers = {}; - YieldTimers.timerId = 0; - }; - - module.exports = YieldTimers; - - -/***/ }, -/* 11 */ -/***/ function(module, exports) { - - function Scratch3Blocks(runtime) { - /** - * The runtime instantiating this block package. - * @type {Runtime} - */ - this.runtime = runtime; - } - - /** - * Retrieve the block primitives implemented by this package. - * @return {Object.<string, Function>} Mapping of opcode to Function. - */ - Scratch3Blocks.prototype.getPrimitives = function() { - return { - 'control_repeat': this.repeat, - 'control_forever': this.forever, - 'control_wait': this.wait, - 'control_stop': this.stop, - 'event_whenflagclicked': this.whenFlagClicked, - 'event_whenbroadcastreceived': this.whenBroadcastReceived, - 'event_broadcast': this.broadcast - }; - }; - - Scratch3Blocks.prototype.repeat = function(argValues, util) { - console.log('Running: control_repeat'); - // Initialize loop - if (util.stackFrame.loopCounter === undefined) { - util.stackFrame.loopCounter = parseInt(argValues[0]); // @todo arg - } - // Decrease counter - util.stackFrame.loopCounter--; - // If we still have some left, start the substack - if (util.stackFrame.loopCounter >= 0) { - util.startSubstack(); - } - }; - - Scratch3Blocks.prototype.forever = function(argValues, util) { - console.log('Running: control_forever'); - util.startSubstack(); - }; - - Scratch3Blocks.prototype.wait = function(argValues, util) { - console.log('Running: control_wait'); - util.yield(); - util.timeout(function() { - util.done(); - }, 1000 * parseFloat(argValues[0])); - }; - - Scratch3Blocks.prototype.stop = function() { - console.log('Running: control_stop'); - // @todo - don't use this.runtime - this.runtime.stopAll(); - }; - - Scratch3Blocks.prototype.whenFlagClicked = function() { - console.log('Running: event_whenflagclicked'); - // No-op - }; - - Scratch3Blocks.prototype.whenBroadcastReceived = function() { - console.log('Running: event_whenbroadcastreceived'); - // No-op - }; - - Scratch3Blocks.prototype.broadcast = function(argValues, util) { - console.log('Running: event_broadcast'); - util.startHats(function(hat) { - if (hat.opcode === 'event_whenbroadcastreceived') { - var shadows = hat.fields.CHOICE.blocks; - for (var sb in shadows) { - var shadowblock = shadows[sb]; - return shadowblock.fields.CHOICE.value === argValues[0]; - } - } - return false; - }); - }; - - module.exports = Scratch3Blocks; - - -/***/ }, -/* 12 */ -/***/ function(module, exports, __webpack_require__) { - - - var YieldTimers = __webpack_require__(10); - - function WeDo2Blocks(runtime) { - /** - * The runtime instantiating this block package. - * @type {Runtime} - */ - this.runtime = runtime; - - /** - * Current motor speed, as a percentage (100 = full speed). - * @type {number} - * @private - */ - this._motorSpeed = 100; - - /** - * The timeout ID for a pending motor action. - * @type {?int} - * @private - */ - this._motorTimeout = null; - } - - /** - * Retrieve the block primitives implemented by this package. - * @return {Object.<string, Function>} Mapping of opcode to Function. - */ - WeDo2Blocks.prototype.getPrimitives = function() { - return { - 'wedo_motorclockwise': this.motorClockwise, - 'wedo_motorcounterclockwise': this.motorCounterClockwise, - 'wedo_motorspeed': this.motorSpeed, - 'wedo_setcolor': this.setColor, - 'wedo_whendistanceclose': this.whenDistanceClose, - 'wedo_whentilt': this.whenTilt - }; - }; - - /** - * Clamp a value between a minimum and maximum value. - * @todo move this to a common utility class. - * @param val The value to clamp. - * @param min The minimum return value. - * @param max The maximum return value. - * @returns {number} The clamped value. - * @private - */ - WeDo2Blocks.prototype._clamp = function(val, min, max) { - return Math.max(min, Math.min(val, max)); - }; - - /** - * Common implementation for motor blocks. - * @param direction The direction to turn ('left' or 'right'). - * @param durationSeconds The number of seconds to run. - * @param util The util instance to use for yielding and finishing. - * @private - */ - WeDo2Blocks.prototype._motorOnFor = function(direction, durationSeconds, util) { - if (this._motorTimeout > 0) { - // @todo maybe this should go through util - YieldTimers.resolve(this._motorTimeout); - this._motorTimeout = null; - } - if (window.native) { - window.native.motorRun(direction, this._motorSpeed); - } - - var instance = this; - var myTimeout = this._motorTimeout = util.timeout(function() { - if (instance._motorTimeout == myTimeout) { - instance._motorTimeout = null; - } - if (window.native) { - window.native.motorStop(); - } - util.done(); - }, 1000 * durationSeconds); - - util.yield(); - }; - - WeDo2Blocks.prototype.motorClockwise = function(argValues, util) { - this._motorOnFor('right', parseFloat(argValues[0]), util); - }; - - WeDo2Blocks.prototype.motorCounterClockwise = function(argValues, util) { - this._motorOnFor('left', parseFloat(argValues[0]), util); - }; - - WeDo2Blocks.prototype.motorSpeed = function(argValues) { - var speed = argValues[0]; - switch (speed) { - case 'slow': - this._motorSpeed = 20; - break; - case 'medium': - this._motorSpeed = 50; - break; - case 'fast': - this._motorSpeed = 100; - break; - } - }; - - /** - * Convert a color name to a WeDo color index. - * Supports 'mystery' for a random hue. - * @param colorName The color to retrieve. - * @returns {number} The WeDo color index. - * @private - */ - WeDo2Blocks.prototype._getColor = function(colorName) { - var colors = { - 'yellow': 7, - 'orange': 8, - 'coral': 9, - 'magenta': 1, - 'purple': 2, - 'blue': 3, - 'green': 6, - 'white': 10 - }; - - if (colorName == 'mystery') { - return Math.floor((Math.random() * 10) + 1); - } - - return colors[colorName]; - }; - - WeDo2Blocks.prototype.setColor = function(argValues, util) { - if (window.native) { - var colorIndex = this._getColor(argValues[0]); - window.native.setLedColor(colorIndex); - } - // Pause for quarter second - util.yield(); - util.timeout(function() { - util.done(); - }, 250); - }; - - WeDo2Blocks.prototype.whenDistanceClose = function() { - console.log('Running: wedo_whendistanceclose'); - }; - - WeDo2Blocks.prototype.whenTilt = function() { - console.log('Running: wedo_whentilt'); - }; - - module.exports = WeDo2Blocks; - - -/***/ }, -/* 13 */ -/***/ function(module, exports, __webpack_require__) { - - var html = __webpack_require__(14); - var memoize = __webpack_require__(65); - var parseDOM = memoize(html.parseDOM, { - length: 1, - resolvers: [String], - max: 200 - }); - - /** - * Adapter between block creation events and block representation which can be - * used by the Scratch runtime. - * - * @param {Object} `Blockly.events.create` - * - * @return {Object} - */ - module.exports = function (e) { - // Validate input - if (typeof e !== 'object') return; - if (typeof e.blockId !== 'string') return; - if (typeof e.xml !== 'object') return; - - // Storage object - var obj = { - id: e.blockId, - opcode: null, - next: null, - fields: {} - }; - - // Set opcode - if (typeof e.xml.attributes === 'object') { - obj.opcode = e.xml.attributes.type.value; - } - - // Extract fields from event's `innerHTML` - if (typeof e.xml.innerHTML !== 'string') return obj; - if (e.xml.innerHTML === '') return obj; - obj.fields = extract(parseDOM(e.xml.innerHTML)); - - return obj; - }; - - /** - * Extracts fields from a block's innerHTML. - * @todo Extend this to support vertical grammar / nested blocks. - * - * @param {Object} DOM representation of block's innerHTML - * - * @return {Object} - */ - function extract (dom) { - // Storage object - var fields = {}; - - // Field - var field = dom[0]; - var fieldName = field.attribs.name; - fields[fieldName] = { - name: fieldName, - value: null, - blocks: {} - }; - - // Shadow block - var shadow = field.children[0]; - var shadowId = shadow.attribs.id; - var shadowOpcode = shadow.attribs.type; - fields[fieldName].blocks[shadowId] = { - id: shadowId, - opcode: shadowOpcode, - next: null, - fields: {} - }; - - // Primitive - var primitive = shadow.children[0]; - var primitiveName = primitive.attribs.name; - var primitiveValue = primitive.children[0].data; - fields[fieldName].blocks[shadowId].fields[primitiveName] = { - name: primitiveName, - value: primitiveValue, - blocks: null - }; - - return fields; - } - - -/***/ }, -/* 14 */ -/***/ function(module, exports, __webpack_require__) { - - var Parser = __webpack_require__(15), - DomHandler = __webpack_require__(22); - - function defineProp(name, value){ - delete module.exports[name]; - module.exports[name] = value; - return value; - } - - module.exports = { - Parser: Parser, - Tokenizer: __webpack_require__(16), - ElementType: __webpack_require__(23), - DomHandler: DomHandler, - get FeedHandler(){ - return defineProp("FeedHandler", __webpack_require__(26)); - }, - get Stream(){ - return defineProp("Stream", __webpack_require__(27)); - }, - get WritableStream(){ - return defineProp("WritableStream", __webpack_require__(28)); - }, - get ProxyHandler(){ - return defineProp("ProxyHandler", __webpack_require__(51)); - }, - get DomUtils(){ - return defineProp("DomUtils", __webpack_require__(52)); - }, - get CollectingHandler(){ - return defineProp("CollectingHandler", __webpack_require__(64)); - }, - // For legacy support - DefaultHandler: DomHandler, - get RssHandler(){ - return defineProp("RssHandler", this.FeedHandler); - }, - //helper methods - parseDOM: function(data, options){ - var handler = new DomHandler(options); - new Parser(handler, options).end(data); - return handler.dom; - }, - parseFeed: function(feed, options){ - var handler = new module.exports.FeedHandler(options); - new Parser(handler, options).end(feed); - return handler.dom; - }, - createDomStream: function(cb, options, elementCb){ - var handler = new DomHandler(cb, options, elementCb); - return new Parser(handler, options); - }, - // List of all events that the parser emits - EVENTS: { /* Format: eventname: number of arguments */ - attribute: 2, - cdatastart: 0, - cdataend: 0, - text: 1, - processinginstruction: 2, - comment: 1, - commentend: 0, - closetag: 1, - opentag: 2, - opentagname: 1, - error: 1, - end: 0 - } - }; - - -/***/ }, -/* 15 */ -/***/ function(module, exports, __webpack_require__) { - - var Tokenizer = __webpack_require__(16); - - /* - Options: - - xmlMode: Disables the special behavior for script/style tags (false by default) - lowerCaseAttributeNames: call .toLowerCase for each attribute name (true if xmlMode is `false`) - lowerCaseTags: call .toLowerCase for each tag name (true if xmlMode is `false`) - */ - - /* - Callbacks: - - oncdataend, - oncdatastart, - onclosetag, - oncomment, - oncommentend, - onerror, - onopentag, - onprocessinginstruction, - onreset, - ontext - */ - - var formTags = { - input: true, - option: true, - optgroup: true, - select: true, - button: true, - datalist: true, - textarea: true - }; - - var openImpliesClose = { - tr : { tr:true, th:true, td:true }, - th : { th:true }, - td : { thead:true, th:true, td:true }, - body : { head:true, link:true, script:true }, - li : { li:true }, - p : { p:true }, - h1 : { p:true }, - h2 : { p:true }, - h3 : { p:true }, - h4 : { p:true }, - h5 : { p:true }, - h6 : { p:true }, - select : formTags, - input : formTags, - output : formTags, - button : formTags, - datalist: formTags, - textarea: formTags, - option : { option:true }, - optgroup: { optgroup:true } - }; - - var voidElements = { - __proto__: null, - area: true, - base: true, - basefont: true, - br: true, - col: true, - command: true, - embed: true, - frame: true, - hr: true, - img: true, - input: true, - isindex: true, - keygen: true, - link: true, - meta: true, - param: true, - source: true, - track: true, - wbr: true, - - //common self closing svg elements - path: true, - circle: true, - ellipse: true, - line: true, - rect: true, - use: true, - stop: true, - polyline: true, - polygon: true - }; - - var re_nameEnd = /\s|\//; - - function Parser(cbs, options){ - this._options = options || {}; - this._cbs = cbs || {}; - - this._tagname = ""; - this._attribname = ""; - this._attribvalue = ""; - this._attribs = null; - this._stack = []; - - this.startIndex = 0; - this.endIndex = null; - - this._lowerCaseTagNames = "lowerCaseTags" in this._options ? - !!this._options.lowerCaseTags : - !this._options.xmlMode; - this._lowerCaseAttributeNames = "lowerCaseAttributeNames" in this._options ? - !!this._options.lowerCaseAttributeNames : - !this._options.xmlMode; - if(!!this._options.Tokenizer) { - Tokenizer = this._options.Tokenizer; - } - this._tokenizer = new Tokenizer(this._options, this); - - if(this._cbs.onparserinit) this._cbs.onparserinit(this); - } - - __webpack_require__(2).inherits(Parser, __webpack_require__(1).EventEmitter); - - Parser.prototype._updatePosition = function(initialOffset){ - if(this.endIndex === null){ - if(this._tokenizer._sectionStart <= initialOffset){ - this.startIndex = 0; - } else { - this.startIndex = this._tokenizer._sectionStart - initialOffset; - } - } - else this.startIndex = this.endIndex + 1; - this.endIndex = this._tokenizer.getAbsoluteIndex(); - }; - - //Tokenizer event handlers - Parser.prototype.ontext = function(data){ - this._updatePosition(1); - this.endIndex--; - - if(this._cbs.ontext) this._cbs.ontext(data); - }; - - Parser.prototype.onopentagname = function(name){ - if(this._lowerCaseTagNames){ - name = name.toLowerCase(); - } - - this._tagname = name; - - if(!this._options.xmlMode && name in openImpliesClose) { - for( - var el; - (el = this._stack[this._stack.length - 1]) in openImpliesClose[name]; - this.onclosetag(el) - ); - } - - if(this._options.xmlMode || !(name in voidElements)){ - this._stack.push(name); - } - - if(this._cbs.onopentagname) this._cbs.onopentagname(name); - if(this._cbs.onopentag) this._attribs = {}; - }; - - Parser.prototype.onopentagend = function(){ - this._updatePosition(1); - - if(this._attribs){ - if(this._cbs.onopentag) this._cbs.onopentag(this._tagname, this._attribs); - this._attribs = null; - } - - if(!this._options.xmlMode && this._cbs.onclosetag && this._tagname in voidElements){ - this._cbs.onclosetag(this._tagname); - } - - this._tagname = ""; - }; - - Parser.prototype.onclosetag = function(name){ - this._updatePosition(1); - - if(this._lowerCaseTagNames){ - name = name.toLowerCase(); - } - - if(this._stack.length && (!(name in voidElements) || this._options.xmlMode)){ - var pos = this._stack.lastIndexOf(name); - if(pos !== -1){ - if(this._cbs.onclosetag){ - pos = this._stack.length - pos; - while(pos--) this._cbs.onclosetag(this._stack.pop()); - } - else this._stack.length = pos; - } else if(name === "p" && !this._options.xmlMode){ - this.onopentagname(name); - this._closeCurrentTag(); - } - } else if(!this._options.xmlMode && (name === "br" || name === "p")){ - this.onopentagname(name); - this._closeCurrentTag(); - } - }; - - Parser.prototype.onselfclosingtag = function(){ - if(this._options.xmlMode || this._options.recognizeSelfClosing){ - this._closeCurrentTag(); - } else { - this.onopentagend(); - } - }; - - Parser.prototype._closeCurrentTag = function(){ - var name = this._tagname; - - this.onopentagend(); - - //self-closing tags will be on the top of the stack - //(cheaper check than in onclosetag) - if(this._stack[this._stack.length - 1] === name){ - if(this._cbs.onclosetag){ - this._cbs.onclosetag(name); - } - this._stack.pop(); - } - }; - - Parser.prototype.onattribname = function(name){ - if(this._lowerCaseAttributeNames){ - name = name.toLowerCase(); - } - this._attribname = name; - }; - - Parser.prototype.onattribdata = function(value){ - this._attribvalue += value; - }; - - Parser.prototype.onattribend = function(){ - if(this._cbs.onattribute) this._cbs.onattribute(this._attribname, this._attribvalue); - if( - this._attribs && - !Object.prototype.hasOwnProperty.call(this._attribs, this._attribname) - ){ - this._attribs[this._attribname] = this._attribvalue; - } - this._attribname = ""; - this._attribvalue = ""; - }; - - Parser.prototype._getInstructionName = function(value){ - var idx = value.search(re_nameEnd), - name = idx < 0 ? value : value.substr(0, idx); - - if(this._lowerCaseTagNames){ - name = name.toLowerCase(); - } - - return name; - }; - - Parser.prototype.ondeclaration = function(value){ - if(this._cbs.onprocessinginstruction){ - var name = this._getInstructionName(value); - this._cbs.onprocessinginstruction("!" + name, "!" + value); - } - }; - - Parser.prototype.onprocessinginstruction = function(value){ - if(this._cbs.onprocessinginstruction){ - var name = this._getInstructionName(value); - this._cbs.onprocessinginstruction("?" + name, "?" + value); - } - }; - - Parser.prototype.oncomment = function(value){ - this._updatePosition(4); - - if(this._cbs.oncomment) this._cbs.oncomment(value); - if(this._cbs.oncommentend) this._cbs.oncommentend(); - }; - - Parser.prototype.oncdata = function(value){ - this._updatePosition(1); - - if(this._options.xmlMode || this._options.recognizeCDATA){ - if(this._cbs.oncdatastart) this._cbs.oncdatastart(); - if(this._cbs.ontext) this._cbs.ontext(value); - if(this._cbs.oncdataend) this._cbs.oncdataend(); - } else { - this.oncomment("[CDATA[" + value + "]]"); - } - }; - - Parser.prototype.onerror = function(err){ - if(this._cbs.onerror) this._cbs.onerror(err); - }; - - Parser.prototype.onend = function(){ - if(this._cbs.onclosetag){ - for( - var i = this._stack.length; - i > 0; - this._cbs.onclosetag(this._stack[--i]) - ); - } - if(this._cbs.onend) this._cbs.onend(); - }; - - - //Resets the parser to a blank state, ready to parse a new HTML document - Parser.prototype.reset = function(){ - if(this._cbs.onreset) this._cbs.onreset(); - this._tokenizer.reset(); - - this._tagname = ""; - this._attribname = ""; - this._attribs = null; - this._stack = []; - - if(this._cbs.onparserinit) this._cbs.onparserinit(this); - }; - - //Parses a complete HTML document and pushes it to the handler - Parser.prototype.parseComplete = function(data){ - this.reset(); - this.end(data); - }; - - Parser.prototype.write = function(chunk){ - this._tokenizer.write(chunk); - }; - - Parser.prototype.end = function(chunk){ - this._tokenizer.end(chunk); - }; - - Parser.prototype.pause = function(){ - this._tokenizer.pause(); - }; - - Parser.prototype.resume = function(){ - this._tokenizer.resume(); - }; - - //alias for backwards compat - Parser.prototype.parseChunk = Parser.prototype.write; - Parser.prototype.done = Parser.prototype.end; - - module.exports = Parser; - - -/***/ }, -/* 16 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = Tokenizer; - - var decodeCodePoint = __webpack_require__(17), - entityMap = __webpack_require__(19), - legacyMap = __webpack_require__(20), - xmlMap = __webpack_require__(21), - - i = 0, - - TEXT = i++, - BEFORE_TAG_NAME = i++, //after < - IN_TAG_NAME = i++, - IN_SELF_CLOSING_TAG = i++, - BEFORE_CLOSING_TAG_NAME = i++, - IN_CLOSING_TAG_NAME = i++, - AFTER_CLOSING_TAG_NAME = i++, - - //attributes - BEFORE_ATTRIBUTE_NAME = i++, - IN_ATTRIBUTE_NAME = i++, - AFTER_ATTRIBUTE_NAME = i++, - BEFORE_ATTRIBUTE_VALUE = i++, - IN_ATTRIBUTE_VALUE_DQ = i++, // " - IN_ATTRIBUTE_VALUE_SQ = i++, // ' - IN_ATTRIBUTE_VALUE_NQ = i++, - - //declarations - BEFORE_DECLARATION = i++, // ! - IN_DECLARATION = i++, - - //processing instructions - IN_PROCESSING_INSTRUCTION = i++, // ? - - //comments - BEFORE_COMMENT = i++, - IN_COMMENT = i++, - AFTER_COMMENT_1 = i++, - AFTER_COMMENT_2 = i++, - - //cdata - BEFORE_CDATA_1 = i++, // [ - BEFORE_CDATA_2 = i++, // C - BEFORE_CDATA_3 = i++, // D - BEFORE_CDATA_4 = i++, // A - BEFORE_CDATA_5 = i++, // T - BEFORE_CDATA_6 = i++, // A - IN_CDATA = i++, // [ - AFTER_CDATA_1 = i++, // ] - AFTER_CDATA_2 = i++, // ] - - //special tags - BEFORE_SPECIAL = i++, //S - BEFORE_SPECIAL_END = i++, //S - - BEFORE_SCRIPT_1 = i++, //C - BEFORE_SCRIPT_2 = i++, //R - BEFORE_SCRIPT_3 = i++, //I - BEFORE_SCRIPT_4 = i++, //P - BEFORE_SCRIPT_5 = i++, //T - AFTER_SCRIPT_1 = i++, //C - AFTER_SCRIPT_2 = i++, //R - AFTER_SCRIPT_3 = i++, //I - AFTER_SCRIPT_4 = i++, //P - AFTER_SCRIPT_5 = i++, //T - - BEFORE_STYLE_1 = i++, //T - BEFORE_STYLE_2 = i++, //Y - BEFORE_STYLE_3 = i++, //L - BEFORE_STYLE_4 = i++, //E - AFTER_STYLE_1 = i++, //T - AFTER_STYLE_2 = i++, //Y - AFTER_STYLE_3 = i++, //L - AFTER_STYLE_4 = i++, //E - - BEFORE_ENTITY = i++, //& - BEFORE_NUMERIC_ENTITY = i++, //# - IN_NAMED_ENTITY = i++, - IN_NUMERIC_ENTITY = i++, - IN_HEX_ENTITY = i++, //X - - j = 0, - - SPECIAL_NONE = j++, - SPECIAL_SCRIPT = j++, - SPECIAL_STYLE = j++; - - function whitespace(c){ - return c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r"; - } - - function characterState(char, SUCCESS){ - return function(c){ - if(c === char) this._state = SUCCESS; - }; - } - - function ifElseState(upper, SUCCESS, FAILURE){ - var lower = upper.toLowerCase(); - - if(upper === lower){ - return function(c){ - if(c === lower){ - this._state = SUCCESS; - } else { - this._state = FAILURE; - this._index--; - } - }; - } else { - return function(c){ - if(c === lower || c === upper){ - this._state = SUCCESS; - } else { - this._state = FAILURE; - this._index--; - } - }; - } - } - - function consumeSpecialNameChar(upper, NEXT_STATE){ - var lower = upper.toLowerCase(); - - return function(c){ - if(c === lower || c === upper){ - this._state = NEXT_STATE; - } else { - this._state = IN_TAG_NAME; - this._index--; //consume the token again - } - }; - } - - function Tokenizer(options, cbs){ - this._state = TEXT; - this._buffer = ""; - this._sectionStart = 0; - this._index = 0; - this._bufferOffset = 0; //chars removed from _buffer - this._baseState = TEXT; - this._special = SPECIAL_NONE; - this._cbs = cbs; - this._running = true; - this._ended = false; - this._xmlMode = !!(options && options.xmlMode); - this._decodeEntities = !!(options && options.decodeEntities); - } - - Tokenizer.prototype._stateText = function(c){ - if(c === "<"){ - if(this._index > this._sectionStart){ - this._cbs.ontext(this._getSection()); - } - this._state = BEFORE_TAG_NAME; - this._sectionStart = this._index; - } else if(this._decodeEntities && this._special === SPECIAL_NONE && c === "&"){ - if(this._index > this._sectionStart){ - this._cbs.ontext(this._getSection()); - } - this._baseState = TEXT; - this._state = BEFORE_ENTITY; - this._sectionStart = this._index; - } - }; - - Tokenizer.prototype._stateBeforeTagName = function(c){ - if(c === "/"){ - this._state = BEFORE_CLOSING_TAG_NAME; - } else if(c === ">" || this._special !== SPECIAL_NONE || whitespace(c)) { - this._state = TEXT; - } else if(c === "!"){ - this._state = BEFORE_DECLARATION; - this._sectionStart = this._index + 1; - } else if(c === "?"){ - this._state = IN_PROCESSING_INSTRUCTION; - this._sectionStart = this._index + 1; - } else if(c === "<"){ - this._cbs.ontext(this._getSection()); - this._sectionStart = this._index; - } else { - this._state = (!this._xmlMode && (c === "s" || c === "S")) ? - BEFORE_SPECIAL : IN_TAG_NAME; - this._sectionStart = this._index; - } - }; - - Tokenizer.prototype._stateInTagName = function(c){ - if(c === "/" || c === ">" || whitespace(c)){ - this._emitToken("onopentagname"); - this._state = BEFORE_ATTRIBUTE_NAME; - this._index--; - } - }; - - Tokenizer.prototype._stateBeforeCloseingTagName = function(c){ - if(whitespace(c)); - else if(c === ">"){ - this._state = TEXT; - } else if(this._special !== SPECIAL_NONE){ - if(c === "s" || c === "S"){ - this._state = BEFORE_SPECIAL_END; - } else { - this._state = TEXT; - this._index--; - } - } else { - this._state = IN_CLOSING_TAG_NAME; - this._sectionStart = this._index; - } - }; - - Tokenizer.prototype._stateInCloseingTagName = function(c){ - if(c === ">" || whitespace(c)){ - this._emitToken("onclosetag"); - this._state = AFTER_CLOSING_TAG_NAME; - this._index--; - } - }; - - Tokenizer.prototype._stateAfterCloseingTagName = function(c){ - //skip everything until ">" - if(c === ">"){ - this._state = TEXT; - this._sectionStart = this._index + 1; - } - }; - - Tokenizer.prototype._stateBeforeAttributeName = function(c){ - if(c === ">"){ - this._cbs.onopentagend(); - this._state = TEXT; - this._sectionStart = this._index + 1; - } else if(c === "/"){ - this._state = IN_SELF_CLOSING_TAG; - } else if(!whitespace(c)){ - this._state = IN_ATTRIBUTE_NAME; - this._sectionStart = this._index; - } - }; - - Tokenizer.prototype._stateInSelfClosingTag = function(c){ - if(c === ">"){ - this._cbs.onselfclosingtag(); - this._state = TEXT; - this._sectionStart = this._index + 1; - } else if(!whitespace(c)){ - this._state = BEFORE_ATTRIBUTE_NAME; - this._index--; - } - }; - - Tokenizer.prototype._stateInAttributeName = function(c){ - if(c === "=" || c === "/" || c === ">" || whitespace(c)){ - this._cbs.onattribname(this._getSection()); - this._sectionStart = -1; - this._state = AFTER_ATTRIBUTE_NAME; - this._index--; - } - }; - - Tokenizer.prototype._stateAfterAttributeName = function(c){ - if(c === "="){ - this._state = BEFORE_ATTRIBUTE_VALUE; - } else if(c === "/" || c === ">"){ - this._cbs.onattribend(); - this._state = BEFORE_ATTRIBUTE_NAME; - this._index--; - } else if(!whitespace(c)){ - this._cbs.onattribend(); - this._state = IN_ATTRIBUTE_NAME; - this._sectionStart = this._index; - } - }; - - Tokenizer.prototype._stateBeforeAttributeValue = function(c){ - if(c === "\""){ - this._state = IN_ATTRIBUTE_VALUE_DQ; - this._sectionStart = this._index + 1; - } else if(c === "'"){ - this._state = IN_ATTRIBUTE_VALUE_SQ; - this._sectionStart = this._index + 1; - } else if(!whitespace(c)){ - this._state = IN_ATTRIBUTE_VALUE_NQ; - this._sectionStart = this._index; - this._index--; //reconsume token - } - }; - - Tokenizer.prototype._stateInAttributeValueDoubleQuotes = function(c){ - if(c === "\""){ - this._emitToken("onattribdata"); - this._cbs.onattribend(); - this._state = BEFORE_ATTRIBUTE_NAME; - } else if(this._decodeEntities && c === "&"){ - this._emitToken("onattribdata"); - this._baseState = this._state; - this._state = BEFORE_ENTITY; - this._sectionStart = this._index; - } - }; - - Tokenizer.prototype._stateInAttributeValueSingleQuotes = function(c){ - if(c === "'"){ - this._emitToken("onattribdata"); - this._cbs.onattribend(); - this._state = BEFORE_ATTRIBUTE_NAME; - } else if(this._decodeEntities && c === "&"){ - this._emitToken("onattribdata"); - this._baseState = this._state; - this._state = BEFORE_ENTITY; - this._sectionStart = this._index; - } - }; - - Tokenizer.prototype._stateInAttributeValueNoQuotes = function(c){ - if(whitespace(c) || c === ">"){ - this._emitToken("onattribdata"); - this._cbs.onattribend(); - this._state = BEFORE_ATTRIBUTE_NAME; - this._index--; - } else if(this._decodeEntities && c === "&"){ - this._emitToken("onattribdata"); - this._baseState = this._state; - this._state = BEFORE_ENTITY; - this._sectionStart = this._index; - } - }; - - Tokenizer.prototype._stateBeforeDeclaration = function(c){ - this._state = c === "[" ? BEFORE_CDATA_1 : - c === "-" ? BEFORE_COMMENT : - IN_DECLARATION; - }; - - Tokenizer.prototype._stateInDeclaration = function(c){ - if(c === ">"){ - this._cbs.ondeclaration(this._getSection()); - this._state = TEXT; - this._sectionStart = this._index + 1; - } - }; - - Tokenizer.prototype._stateInProcessingInstruction = function(c){ - if(c === ">"){ - this._cbs.onprocessinginstruction(this._getSection()); - this._state = TEXT; - this._sectionStart = this._index + 1; - } - }; - - Tokenizer.prototype._stateBeforeComment = function(c){ - if(c === "-"){ - this._state = IN_COMMENT; - this._sectionStart = this._index + 1; - } else { - this._state = IN_DECLARATION; - } - }; - - Tokenizer.prototype._stateInComment = function(c){ - if(c === "-") this._state = AFTER_COMMENT_1; - }; - - Tokenizer.prototype._stateAfterComment1 = function(c){ - if(c === "-"){ - this._state = AFTER_COMMENT_2; - } else { - this._state = IN_COMMENT; - } - }; - - Tokenizer.prototype._stateAfterComment2 = function(c){ - if(c === ">"){ - //remove 2 trailing chars - this._cbs.oncomment(this._buffer.substring(this._sectionStart, this._index - 2)); - this._state = TEXT; - this._sectionStart = this._index + 1; - } else if(c !== "-"){ - this._state = IN_COMMENT; - } - // else: stay in AFTER_COMMENT_2 (`--->`) - }; - - Tokenizer.prototype._stateBeforeCdata1 = ifElseState("C", BEFORE_CDATA_2, IN_DECLARATION); - Tokenizer.prototype._stateBeforeCdata2 = ifElseState("D", BEFORE_CDATA_3, IN_DECLARATION); - Tokenizer.prototype._stateBeforeCdata3 = ifElseState("A", BEFORE_CDATA_4, IN_DECLARATION); - Tokenizer.prototype._stateBeforeCdata4 = ifElseState("T", BEFORE_CDATA_5, IN_DECLARATION); - Tokenizer.prototype._stateBeforeCdata5 = ifElseState("A", BEFORE_CDATA_6, IN_DECLARATION); - - Tokenizer.prototype._stateBeforeCdata6 = function(c){ - if(c === "["){ - this._state = IN_CDATA; - this._sectionStart = this._index + 1; - } else { - this._state = IN_DECLARATION; - this._index--; - } - }; - - Tokenizer.prototype._stateInCdata = function(c){ - if(c === "]") this._state = AFTER_CDATA_1; - }; - - Tokenizer.prototype._stateAfterCdata1 = characterState("]", AFTER_CDATA_2); - - Tokenizer.prototype._stateAfterCdata2 = function(c){ - if(c === ">"){ - //remove 2 trailing chars - this._cbs.oncdata(this._buffer.substring(this._sectionStart, this._index - 2)); - this._state = TEXT; - this._sectionStart = this._index + 1; - } else if(c !== "]") { - this._state = IN_CDATA; - } - //else: stay in AFTER_CDATA_2 (`]]]>`) - }; - - Tokenizer.prototype._stateBeforeSpecial = function(c){ - if(c === "c" || c === "C"){ - this._state = BEFORE_SCRIPT_1; - } else if(c === "t" || c === "T"){ - this._state = BEFORE_STYLE_1; - } else { - this._state = IN_TAG_NAME; - this._index--; //consume the token again - } - }; - - Tokenizer.prototype._stateBeforeSpecialEnd = function(c){ - if(this._special === SPECIAL_SCRIPT && (c === "c" || c === "C")){ - this._state = AFTER_SCRIPT_1; - } else if(this._special === SPECIAL_STYLE && (c === "t" || c === "T")){ - this._state = AFTER_STYLE_1; - } - else this._state = TEXT; - }; - - Tokenizer.prototype._stateBeforeScript1 = consumeSpecialNameChar("R", BEFORE_SCRIPT_2); - Tokenizer.prototype._stateBeforeScript2 = consumeSpecialNameChar("I", BEFORE_SCRIPT_3); - Tokenizer.prototype._stateBeforeScript3 = consumeSpecialNameChar("P", BEFORE_SCRIPT_4); - Tokenizer.prototype._stateBeforeScript4 = consumeSpecialNameChar("T", BEFORE_SCRIPT_5); - - Tokenizer.prototype._stateBeforeScript5 = function(c){ - if(c === "/" || c === ">" || whitespace(c)){ - this._special = SPECIAL_SCRIPT; - } - this._state = IN_TAG_NAME; - this._index--; //consume the token again - }; - - Tokenizer.prototype._stateAfterScript1 = ifElseState("R", AFTER_SCRIPT_2, TEXT); - Tokenizer.prototype._stateAfterScript2 = ifElseState("I", AFTER_SCRIPT_3, TEXT); - Tokenizer.prototype._stateAfterScript3 = ifElseState("P", AFTER_SCRIPT_4, TEXT); - Tokenizer.prototype._stateAfterScript4 = ifElseState("T", AFTER_SCRIPT_5, TEXT); - - Tokenizer.prototype._stateAfterScript5 = function(c){ - if(c === ">" || whitespace(c)){ - this._special = SPECIAL_NONE; - this._state = IN_CLOSING_TAG_NAME; - this._sectionStart = this._index - 6; - this._index--; //reconsume the token - } - else this._state = TEXT; - }; - - Tokenizer.prototype._stateBeforeStyle1 = consumeSpecialNameChar("Y", BEFORE_STYLE_2); - Tokenizer.prototype._stateBeforeStyle2 = consumeSpecialNameChar("L", BEFORE_STYLE_3); - Tokenizer.prototype._stateBeforeStyle3 = consumeSpecialNameChar("E", BEFORE_STYLE_4); - - Tokenizer.prototype._stateBeforeStyle4 = function(c){ - if(c === "/" || c === ">" || whitespace(c)){ - this._special = SPECIAL_STYLE; - } - this._state = IN_TAG_NAME; - this._index--; //consume the token again - }; - - Tokenizer.prototype._stateAfterStyle1 = ifElseState("Y", AFTER_STYLE_2, TEXT); - Tokenizer.prototype._stateAfterStyle2 = ifElseState("L", AFTER_STYLE_3, TEXT); - Tokenizer.prototype._stateAfterStyle3 = ifElseState("E", AFTER_STYLE_4, TEXT); - - Tokenizer.prototype._stateAfterStyle4 = function(c){ - if(c === ">" || whitespace(c)){ - this._special = SPECIAL_NONE; - this._state = IN_CLOSING_TAG_NAME; - this._sectionStart = this._index - 5; - this._index--; //reconsume the token - } - else this._state = TEXT; - }; - - Tokenizer.prototype._stateBeforeEntity = ifElseState("#", BEFORE_NUMERIC_ENTITY, IN_NAMED_ENTITY); - Tokenizer.prototype._stateBeforeNumericEntity = ifElseState("X", IN_HEX_ENTITY, IN_NUMERIC_ENTITY); - - //for entities terminated with a semicolon - Tokenizer.prototype._parseNamedEntityStrict = function(){ - //offset = 1 - if(this._sectionStart + 1 < this._index){ - var entity = this._buffer.substring(this._sectionStart + 1, this._index), - map = this._xmlMode ? xmlMap : entityMap; - - if(map.hasOwnProperty(entity)){ - this._emitPartial(map[entity]); - this._sectionStart = this._index + 1; - } - } - }; - - - //parses legacy entities (without trailing semicolon) - Tokenizer.prototype._parseLegacyEntity = function(){ - var start = this._sectionStart + 1, - limit = this._index - start; - - if(limit > 6) limit = 6; //the max length of legacy entities is 6 - - while(limit >= 2){ //the min length of legacy entities is 2 - var entity = this._buffer.substr(start, limit); - - if(legacyMap.hasOwnProperty(entity)){ - this._emitPartial(legacyMap[entity]); - this._sectionStart += limit + 1; - return; - } else { - limit--; - } - } - }; - - Tokenizer.prototype._stateInNamedEntity = function(c){ - if(c === ";"){ - this._parseNamedEntityStrict(); - if(this._sectionStart + 1 < this._index && !this._xmlMode){ - this._parseLegacyEntity(); - } - this._state = this._baseState; - } else if((c < "a" || c > "z") && (c < "A" || c > "Z") && (c < "0" || c > "9")){ - if(this._xmlMode); - else if(this._sectionStart + 1 === this._index); - else if(this._baseState !== TEXT){ - if(c !== "="){ - this._parseNamedEntityStrict(); - } - } else { - this._parseLegacyEntity(); - } - - this._state = this._baseState; - this._index--; - } - }; - - Tokenizer.prototype._decodeNumericEntity = function(offset, base){ - var sectionStart = this._sectionStart + offset; - - if(sectionStart !== this._index){ - //parse entity - var entity = this._buffer.substring(sectionStart, this._index); - var parsed = parseInt(entity, base); - - this._emitPartial(decodeCodePoint(parsed)); - this._sectionStart = this._index; - } else { - this._sectionStart--; - } - - this._state = this._baseState; - }; - - Tokenizer.prototype._stateInNumericEntity = function(c){ - if(c === ";"){ - this._decodeNumericEntity(2, 10); - this._sectionStart++; - } else if(c < "0" || c > "9"){ - if(!this._xmlMode){ - this._decodeNumericEntity(2, 10); - } else { - this._state = this._baseState; - } - this._index--; - } - }; - - Tokenizer.prototype._stateInHexEntity = function(c){ - if(c === ";"){ - this._decodeNumericEntity(3, 16); - this._sectionStart++; - } else if((c < "a" || c > "f") && (c < "A" || c > "F") && (c < "0" || c > "9")){ - if(!this._xmlMode){ - this._decodeNumericEntity(3, 16); - } else { - this._state = this._baseState; - } - this._index--; - } - }; - - Tokenizer.prototype._cleanup = function (){ - if(this._sectionStart < 0){ - this._buffer = ""; - this._index = 0; - this._bufferOffset += this._index; - } else if(this._running){ - if(this._state === TEXT){ - if(this._sectionStart !== this._index){ - this._cbs.ontext(this._buffer.substr(this._sectionStart)); - } - this._buffer = ""; - this._index = 0; - this._bufferOffset += this._index; - } else if(this._sectionStart === this._index){ - //the section just started - this._buffer = ""; - this._index = 0; - this._bufferOffset += this._index; - } else { - //remove everything unnecessary - this._buffer = this._buffer.substr(this._sectionStart); - this._index -= this._sectionStart; - this._bufferOffset += this._sectionStart; - } - - this._sectionStart = 0; - } - }; - - //TODO make events conditional - Tokenizer.prototype.write = function(chunk){ - if(this._ended) this._cbs.onerror(Error(".write() after done!")); - - this._buffer += chunk; - this._parse(); - }; - - Tokenizer.prototype._parse = function(){ - while(this._index < this._buffer.length && this._running){ - var c = this._buffer.charAt(this._index); - if(this._state === TEXT) { - this._stateText(c); - } else if(this._state === BEFORE_TAG_NAME){ - this._stateBeforeTagName(c); - } else if(this._state === IN_TAG_NAME) { - this._stateInTagName(c); - } else if(this._state === BEFORE_CLOSING_TAG_NAME){ - this._stateBeforeCloseingTagName(c); - } else if(this._state === IN_CLOSING_TAG_NAME){ - this._stateInCloseingTagName(c); - } else if(this._state === AFTER_CLOSING_TAG_NAME){ - this._stateAfterCloseingTagName(c); - } else if(this._state === IN_SELF_CLOSING_TAG){ - this._stateInSelfClosingTag(c); - } - - /* - * attributes - */ - else if(this._state === BEFORE_ATTRIBUTE_NAME){ - this._stateBeforeAttributeName(c); - } else if(this._state === IN_ATTRIBUTE_NAME){ - this._stateInAttributeName(c); - } else if(this._state === AFTER_ATTRIBUTE_NAME){ - this._stateAfterAttributeName(c); - } else if(this._state === BEFORE_ATTRIBUTE_VALUE){ - this._stateBeforeAttributeValue(c); - } else if(this._state === IN_ATTRIBUTE_VALUE_DQ){ - this._stateInAttributeValueDoubleQuotes(c); - } else if(this._state === IN_ATTRIBUTE_VALUE_SQ){ - this._stateInAttributeValueSingleQuotes(c); - } else if(this._state === IN_ATTRIBUTE_VALUE_NQ){ - this._stateInAttributeValueNoQuotes(c); - } - - /* - * declarations - */ - else if(this._state === BEFORE_DECLARATION){ - this._stateBeforeDeclaration(c); - } else if(this._state === IN_DECLARATION){ - this._stateInDeclaration(c); - } - - /* - * processing instructions - */ - else if(this._state === IN_PROCESSING_INSTRUCTION){ - this._stateInProcessingInstruction(c); - } - - /* - * comments - */ - else if(this._state === BEFORE_COMMENT){ - this._stateBeforeComment(c); - } else if(this._state === IN_COMMENT){ - this._stateInComment(c); - } else if(this._state === AFTER_COMMENT_1){ - this._stateAfterComment1(c); - } else if(this._state === AFTER_COMMENT_2){ - this._stateAfterComment2(c); - } - - /* - * cdata - */ - else if(this._state === BEFORE_CDATA_1){ - this._stateBeforeCdata1(c); - } else if(this._state === BEFORE_CDATA_2){ - this._stateBeforeCdata2(c); - } else if(this._state === BEFORE_CDATA_3){ - this._stateBeforeCdata3(c); - } else if(this._state === BEFORE_CDATA_4){ - this._stateBeforeCdata4(c); - } else if(this._state === BEFORE_CDATA_5){ - this._stateBeforeCdata5(c); - } else if(this._state === BEFORE_CDATA_6){ - this._stateBeforeCdata6(c); - } else if(this._state === IN_CDATA){ - this._stateInCdata(c); - } else if(this._state === AFTER_CDATA_1){ - this._stateAfterCdata1(c); - } else if(this._state === AFTER_CDATA_2){ - this._stateAfterCdata2(c); - } - - /* - * special tags - */ - else if(this._state === BEFORE_SPECIAL){ - this._stateBeforeSpecial(c); - } else if(this._state === BEFORE_SPECIAL_END){ - this._stateBeforeSpecialEnd(c); - } - - /* - * script - */ - else if(this._state === BEFORE_SCRIPT_1){ - this._stateBeforeScript1(c); - } else if(this._state === BEFORE_SCRIPT_2){ - this._stateBeforeScript2(c); - } else if(this._state === BEFORE_SCRIPT_3){ - this._stateBeforeScript3(c); - } else if(this._state === BEFORE_SCRIPT_4){ - this._stateBeforeScript4(c); - } else if(this._state === BEFORE_SCRIPT_5){ - this._stateBeforeScript5(c); - } - - else if(this._state === AFTER_SCRIPT_1){ - this._stateAfterScript1(c); - } else if(this._state === AFTER_SCRIPT_2){ - this._stateAfterScript2(c); - } else if(this._state === AFTER_SCRIPT_3){ - this._stateAfterScript3(c); - } else if(this._state === AFTER_SCRIPT_4){ - this._stateAfterScript4(c); - } else if(this._state === AFTER_SCRIPT_5){ - this._stateAfterScript5(c); - } - - /* - * style - */ - else if(this._state === BEFORE_STYLE_1){ - this._stateBeforeStyle1(c); - } else if(this._state === BEFORE_STYLE_2){ - this._stateBeforeStyle2(c); - } else if(this._state === BEFORE_STYLE_3){ - this._stateBeforeStyle3(c); - } else if(this._state === BEFORE_STYLE_4){ - this._stateBeforeStyle4(c); - } - - else if(this._state === AFTER_STYLE_1){ - this._stateAfterStyle1(c); - } else if(this._state === AFTER_STYLE_2){ - this._stateAfterStyle2(c); - } else if(this._state === AFTER_STYLE_3){ - this._stateAfterStyle3(c); - } else if(this._state === AFTER_STYLE_4){ - this._stateAfterStyle4(c); - } - - /* - * entities - */ - else if(this._state === BEFORE_ENTITY){ - this._stateBeforeEntity(c); - } else if(this._state === BEFORE_NUMERIC_ENTITY){ - this._stateBeforeNumericEntity(c); - } else if(this._state === IN_NAMED_ENTITY){ - this._stateInNamedEntity(c); - } else if(this._state === IN_NUMERIC_ENTITY){ - this._stateInNumericEntity(c); - } else if(this._state === IN_HEX_ENTITY){ - this._stateInHexEntity(c); - } - - else { - this._cbs.onerror(Error("unknown _state"), this._state); - } - - this._index++; - } - - this._cleanup(); - }; - - Tokenizer.prototype.pause = function(){ - this._running = false; - }; - Tokenizer.prototype.resume = function(){ - this._running = true; - - if(this._index < this._buffer.length){ - this._parse(); - } - if(this._ended){ - this._finish(); - } - }; - - Tokenizer.prototype.end = function(chunk){ - if(this._ended) this._cbs.onerror(Error(".end() after done!")); - if(chunk) this.write(chunk); - - this._ended = true; - - if(this._running) this._finish(); - }; - - Tokenizer.prototype._finish = function(){ - //if there is remaining data, emit it in a reasonable way - if(this._sectionStart < this._index){ - this._handleTrailingData(); - } - - this._cbs.onend(); - }; - - Tokenizer.prototype._handleTrailingData = function(){ - var data = this._buffer.substr(this._sectionStart); - - if(this._state === IN_CDATA || this._state === AFTER_CDATA_1 || this._state === AFTER_CDATA_2){ - this._cbs.oncdata(data); - } else if(this._state === IN_COMMENT || this._state === AFTER_COMMENT_1 || this._state === AFTER_COMMENT_2){ - this._cbs.oncomment(data); - } else if(this._state === IN_NAMED_ENTITY && !this._xmlMode){ - this._parseLegacyEntity(); - if(this._sectionStart < this._index){ - this._state = this._baseState; - this._handleTrailingData(); - } - } else if(this._state === IN_NUMERIC_ENTITY && !this._xmlMode){ - this._decodeNumericEntity(2, 10); - if(this._sectionStart < this._index){ - this._state = this._baseState; - this._handleTrailingData(); - } - } else if(this._state === IN_HEX_ENTITY && !this._xmlMode){ - this._decodeNumericEntity(3, 16); - if(this._sectionStart < this._index){ - this._state = this._baseState; - this._handleTrailingData(); - } - } else if( - this._state !== IN_TAG_NAME && - this._state !== BEFORE_ATTRIBUTE_NAME && - this._state !== BEFORE_ATTRIBUTE_VALUE && - this._state !== AFTER_ATTRIBUTE_NAME && - this._state !== IN_ATTRIBUTE_NAME && - this._state !== IN_ATTRIBUTE_VALUE_SQ && - this._state !== IN_ATTRIBUTE_VALUE_DQ && - this._state !== IN_ATTRIBUTE_VALUE_NQ && - this._state !== IN_CLOSING_TAG_NAME - ){ - this._cbs.ontext(data); - } - //else, ignore remaining data - //TODO add a way to remove current tag - }; - - Tokenizer.prototype.reset = function(){ - Tokenizer.call(this, {xmlMode: this._xmlMode, decodeEntities: this._decodeEntities}, this._cbs); - }; - - Tokenizer.prototype.getAbsoluteIndex = function(){ - return this._bufferOffset + this._index; - }; - - Tokenizer.prototype._getSection = function(){ - return this._buffer.substring(this._sectionStart, this._index); - }; - - Tokenizer.prototype._emitToken = function(name){ - this._cbs[name](this._getSection()); - this._sectionStart = -1; - }; - - Tokenizer.prototype._emitPartial = function(value){ - if(this._baseState !== TEXT){ - this._cbs.onattribdata(value); //TODO implement the new event - } else { - this._cbs.ontext(value); - } - }; - - -/***/ }, -/* 17 */ -/***/ function(module, exports, __webpack_require__) { - - var decodeMap = __webpack_require__(18); - - module.exports = decodeCodePoint; - - // modified version of https://github.com/mathiasbynens/he/blob/master/src/he.js#L94-L119 - function decodeCodePoint(codePoint){ - - if((codePoint >= 0xD800 && codePoint <= 0xDFFF) || codePoint > 0x10FFFF){ - return "\uFFFD"; - } - - if(codePoint in decodeMap){ - codePoint = decodeMap[codePoint]; - } - - var output = ""; - - if(codePoint > 0xFFFF){ - codePoint -= 0x10000; - output += String.fromCharCode(codePoint >>> 10 & 0x3FF | 0xD800); - codePoint = 0xDC00 | codePoint & 0x3FF; - } - - output += String.fromCharCode(codePoint); - return output; - } - - -/***/ }, -/* 18 */ -/***/ function(module, exports) { - - module.exports = { - "0": 65533, - "128": 8364, - "130": 8218, - "131": 402, - "132": 8222, - "133": 8230, - "134": 8224, - "135": 8225, - "136": 710, - "137": 8240, - "138": 352, - "139": 8249, - "140": 338, - "142": 381, - "145": 8216, - "146": 8217, - "147": 8220, - "148": 8221, - "149": 8226, - "150": 8211, - "151": 8212, - "152": 732, - "153": 8482, - "154": 353, - "155": 8250, - "156": 339, - "158": 382, - "159": 376 - }; - -/***/ }, -/* 19 */ -/***/ function(module, exports) { - - module.exports = { - "Aacute": "Á", - "aacute": "á", - "Abreve": "Ă", - "abreve": "ă", - "ac": "∾", - "acd": "∿", - "acE": "∾̳", - "Acirc": "Â", - "acirc": "â", - "acute": "´", - "Acy": "А", - "acy": "а", - "AElig": "Æ", - "aelig": "æ", - "af": "", - "Afr": "𝔄", - "afr": "𝔞", - "Agrave": "À", - "agrave": "à", - "alefsym": "ℵ", - "aleph": "ℵ", - "Alpha": "Α", - "alpha": "α", - "Amacr": "Ā", - "amacr": "ā", - "amalg": "⨿", - "amp": "&", - "AMP": "&", - "andand": "⩕", - "And": "⩓", - "and": "∧", - "andd": "⩜", - "andslope": "⩘", - "andv": "⩚", - "ang": "∠", - "ange": "⦤", - "angle": "∠", - "angmsdaa": "⦨", - "angmsdab": "⦩", - "angmsdac": "⦪", - "angmsdad": "⦫", - "angmsdae": "⦬", - "angmsdaf": "⦭", - "angmsdag": "⦮", - "angmsdah": "⦯", - "angmsd": "∡", - "angrt": "∟", - "angrtvb": "⊾", - "angrtvbd": "⦝", - "angsph": "∢", - "angst": "Å", - "angzarr": "⍼", - "Aogon": "Ą", - "aogon": "ą", - "Aopf": "𝔸", - "aopf": "𝕒", - "apacir": "⩯", - "ap": "≈", - "apE": "⩰", - "ape": "≊", - "apid": "≋", - "apos": "'", - "ApplyFunction": "", - "approx": "≈", - "approxeq": "≊", - "Aring": "Å", - "aring": "å", - "Ascr": "𝒜", - "ascr": "𝒶", - "Assign": "≔", - "ast": "*", - "asymp": "≈", - "asympeq": "≍", - "Atilde": "Ã", - "atilde": "ã", - "Auml": "Ä", - "auml": "ä", - "awconint": "∳", - "awint": "⨑", - "backcong": "≌", - "backepsilon": "϶", - "backprime": "‵", - "backsim": "∽", - "backsimeq": "⋍", - "Backslash": "∖", - "Barv": "⫧", - "barvee": "⊽", - "barwed": "⌅", - "Barwed": "⌆", - "barwedge": "⌅", - "bbrk": "⎵", - "bbrktbrk": "⎶", - "bcong": "≌", - "Bcy": "Б", - "bcy": "б", - "bdquo": "„", - "becaus": "∵", - "because": "∵", - "Because": "∵", - "bemptyv": "⦰", - "bepsi": "϶", - "bernou": "ℬ", - "Bernoullis": "ℬ", - "Beta": "Β", - "beta": "β", - "beth": "ℶ", - "between": "≬", - "Bfr": "𝔅", - "bfr": "𝔟", - "bigcap": "⋂", - "bigcirc": "◯", - "bigcup": "⋃", - "bigodot": "⨀", - "bigoplus": "⨁", - "bigotimes": "⨂", - "bigsqcup": "⨆", - "bigstar": "★", - "bigtriangledown": "▽", - "bigtriangleup": "△", - "biguplus": "⨄", - "bigvee": "⋁", - "bigwedge": "⋀", - "bkarow": "⤍", - "blacklozenge": "⧫", - "blacksquare": "▪", - "blacktriangle": "▴", - "blacktriangledown": "▾", - "blacktriangleleft": "◂", - "blacktriangleright": "▸", - "blank": "␣", - "blk12": "▒", - "blk14": "░", - "blk34": "▓", - "block": "█", - "bne": "=⃥", - "bnequiv": "≡⃥", - "bNot": "⫭", - "bnot": "⌐", - "Bopf": "𝔹", - "bopf": "𝕓", - "bot": "⊥", - "bottom": "⊥", - "bowtie": "⋈", - "boxbox": "⧉", - "boxdl": "┐", - "boxdL": "╕", - "boxDl": "╖", - "boxDL": "╗", - "boxdr": "┌", - "boxdR": "╒", - "boxDr": "╓", - "boxDR": "╔", - "boxh": "─", - "boxH": "═", - "boxhd": "┬", - "boxHd": "╤", - "boxhD": "╥", - "boxHD": "╦", - "boxhu": "┴", - "boxHu": "╧", - "boxhU": "╨", - "boxHU": "╩", - "boxminus": "⊟", - "boxplus": "⊞", - "boxtimes": "⊠", - "boxul": "┘", - "boxuL": "╛", - "boxUl": "╜", - "boxUL": "╝", - "boxur": "└", - "boxuR": "╘", - "boxUr": "╙", - "boxUR": "╚", - "boxv": "│", - "boxV": "║", - "boxvh": "┼", - "boxvH": "╪", - "boxVh": "╫", - "boxVH": "╬", - "boxvl": "┤", - "boxvL": "╡", - "boxVl": "╢", - "boxVL": "╣", - "boxvr": "├", - "boxvR": "╞", - "boxVr": "╟", - "boxVR": "╠", - "bprime": "‵", - "breve": "˘", - "Breve": "˘", - "brvbar": "¦", - "bscr": "𝒷", - "Bscr": "ℬ", - "bsemi": "⁏", - "bsim": "∽", - "bsime": "⋍", - "bsolb": "⧅", - "bsol": "\\", - "bsolhsub": "⟈", - "bull": "•", - "bullet": "•", - "bump": "≎", - "bumpE": "⪮", - "bumpe": "≏", - "Bumpeq": "≎", - "bumpeq": "≏", - "Cacute": "Ć", - "cacute": "ć", - "capand": "⩄", - "capbrcup": "⩉", - "capcap": "⩋", - "cap": "∩", - "Cap": "⋒", - "capcup": "⩇", - "capdot": "⩀", - "CapitalDifferentialD": "ⅅ", - "caps": "∩︀", - "caret": "⁁", - "caron": "ˇ", - "Cayleys": "ℭ", - "ccaps": "⩍", - "Ccaron": "Č", - "ccaron": "č", - "Ccedil": "Ç", - "ccedil": "ç", - "Ccirc": "Ĉ", - "ccirc": "ĉ", - "Cconint": "∰", - "ccups": "⩌", - "ccupssm": "⩐", - "Cdot": "Ċ", - "cdot": "ċ", - "cedil": "¸", - "Cedilla": "¸", - "cemptyv": "⦲", - "cent": "¢", - "centerdot": "·", - "CenterDot": "·", - "cfr": "𝔠", - "Cfr": "ℭ", - "CHcy": "Ч", - "chcy": "ч", - "check": "✓", - "checkmark": "✓", - "Chi": "Χ", - "chi": "χ", - "circ": "ˆ", - "circeq": "≗", - "circlearrowleft": "↺", - "circlearrowright": "↻", - "circledast": "⊛", - "circledcirc": "⊚", - "circleddash": "⊝", - "CircleDot": "⊙", - "circledR": "®", - "circledS": "Ⓢ", - "CircleMinus": "⊖", - "CirclePlus": "⊕", - "CircleTimes": "⊗", - "cir": "○", - "cirE": "⧃", - "cire": "≗", - "cirfnint": "⨐", - "cirmid": "⫯", - "cirscir": "⧂", - "ClockwiseContourIntegral": "∲", - "CloseCurlyDoubleQuote": "”", - "CloseCurlyQuote": "’", - "clubs": "♣", - "clubsuit": "♣", - "colon": ":", - "Colon": "∷", - "Colone": "⩴", - "colone": "≔", - "coloneq": "≔", - "comma": ",", - "commat": "@", - "comp": "∁", - "compfn": "∘", - "complement": "∁", - "complexes": "ℂ", - "cong": "≅", - "congdot": "⩭", - "Congruent": "≡", - "conint": "∮", - "Conint": "∯", - "ContourIntegral": "∮", - "copf": "𝕔", - "Copf": "ℂ", - "coprod": "∐", - "Coproduct": "∐", - "copy": "©", - "COPY": "©", - "copysr": "℗", - "CounterClockwiseContourIntegral": "∳", - "crarr": "↵", - "cross": "✗", - "Cross": "⨯", - "Cscr": "𝒞", - "cscr": "𝒸", - "csub": "⫏", - "csube": "⫑", - "csup": "⫐", - "csupe": "⫒", - "ctdot": "⋯", - "cudarrl": "⤸", - "cudarrr": "⤵", - "cuepr": "⋞", - "cuesc": "⋟", - "cularr": "↶", - "cularrp": "⤽", - "cupbrcap": "⩈", - "cupcap": "⩆", - "CupCap": "≍", - "cup": "∪", - "Cup": "⋓", - "cupcup": "⩊", - "cupdot": "⊍", - "cupor": "⩅", - "cups": "∪︀", - "curarr": "↷", - "curarrm": "⤼", - "curlyeqprec": "⋞", - "curlyeqsucc": "⋟", - "curlyvee": "⋎", - "curlywedge": "⋏", - "curren": "¤", - "curvearrowleft": "↶", - "curvearrowright": "↷", - "cuvee": "⋎", - "cuwed": "⋏", - "cwconint": "∲", - "cwint": "∱", - "cylcty": "⌭", - "dagger": "†", - "Dagger": "‡", - "daleth": "ℸ", - "darr": "↓", - "Darr": "↡", - "dArr": "⇓", - "dash": "‐", - "Dashv": "⫤", - "dashv": "⊣", - "dbkarow": "⤏", - "dblac": "˝", - "Dcaron": "Ď", - "dcaron": "ď", - "Dcy": "Д", - "dcy": "д", - "ddagger": "‡", - "ddarr": "⇊", - "DD": "ⅅ", - "dd": "ⅆ", - "DDotrahd": "⤑", - "ddotseq": "⩷", - "deg": "°", - "Del": "∇", - "Delta": "Δ", - "delta": "δ", - "demptyv": "⦱", - "dfisht": "⥿", - "Dfr": "𝔇", - "dfr": "𝔡", - "dHar": "⥥", - "dharl": "⇃", - "dharr": "⇂", - "DiacriticalAcute": "´", - "DiacriticalDot": "˙", - "DiacriticalDoubleAcute": "˝", - "DiacriticalGrave": "`", - "DiacriticalTilde": "˜", - "diam": "⋄", - "diamond": "⋄", - "Diamond": "⋄", - "diamondsuit": "♦", - "diams": "♦", - "die": "¨", - "DifferentialD": "ⅆ", - "digamma": "ϝ", - "disin": "⋲", - "div": "÷", - "divide": "÷", - "divideontimes": "⋇", - "divonx": "⋇", - "DJcy": "Ђ", - "djcy": "ђ", - "dlcorn": "⌞", - "dlcrop": "⌍", - "dollar": "$", - "Dopf": "𝔻", - "dopf": "𝕕", - "Dot": "¨", - "dot": "˙", - "DotDot": "⃜", - "doteq": "≐", - "doteqdot": "≑", - "DotEqual": "≐", - "dotminus": "∸", - "dotplus": "∔", - "dotsquare": "⊡", - "doublebarwedge": "⌆", - "DoubleContourIntegral": "∯", - "DoubleDot": "¨", - "DoubleDownArrow": "⇓", - "DoubleLeftArrow": "⇐", - "DoubleLeftRightArrow": "⇔", - "DoubleLeftTee": "⫤", - "DoubleLongLeftArrow": "⟸", - "DoubleLongLeftRightArrow": "⟺", - "DoubleLongRightArrow": "⟹", - "DoubleRightArrow": "⇒", - "DoubleRightTee": "⊨", - "DoubleUpArrow": "⇑", - "DoubleUpDownArrow": "⇕", - "DoubleVerticalBar": "∥", - "DownArrowBar": "⤓", - "downarrow": "↓", - "DownArrow": "↓", - "Downarrow": "⇓", - "DownArrowUpArrow": "⇵", - "DownBreve": "̑", - "downdownarrows": "⇊", - "downharpoonleft": "⇃", - "downharpoonright": "⇂", - "DownLeftRightVector": "⥐", - "DownLeftTeeVector": "⥞", - "DownLeftVectorBar": "⥖", - "DownLeftVector": "↽", - "DownRightTeeVector": "⥟", - "DownRightVectorBar": "⥗", - "DownRightVector": "⇁", - "DownTeeArrow": "↧", - "DownTee": "⊤", - "drbkarow": "⤐", - "drcorn": "⌟", - "drcrop": "⌌", - "Dscr": "𝒟", - "dscr": "𝒹", - "DScy": "Ѕ", - "dscy": "ѕ", - "dsol": "⧶", - "Dstrok": "Đ", - "dstrok": "đ", - "dtdot": "⋱", - "dtri": "▿", - "dtrif": "▾", - "duarr": "⇵", - "duhar": "⥯", - "dwangle": "⦦", - "DZcy": "Џ", - "dzcy": "џ", - "dzigrarr": "⟿", - "Eacute": "É", - "eacute": "é", - "easter": "⩮", - "Ecaron": "Ě", - "ecaron": "ě", - "Ecirc": "Ê", - "ecirc": "ê", - "ecir": "≖", - "ecolon": "≕", - "Ecy": "Э", - "ecy": "э", - "eDDot": "⩷", - "Edot": "Ė", - "edot": "ė", - "eDot": "≑", - "ee": "ⅇ", - "efDot": "≒", - "Efr": "𝔈", - "efr": "𝔢", - "eg": "⪚", - "Egrave": "È", - "egrave": "è", - "egs": "⪖", - "egsdot": "⪘", - "el": "⪙", - "Element": "∈", - "elinters": "⏧", - "ell": "ℓ", - "els": "⪕", - "elsdot": "⪗", - "Emacr": "Ē", - "emacr": "ē", - "empty": "∅", - "emptyset": "∅", - "EmptySmallSquare": "◻", - "emptyv": "∅", - "EmptyVerySmallSquare": "▫", - "emsp13": " ", - "emsp14": " ", - "emsp": " ", - "ENG": "Ŋ", - "eng": "ŋ", - "ensp": " ", - "Eogon": "Ę", - "eogon": "ę", - "Eopf": "𝔼", - "eopf": "𝕖", - "epar": "⋕", - "eparsl": "⧣", - "eplus": "⩱", - "epsi": "ε", - "Epsilon": "Ε", - "epsilon": "ε", - "epsiv": "ϵ", - "eqcirc": "≖", - "eqcolon": "≕", - "eqsim": "≂", - "eqslantgtr": "⪖", - "eqslantless": "⪕", - "Equal": "⩵", - "equals": "=", - "EqualTilde": "≂", - "equest": "≟", - "Equilibrium": "⇌", - "equiv": "≡", - "equivDD": "⩸", - "eqvparsl": "⧥", - "erarr": "⥱", - "erDot": "≓", - "escr": "ℯ", - "Escr": "ℰ", - "esdot": "≐", - "Esim": "⩳", - "esim": "≂", - "Eta": "Η", - "eta": "η", - "ETH": "Ð", - "eth": "ð", - "Euml": "Ë", - "euml": "ë", - "euro": "€", - "excl": "!", - "exist": "∃", - "Exists": "∃", - "expectation": "ℰ", - "exponentiale": "ⅇ", - "ExponentialE": "ⅇ", - "fallingdotseq": "≒", - "Fcy": "Ф", - "fcy": "ф", - "female": "♀", - "ffilig": "ffi", - "fflig": "ff", - "ffllig": "ffl", - "Ffr": "𝔉", - "ffr": "𝔣", - "filig": "fi", - "FilledSmallSquare": "◼", - "FilledVerySmallSquare": "▪", - "fjlig": "fj", - "flat": "♭", - "fllig": "fl", - "fltns": "▱", - "fnof": "ƒ", - "Fopf": "𝔽", - "fopf": "𝕗", - "forall": "∀", - "ForAll": "∀", - "fork": "⋔", - "forkv": "⫙", - "Fouriertrf": "ℱ", - "fpartint": "⨍", - "frac12": "½", - "frac13": "⅓", - "frac14": "¼", - "frac15": "⅕", - "frac16": "⅙", - "frac18": "⅛", - "frac23": "⅔", - "frac25": "⅖", - "frac34": "¾", - "frac35": "⅗", - "frac38": "⅜", - "frac45": "⅘", - "frac56": "⅚", - "frac58": "⅝", - "frac78": "⅞", - "frasl": "⁄", - "frown": "⌢", - "fscr": "𝒻", - "Fscr": "ℱ", - "gacute": "ǵ", - "Gamma": "Γ", - "gamma": "γ", - "Gammad": "Ϝ", - "gammad": "ϝ", - "gap": "⪆", - "Gbreve": "Ğ", - "gbreve": "ğ", - "Gcedil": "Ģ", - "Gcirc": "Ĝ", - "gcirc": "ĝ", - "Gcy": "Г", - "gcy": "г", - "Gdot": "Ġ", - "gdot": "ġ", - "ge": "≥", - "gE": "≧", - "gEl": "⪌", - "gel": "⋛", - "geq": "≥", - "geqq": "≧", - "geqslant": "⩾", - "gescc": "⪩", - "ges": "⩾", - "gesdot": "⪀", - "gesdoto": "⪂", - "gesdotol": "⪄", - "gesl": "⋛︀", - "gesles": "⪔", - "Gfr": "𝔊", - "gfr": "𝔤", - "gg": "≫", - "Gg": "⋙", - "ggg": "⋙", - "gimel": "ℷ", - "GJcy": "Ѓ", - "gjcy": "ѓ", - "gla": "⪥", - "gl": "≷", - "glE": "⪒", - "glj": "⪤", - "gnap": "⪊", - "gnapprox": "⪊", - "gne": "⪈", - "gnE": "≩", - "gneq": "⪈", - "gneqq": "≩", - "gnsim": "⋧", - "Gopf": "𝔾", - "gopf": "𝕘", - "grave": "`", - "GreaterEqual": "≥", - "GreaterEqualLess": "⋛", - "GreaterFullEqual": "≧", - "GreaterGreater": "⪢", - "GreaterLess": "≷", - "GreaterSlantEqual": "⩾", - "GreaterTilde": "≳", - "Gscr": "𝒢", - "gscr": "ℊ", - "gsim": "≳", - "gsime": "⪎", - "gsiml": "⪐", - "gtcc": "⪧", - "gtcir": "⩺", - "gt": ">", - "GT": ">", - "Gt": "≫", - "gtdot": "⋗", - "gtlPar": "⦕", - "gtquest": "⩼", - "gtrapprox": "⪆", - "gtrarr": "⥸", - "gtrdot": "⋗", - "gtreqless": "⋛", - "gtreqqless": "⪌", - "gtrless": "≷", - "gtrsim": "≳", - "gvertneqq": "≩︀", - "gvnE": "≩︀", - "Hacek": "ˇ", - "hairsp": " ", - "half": "½", - "hamilt": "ℋ", - "HARDcy": "Ъ", - "hardcy": "ъ", - "harrcir": "⥈", - "harr": "↔", - "hArr": "⇔", - "harrw": "↭", - "Hat": "^", - "hbar": "ℏ", - "Hcirc": "Ĥ", - "hcirc": "ĥ", - "hearts": "♥", - "heartsuit": "♥", - "hellip": "…", - "hercon": "⊹", - "hfr": "𝔥", - "Hfr": "ℌ", - "HilbertSpace": "ℋ", - "hksearow": "⤥", - "hkswarow": "⤦", - "hoarr": "⇿", - "homtht": "∻", - "hookleftarrow": "↩", - "hookrightarrow": "↪", - "hopf": "𝕙", - "Hopf": "ℍ", - "horbar": "―", - "HorizontalLine": "─", - "hscr": "𝒽", - "Hscr": "ℋ", - "hslash": "ℏ", - "Hstrok": "Ħ", - "hstrok": "ħ", - "HumpDownHump": "≎", - "HumpEqual": "≏", - "hybull": "⁃", - "hyphen": "‐", - "Iacute": "Í", - "iacute": "í", - "ic": "", - "Icirc": "Î", - "icirc": "î", - "Icy": "И", - "icy": "и", - "Idot": "İ", - "IEcy": "Е", - "iecy": "е", - "iexcl": "¡", - "iff": "⇔", - "ifr": "𝔦", - "Ifr": "ℑ", - "Igrave": "Ì", - "igrave": "ì", - "ii": "ⅈ", - "iiiint": "⨌", - "iiint": "∭", - "iinfin": "⧜", - "iiota": "℩", - "IJlig": "IJ", - "ijlig": "ij", - "Imacr": "Ī", - "imacr": "ī", - "image": "ℑ", - "ImaginaryI": "ⅈ", - "imagline": "ℐ", - "imagpart": "ℑ", - "imath": "ı", - "Im": "ℑ", - "imof": "⊷", - "imped": "Ƶ", - "Implies": "⇒", - "incare": "℅", - "in": "∈", - "infin": "∞", - "infintie": "⧝", - "inodot": "ı", - "intcal": "⊺", - "int": "∫", - "Int": "∬", - "integers": "ℤ", - "Integral": "∫", - "intercal": "⊺", - "Intersection": "⋂", - "intlarhk": "⨗", - "intprod": "⨼", - "InvisibleComma": "", - "InvisibleTimes": "", - "IOcy": "Ё", - "iocy": "ё", - "Iogon": "Į", - "iogon": "į", - "Iopf": "𝕀", - "iopf": "𝕚", - "Iota": "Ι", - "iota": "ι", - "iprod": "⨼", - "iquest": "¿", - "iscr": "𝒾", - "Iscr": "ℐ", - "isin": "∈", - "isindot": "⋵", - "isinE": "⋹", - "isins": "⋴", - "isinsv": "⋳", - "isinv": "∈", - "it": "", - "Itilde": "Ĩ", - "itilde": "ĩ", - "Iukcy": "І", - "iukcy": "і", - "Iuml": "Ï", - "iuml": "ï", - "Jcirc": "Ĵ", - "jcirc": "ĵ", - "Jcy": "Й", - "jcy": "й", - "Jfr": "𝔍", - "jfr": "𝔧", - "jmath": "ȷ", - "Jopf": "𝕁", - "jopf": "𝕛", - "Jscr": "𝒥", - "jscr": "𝒿", - "Jsercy": "Ј", - "jsercy": "ј", - "Jukcy": "Є", - "jukcy": "є", - "Kappa": "Κ", - "kappa": "κ", - "kappav": "ϰ", - "Kcedil": "Ķ", - "kcedil": "ķ", - "Kcy": "К", - "kcy": "к", - "Kfr": "𝔎", - "kfr": "𝔨", - "kgreen": "ĸ", - "KHcy": "Х", - "khcy": "х", - "KJcy": "Ќ", - "kjcy": "ќ", - "Kopf": "𝕂", - "kopf": "𝕜", - "Kscr": "𝒦", - "kscr": "𝓀", - "lAarr": "⇚", - "Lacute": "Ĺ", - "lacute": "ĺ", - "laemptyv": "⦴", - "lagran": "ℒ", - "Lambda": "Λ", - "lambda": "λ", - "lang": "⟨", - "Lang": "⟪", - "langd": "⦑", - "langle": "⟨", - "lap": "⪅", - "Laplacetrf": "ℒ", - "laquo": "«", - "larrb": "⇤", - "larrbfs": "⤟", - "larr": "←", - "Larr": "↞", - "lArr": "⇐", - "larrfs": "⤝", - "larrhk": "↩", - "larrlp": "↫", - "larrpl": "⤹", - "larrsim": "⥳", - "larrtl": "↢", - "latail": "⤙", - "lAtail": "⤛", - "lat": "⪫", - "late": "⪭", - "lates": "⪭︀", - "lbarr": "⤌", - "lBarr": "⤎", - "lbbrk": "❲", - "lbrace": "{", - "lbrack": "[", - "lbrke": "⦋", - "lbrksld": "⦏", - "lbrkslu": "⦍", - "Lcaron": "Ľ", - "lcaron": "ľ", - "Lcedil": "Ļ", - "lcedil": "ļ", - "lceil": "⌈", - "lcub": "{", - "Lcy": "Л", - "lcy": "л", - "ldca": "⤶", - "ldquo": "“", - "ldquor": "„", - "ldrdhar": "⥧", - "ldrushar": "⥋", - "ldsh": "↲", - "le": "≤", - "lE": "≦", - "LeftAngleBracket": "⟨", - "LeftArrowBar": "⇤", - "leftarrow": "←", - "LeftArrow": "←", - "Leftarrow": "⇐", - "LeftArrowRightArrow": "⇆", - "leftarrowtail": "↢", - "LeftCeiling": "⌈", - "LeftDoubleBracket": "⟦", - "LeftDownTeeVector": "⥡", - "LeftDownVectorBar": "⥙", - "LeftDownVector": "⇃", - "LeftFloor": "⌊", - "leftharpoondown": "↽", - "leftharpoonup": "↼", - "leftleftarrows": "⇇", - "leftrightarrow": "↔", - "LeftRightArrow": "↔", - "Leftrightarrow": "⇔", - "leftrightarrows": "⇆", - "leftrightharpoons": "⇋", - "leftrightsquigarrow": "↭", - "LeftRightVector": "⥎", - "LeftTeeArrow": "↤", - "LeftTee": "⊣", - "LeftTeeVector": "⥚", - "leftthreetimes": "⋋", - "LeftTriangleBar": "⧏", - "LeftTriangle": "⊲", - "LeftTriangleEqual": "⊴", - "LeftUpDownVector": "⥑", - "LeftUpTeeVector": "⥠", - "LeftUpVectorBar": "⥘", - "LeftUpVector": "↿", - "LeftVectorBar": "⥒", - "LeftVector": "↼", - "lEg": "⪋", - "leg": "⋚", - "leq": "≤", - "leqq": "≦", - "leqslant": "⩽", - "lescc": "⪨", - "les": "⩽", - "lesdot": "⩿", - "lesdoto": "⪁", - "lesdotor": "⪃", - "lesg": "⋚︀", - "lesges": "⪓", - "lessapprox": "⪅", - "lessdot": "⋖", - "lesseqgtr": "⋚", - "lesseqqgtr": "⪋", - "LessEqualGreater": "⋚", - "LessFullEqual": "≦", - "LessGreater": "≶", - "lessgtr": "≶", - "LessLess": "⪡", - "lesssim": "≲", - "LessSlantEqual": "⩽", - "LessTilde": "≲", - "lfisht": "⥼", - "lfloor": "⌊", - "Lfr": "𝔏", - "lfr": "𝔩", - "lg": "≶", - "lgE": "⪑", - "lHar": "⥢", - "lhard": "↽", - "lharu": "↼", - "lharul": "⥪", - "lhblk": "▄", - "LJcy": "Љ", - "ljcy": "љ", - "llarr": "⇇", - "ll": "≪", - "Ll": "⋘", - "llcorner": "⌞", - "Lleftarrow": "⇚", - "llhard": "⥫", - "lltri": "◺", - "Lmidot": "Ŀ", - "lmidot": "ŀ", - "lmoustache": "⎰", - "lmoust": "⎰", - "lnap": "⪉", - "lnapprox": "⪉", - "lne": "⪇", - "lnE": "≨", - "lneq": "⪇", - "lneqq": "≨", - "lnsim": "⋦", - "loang": "⟬", - "loarr": "⇽", - "lobrk": "⟦", - "longleftarrow": "⟵", - "LongLeftArrow": "⟵", - "Longleftarrow": "⟸", - "longleftrightarrow": "⟷", - "LongLeftRightArrow": "⟷", - "Longleftrightarrow": "⟺", - "longmapsto": "⟼", - "longrightarrow": "⟶", - "LongRightArrow": "⟶", - "Longrightarrow": "⟹", - "looparrowleft": "↫", - "looparrowright": "↬", - "lopar": "⦅", - "Lopf": "𝕃", - "lopf": "𝕝", - "loplus": "⨭", - "lotimes": "⨴", - "lowast": "∗", - "lowbar": "_", - "LowerLeftArrow": "↙", - "LowerRightArrow": "↘", - "loz": "◊", - "lozenge": "◊", - "lozf": "⧫", - "lpar": "(", - "lparlt": "⦓", - "lrarr": "⇆", - "lrcorner": "⌟", - "lrhar": "⇋", - "lrhard": "⥭", - "lrm": "", - "lrtri": "⊿", - "lsaquo": "‹", - "lscr": "𝓁", - "Lscr": "ℒ", - "lsh": "↰", - "Lsh": "↰", - "lsim": "≲", - "lsime": "⪍", - "lsimg": "⪏", - "lsqb": "[", - "lsquo": "‘", - "lsquor": "‚", - "Lstrok": "Ł", - "lstrok": "ł", - "ltcc": "⪦", - "ltcir": "⩹", - "lt": "<", - "LT": "<", - "Lt": "≪", - "ltdot": "⋖", - "lthree": "⋋", - "ltimes": "⋉", - "ltlarr": "⥶", - "ltquest": "⩻", - "ltri": "◃", - "ltrie": "⊴", - "ltrif": "◂", - "ltrPar": "⦖", - "lurdshar": "⥊", - "luruhar": "⥦", - "lvertneqq": "≨︀", - "lvnE": "≨︀", - "macr": "¯", - "male": "♂", - "malt": "✠", - "maltese": "✠", - "Map": "⤅", - "map": "↦", - "mapsto": "↦", - "mapstodown": "↧", - "mapstoleft": "↤", - "mapstoup": "↥", - "marker": "▮", - "mcomma": "⨩", - "Mcy": "М", - "mcy": "м", - "mdash": "—", - "mDDot": "∺", - "measuredangle": "∡", - "MediumSpace": " ", - "Mellintrf": "ℳ", - "Mfr": "𝔐", - "mfr": "𝔪", - "mho": "℧", - "micro": "µ", - "midast": "*", - "midcir": "⫰", - "mid": "∣", - "middot": "·", - "minusb": "⊟", - "minus": "−", - "minusd": "∸", - "minusdu": "⨪", - "MinusPlus": "∓", - "mlcp": "⫛", - "mldr": "…", - "mnplus": "∓", - "models": "⊧", - "Mopf": "𝕄", - "mopf": "𝕞", - "mp": "∓", - "mscr": "𝓂", - "Mscr": "ℳ", - "mstpos": "∾", - "Mu": "Μ", - "mu": "μ", - "multimap": "⊸", - "mumap": "⊸", - "nabla": "∇", - "Nacute": "Ń", - "nacute": "ń", - "nang": "∠⃒", - "nap": "≉", - "napE": "⩰̸", - "napid": "≋̸", - "napos": "ʼn", - "napprox": "≉", - "natural": "♮", - "naturals": "ℕ", - "natur": "♮", - "nbsp": " ", - "nbump": "≎̸", - "nbumpe": "≏̸", - "ncap": "⩃", - "Ncaron": "Ň", - "ncaron": "ň", - "Ncedil": "Ņ", - "ncedil": "ņ", - "ncong": "≇", - "ncongdot": "⩭̸", - "ncup": "⩂", - "Ncy": "Н", - "ncy": "н", - "ndash": "–", - "nearhk": "⤤", - "nearr": "↗", - "neArr": "⇗", - "nearrow": "↗", - "ne": "≠", - "nedot": "≐̸", - "NegativeMediumSpace": "", - "NegativeThickSpace": "", - "NegativeThinSpace": "", - "NegativeVeryThinSpace": "", - "nequiv": "≢", - "nesear": "⤨", - "nesim": "≂̸", - "NestedGreaterGreater": "≫", - "NestedLessLess": "≪", - "NewLine": "\n", - "nexist": "∄", - "nexists": "∄", - "Nfr": "𝔑", - "nfr": "𝔫", - "ngE": "≧̸", - "nge": "≱", - "ngeq": "≱", - "ngeqq": "≧̸", - "ngeqslant": "⩾̸", - "nges": "⩾̸", - "nGg": "⋙̸", - "ngsim": "≵", - "nGt": "≫⃒", - "ngt": "≯", - "ngtr": "≯", - "nGtv": "≫̸", - "nharr": "↮", - "nhArr": "⇎", - "nhpar": "⫲", - "ni": "∋", - "nis": "⋼", - "nisd": "⋺", - "niv": "∋", - "NJcy": "Њ", - "njcy": "њ", - "nlarr": "↚", - "nlArr": "⇍", - "nldr": "‥", - "nlE": "≦̸", - "nle": "≰", - "nleftarrow": "↚", - "nLeftarrow": "⇍", - "nleftrightarrow": "↮", - "nLeftrightarrow": "⇎", - "nleq": "≰", - "nleqq": "≦̸", - "nleqslant": "⩽̸", - "nles": "⩽̸", - "nless": "≮", - "nLl": "⋘̸", - "nlsim": "≴", - "nLt": "≪⃒", - "nlt": "≮", - "nltri": "⋪", - "nltrie": "⋬", - "nLtv": "≪̸", - "nmid": "∤", - "NoBreak": "", - "NonBreakingSpace": " ", - "nopf": "𝕟", - "Nopf": "ℕ", - "Not": "⫬", - "not": "¬", - "NotCongruent": "≢", - "NotCupCap": "≭", - "NotDoubleVerticalBar": "∦", - "NotElement": "∉", - "NotEqual": "≠", - "NotEqualTilde": "≂̸", - "NotExists": "∄", - "NotGreater": "≯", - "NotGreaterEqual": "≱", - "NotGreaterFullEqual": "≧̸", - "NotGreaterGreater": "≫̸", - "NotGreaterLess": "≹", - "NotGreaterSlantEqual": "⩾̸", - "NotGreaterTilde": "≵", - "NotHumpDownHump": "≎̸", - "NotHumpEqual": "≏̸", - "notin": "∉", - "notindot": "⋵̸", - "notinE": "⋹̸", - "notinva": "∉", - "notinvb": "⋷", - "notinvc": "⋶", - "NotLeftTriangleBar": "⧏̸", - "NotLeftTriangle": "⋪", - "NotLeftTriangleEqual": "⋬", - "NotLess": "≮", - "NotLessEqual": "≰", - "NotLessGreater": "≸", - "NotLessLess": "≪̸", - "NotLessSlantEqual": "⩽̸", - "NotLessTilde": "≴", - "NotNestedGreaterGreater": "⪢̸", - "NotNestedLessLess": "⪡̸", - "notni": "∌", - "notniva": "∌", - "notnivb": "⋾", - "notnivc": "⋽", - "NotPrecedes": "⊀", - "NotPrecedesEqual": "⪯̸", - "NotPrecedesSlantEqual": "⋠", - "NotReverseElement": "∌", - "NotRightTriangleBar": "⧐̸", - "NotRightTriangle": "⋫", - "NotRightTriangleEqual": "⋭", - "NotSquareSubset": "⊏̸", - "NotSquareSubsetEqual": "⋢", - "NotSquareSuperset": "⊐̸", - "NotSquareSupersetEqual": "⋣", - "NotSubset": "⊂⃒", - "NotSubsetEqual": "⊈", - "NotSucceeds": "⊁", - "NotSucceedsEqual": "⪰̸", - "NotSucceedsSlantEqual": "⋡", - "NotSucceedsTilde": "≿̸", - "NotSuperset": "⊃⃒", - "NotSupersetEqual": "⊉", - "NotTilde": "≁", - "NotTildeEqual": "≄", - "NotTildeFullEqual": "≇", - "NotTildeTilde": "≉", - "NotVerticalBar": "∤", - "nparallel": "∦", - "npar": "∦", - "nparsl": "⫽⃥", - "npart": "∂̸", - "npolint": "⨔", - "npr": "⊀", - "nprcue": "⋠", - "nprec": "⊀", - "npreceq": "⪯̸", - "npre": "⪯̸", - "nrarrc": "⤳̸", - "nrarr": "↛", - "nrArr": "⇏", - "nrarrw": "↝̸", - "nrightarrow": "↛", - "nRightarrow": "⇏", - "nrtri": "⋫", - "nrtrie": "⋭", - "nsc": "⊁", - "nsccue": "⋡", - "nsce": "⪰̸", - "Nscr": "𝒩", - "nscr": "𝓃", - "nshortmid": "∤", - "nshortparallel": "∦", - "nsim": "≁", - "nsime": "≄", - "nsimeq": "≄", - "nsmid": "∤", - "nspar": "∦", - "nsqsube": "⋢", - "nsqsupe": "⋣", - "nsub": "⊄", - "nsubE": "⫅̸", - "nsube": "⊈", - "nsubset": "⊂⃒", - "nsubseteq": "⊈", - "nsubseteqq": "⫅̸", - "nsucc": "⊁", - "nsucceq": "⪰̸", - "nsup": "⊅", - "nsupE": "⫆̸", - "nsupe": "⊉", - "nsupset": "⊃⃒", - "nsupseteq": "⊉", - "nsupseteqq": "⫆̸", - "ntgl": "≹", - "Ntilde": "Ñ", - "ntilde": "ñ", - "ntlg": "≸", - "ntriangleleft": "⋪", - "ntrianglelefteq": "⋬", - "ntriangleright": "⋫", - "ntrianglerighteq": "⋭", - "Nu": "Ν", - "nu": "ν", - "num": "#", - "numero": "№", - "numsp": " ", - "nvap": "≍⃒", - "nvdash": "⊬", - "nvDash": "⊭", - "nVdash": "⊮", - "nVDash": "⊯", - "nvge": "≥⃒", - "nvgt": ">⃒", - "nvHarr": "⤄", - "nvinfin": "⧞", - "nvlArr": "⤂", - "nvle": "≤⃒", - "nvlt": "<⃒", - "nvltrie": "⊴⃒", - "nvrArr": "⤃", - "nvrtrie": "⊵⃒", - "nvsim": "∼⃒", - "nwarhk": "⤣", - "nwarr": "↖", - "nwArr": "⇖", - "nwarrow": "↖", - "nwnear": "⤧", - "Oacute": "Ó", - "oacute": "ó", - "oast": "⊛", - "Ocirc": "Ô", - "ocirc": "ô", - "ocir": "⊚", - "Ocy": "О", - "ocy": "о", - "odash": "⊝", - "Odblac": "Ő", - "odblac": "ő", - "odiv": "⨸", - "odot": "⊙", - "odsold": "⦼", - "OElig": "Œ", - "oelig": "œ", - "ofcir": "⦿", - "Ofr": "𝔒", - "ofr": "𝔬", - "ogon": "˛", - "Ograve": "Ò", - "ograve": "ò", - "ogt": "⧁", - "ohbar": "⦵", - "ohm": "Ω", - "oint": "∮", - "olarr": "↺", - "olcir": "⦾", - "olcross": "⦻", - "oline": "‾", - "olt": "⧀", - "Omacr": "Ō", - "omacr": "ō", - "Omega": "Ω", - "omega": "ω", - "Omicron": "Ο", - "omicron": "ο", - "omid": "⦶", - "ominus": "⊖", - "Oopf": "𝕆", - "oopf": "𝕠", - "opar": "⦷", - "OpenCurlyDoubleQuote": "“", - "OpenCurlyQuote": "‘", - "operp": "⦹", - "oplus": "⊕", - "orarr": "↻", - "Or": "⩔", - "or": "∨", - "ord": "⩝", - "order": "ℴ", - "orderof": "ℴ", - "ordf": "ª", - "ordm": "º", - "origof": "⊶", - "oror": "⩖", - "orslope": "⩗", - "orv": "⩛", - "oS": "Ⓢ", - "Oscr": "𝒪", - "oscr": "ℴ", - "Oslash": "Ø", - "oslash": "ø", - "osol": "⊘", - "Otilde": "Õ", - "otilde": "õ", - "otimesas": "⨶", - "Otimes": "⨷", - "otimes": "⊗", - "Ouml": "Ö", - "ouml": "ö", - "ovbar": "⌽", - "OverBar": "‾", - "OverBrace": "⏞", - "OverBracket": "⎴", - "OverParenthesis": "⏜", - "para": "¶", - "parallel": "∥", - "par": "∥", - "parsim": "⫳", - "parsl": "⫽", - "part": "∂", - "PartialD": "∂", - "Pcy": "П", - "pcy": "п", - "percnt": "%", - "period": ".", - "permil": "‰", - "perp": "⊥", - "pertenk": "‱", - "Pfr": "𝔓", - "pfr": "𝔭", - "Phi": "Φ", - "phi": "φ", - "phiv": "ϕ", - "phmmat": "ℳ", - "phone": "☎", - "Pi": "Π", - "pi": "π", - "pitchfork": "⋔", - "piv": "ϖ", - "planck": "ℏ", - "planckh": "ℎ", - "plankv": "ℏ", - "plusacir": "⨣", - "plusb": "⊞", - "pluscir": "⨢", - "plus": "+", - "plusdo": "∔", - "plusdu": "⨥", - "pluse": "⩲", - "PlusMinus": "±", - "plusmn": "±", - "plussim": "⨦", - "plustwo": "⨧", - "pm": "±", - "Poincareplane": "ℌ", - "pointint": "⨕", - "popf": "𝕡", - "Popf": "ℙ", - "pound": "£", - "prap": "⪷", - "Pr": "⪻", - "pr": "≺", - "prcue": "≼", - "precapprox": "⪷", - "prec": "≺", - "preccurlyeq": "≼", - "Precedes": "≺", - "PrecedesEqual": "⪯", - "PrecedesSlantEqual": "≼", - "PrecedesTilde": "≾", - "preceq": "⪯", - "precnapprox": "⪹", - "precneqq": "⪵", - "precnsim": "⋨", - "pre": "⪯", - "prE": "⪳", - "precsim": "≾", - "prime": "′", - "Prime": "″", - "primes": "ℙ", - "prnap": "⪹", - "prnE": "⪵", - "prnsim": "⋨", - "prod": "∏", - "Product": "∏", - "profalar": "⌮", - "profline": "⌒", - "profsurf": "⌓", - "prop": "∝", - "Proportional": "∝", - "Proportion": "∷", - "propto": "∝", - "prsim": "≾", - "prurel": "⊰", - "Pscr": "𝒫", - "pscr": "𝓅", - "Psi": "Ψ", - "psi": "ψ", - "puncsp": " ", - "Qfr": "𝔔", - "qfr": "𝔮", - "qint": "⨌", - "qopf": "𝕢", - "Qopf": "ℚ", - "qprime": "⁗", - "Qscr": "𝒬", - "qscr": "𝓆", - "quaternions": "ℍ", - "quatint": "⨖", - "quest": "?", - "questeq": "≟", - "quot": "\"", - "QUOT": "\"", - "rAarr": "⇛", - "race": "∽̱", - "Racute": "Ŕ", - "racute": "ŕ", - "radic": "√", - "raemptyv": "⦳", - "rang": "⟩", - "Rang": "⟫", - "rangd": "⦒", - "range": "⦥", - "rangle": "⟩", - "raquo": "»", - "rarrap": "⥵", - "rarrb": "⇥", - "rarrbfs": "⤠", - "rarrc": "⤳", - "rarr": "→", - "Rarr": "↠", - "rArr": "⇒", - "rarrfs": "⤞", - "rarrhk": "↪", - "rarrlp": "↬", - "rarrpl": "⥅", - "rarrsim": "⥴", - "Rarrtl": "⤖", - "rarrtl": "↣", - "rarrw": "↝", - "ratail": "⤚", - "rAtail": "⤜", - "ratio": "∶", - "rationals": "ℚ", - "rbarr": "⤍", - "rBarr": "⤏", - "RBarr": "⤐", - "rbbrk": "❳", - "rbrace": "}", - "rbrack": "]", - "rbrke": "⦌", - "rbrksld": "⦎", - "rbrkslu": "⦐", - "Rcaron": "Ř", - "rcaron": "ř", - "Rcedil": "Ŗ", - "rcedil": "ŗ", - "rceil": "⌉", - "rcub": "}", - "Rcy": "Р", - "rcy": "р", - "rdca": "⤷", - "rdldhar": "⥩", - "rdquo": "”", - "rdquor": "”", - "rdsh": "↳", - "real": "ℜ", - "realine": "ℛ", - "realpart": "ℜ", - "reals": "ℝ", - "Re": "ℜ", - "rect": "▭", - "reg": "®", - "REG": "®", - "ReverseElement": "∋", - "ReverseEquilibrium": "⇋", - "ReverseUpEquilibrium": "⥯", - "rfisht": "⥽", - "rfloor": "⌋", - "rfr": "𝔯", - "Rfr": "ℜ", - "rHar": "⥤", - "rhard": "⇁", - "rharu": "⇀", - "rharul": "⥬", - "Rho": "Ρ", - "rho": "ρ", - "rhov": "ϱ", - "RightAngleBracket": "⟩", - "RightArrowBar": "⇥", - "rightarrow": "→", - "RightArrow": "→", - "Rightarrow": "⇒", - "RightArrowLeftArrow": "⇄", - "rightarrowtail": "↣", - "RightCeiling": "⌉", - "RightDoubleBracket": "⟧", - "RightDownTeeVector": "⥝", - "RightDownVectorBar": "⥕", - "RightDownVector": "⇂", - "RightFloor": "⌋", - "rightharpoondown": "⇁", - "rightharpoonup": "⇀", - "rightleftarrows": "⇄", - "rightleftharpoons": "⇌", - "rightrightarrows": "⇉", - "rightsquigarrow": "↝", - "RightTeeArrow": "↦", - "RightTee": "⊢", - "RightTeeVector": "⥛", - "rightthreetimes": "⋌", - "RightTriangleBar": "⧐", - "RightTriangle": "⊳", - "RightTriangleEqual": "⊵", - "RightUpDownVector": "⥏", - "RightUpTeeVector": "⥜", - "RightUpVectorBar": "⥔", - "RightUpVector": "↾", - "RightVectorBar": "⥓", - "RightVector": "⇀", - "ring": "˚", - "risingdotseq": "≓", - "rlarr": "⇄", - "rlhar": "⇌", - "rlm": "", - "rmoustache": "⎱", - "rmoust": "⎱", - "rnmid": "⫮", - "roang": "⟭", - "roarr": "⇾", - "robrk": "⟧", - "ropar": "⦆", - "ropf": "𝕣", - "Ropf": "ℝ", - "roplus": "⨮", - "rotimes": "⨵", - "RoundImplies": "⥰", - "rpar": ")", - "rpargt": "⦔", - "rppolint": "⨒", - "rrarr": "⇉", - "Rrightarrow": "⇛", - "rsaquo": "›", - "rscr": "𝓇", - "Rscr": "ℛ", - "rsh": "↱", - "Rsh": "↱", - "rsqb": "]", - "rsquo": "’", - "rsquor": "’", - "rthree": "⋌", - "rtimes": "⋊", - "rtri": "▹", - "rtrie": "⊵", - "rtrif": "▸", - "rtriltri": "⧎", - "RuleDelayed": "⧴", - "ruluhar": "⥨", - "rx": "℞", - "Sacute": "Ś", - "sacute": "ś", - "sbquo": "‚", - "scap": "⪸", - "Scaron": "Š", - "scaron": "š", - "Sc": "⪼", - "sc": "≻", - "sccue": "≽", - "sce": "⪰", - "scE": "⪴", - "Scedil": "Ş", - "scedil": "ş", - "Scirc": "Ŝ", - "scirc": "ŝ", - "scnap": "⪺", - "scnE": "⪶", - "scnsim": "⋩", - "scpolint": "⨓", - "scsim": "≿", - "Scy": "С", - "scy": "с", - "sdotb": "⊡", - "sdot": "⋅", - "sdote": "⩦", - "searhk": "⤥", - "searr": "↘", - "seArr": "⇘", - "searrow": "↘", - "sect": "§", - "semi": ";", - "seswar": "⤩", - "setminus": "∖", - "setmn": "∖", - "sext": "✶", - "Sfr": "𝔖", - "sfr": "𝔰", - "sfrown": "⌢", - "sharp": "♯", - "SHCHcy": "Щ", - "shchcy": "щ", - "SHcy": "Ш", - "shcy": "ш", - "ShortDownArrow": "↓", - "ShortLeftArrow": "←", - "shortmid": "∣", - "shortparallel": "∥", - "ShortRightArrow": "→", - "ShortUpArrow": "↑", - "shy": "", - "Sigma": "Σ", - "sigma": "σ", - "sigmaf": "ς", - "sigmav": "ς", - "sim": "∼", - "simdot": "⩪", - "sime": "≃", - "simeq": "≃", - "simg": "⪞", - "simgE": "⪠", - "siml": "⪝", - "simlE": "⪟", - "simne": "≆", - "simplus": "⨤", - "simrarr": "⥲", - "slarr": "←", - "SmallCircle": "∘", - "smallsetminus": "∖", - "smashp": "⨳", - "smeparsl": "⧤", - "smid": "∣", - "smile": "⌣", - "smt": "⪪", - "smte": "⪬", - "smtes": "⪬︀", - "SOFTcy": "Ь", - "softcy": "ь", - "solbar": "⌿", - "solb": "⧄", - "sol": "/", - "Sopf": "𝕊", - "sopf": "𝕤", - "spades": "♠", - "spadesuit": "♠", - "spar": "∥", - "sqcap": "⊓", - "sqcaps": "⊓︀", - "sqcup": "⊔", - "sqcups": "⊔︀", - "Sqrt": "√", - "sqsub": "⊏", - "sqsube": "⊑", - "sqsubset": "⊏", - "sqsubseteq": "⊑", - "sqsup": "⊐", - "sqsupe": "⊒", - "sqsupset": "⊐", - "sqsupseteq": "⊒", - "square": "□", - "Square": "□", - "SquareIntersection": "⊓", - "SquareSubset": "⊏", - "SquareSubsetEqual": "⊑", - "SquareSuperset": "⊐", - "SquareSupersetEqual": "⊒", - "SquareUnion": "⊔", - "squarf": "▪", - "squ": "□", - "squf": "▪", - "srarr": "→", - "Sscr": "𝒮", - "sscr": "𝓈", - "ssetmn": "∖", - "ssmile": "⌣", - "sstarf": "⋆", - "Star": "⋆", - "star": "☆", - "starf": "★", - "straightepsilon": "ϵ", - "straightphi": "ϕ", - "strns": "¯", - "sub": "⊂", - "Sub": "⋐", - "subdot": "⪽", - "subE": "⫅", - "sube": "⊆", - "subedot": "⫃", - "submult": "⫁", - "subnE": "⫋", - "subne": "⊊", - "subplus": "⪿", - "subrarr": "⥹", - "subset": "⊂", - "Subset": "⋐", - "subseteq": "⊆", - "subseteqq": "⫅", - "SubsetEqual": "⊆", - "subsetneq": "⊊", - "subsetneqq": "⫋", - "subsim": "⫇", - "subsub": "⫕", - "subsup": "⫓", - "succapprox": "⪸", - "succ": "≻", - "succcurlyeq": "≽", - "Succeeds": "≻", - "SucceedsEqual": "⪰", - "SucceedsSlantEqual": "≽", - "SucceedsTilde": "≿", - "succeq": "⪰", - "succnapprox": "⪺", - "succneqq": "⪶", - "succnsim": "⋩", - "succsim": "≿", - "SuchThat": "∋", - "sum": "∑", - "Sum": "∑", - "sung": "♪", - "sup1": "¹", - "sup2": "²", - "sup3": "³", - "sup": "⊃", - "Sup": "⋑", - "supdot": "⪾", - "supdsub": "⫘", - "supE": "⫆", - "supe": "⊇", - "supedot": "⫄", - "Superset": "⊃", - "SupersetEqual": "⊇", - "suphsol": "⟉", - "suphsub": "⫗", - "suplarr": "⥻", - "supmult": "⫂", - "supnE": "⫌", - "supne": "⊋", - "supplus": "⫀", - "supset": "⊃", - "Supset": "⋑", - "supseteq": "⊇", - "supseteqq": "⫆", - "supsetneq": "⊋", - "supsetneqq": "⫌", - "supsim": "⫈", - "supsub": "⫔", - "supsup": "⫖", - "swarhk": "⤦", - "swarr": "↙", - "swArr": "⇙", - "swarrow": "↙", - "swnwar": "⤪", - "szlig": "ß", - "Tab": "\t", - "target": "⌖", - "Tau": "Τ", - "tau": "τ", - "tbrk": "⎴", - "Tcaron": "Ť", - "tcaron": "ť", - "Tcedil": "Ţ", - "tcedil": "ţ", - "Tcy": "Т", - "tcy": "т", - "tdot": "⃛", - "telrec": "⌕", - "Tfr": "𝔗", - "tfr": "𝔱", - "there4": "∴", - "therefore": "∴", - "Therefore": "∴", - "Theta": "Θ", - "theta": "θ", - "thetasym": "ϑ", - "thetav": "ϑ", - "thickapprox": "≈", - "thicksim": "∼", - "ThickSpace": " ", - "ThinSpace": " ", - "thinsp": " ", - "thkap": "≈", - "thksim": "∼", - "THORN": "Þ", - "thorn": "þ", - "tilde": "˜", - "Tilde": "∼", - "TildeEqual": "≃", - "TildeFullEqual": "≅", - "TildeTilde": "≈", - "timesbar": "⨱", - "timesb": "⊠", - "times": "×", - "timesd": "⨰", - "tint": "∭", - "toea": "⤨", - "topbot": "⌶", - "topcir": "⫱", - "top": "⊤", - "Topf": "𝕋", - "topf": "𝕥", - "topfork": "⫚", - "tosa": "⤩", - "tprime": "‴", - "trade": "™", - "TRADE": "™", - "triangle": "▵", - "triangledown": "▿", - "triangleleft": "◃", - "trianglelefteq": "⊴", - "triangleq": "≜", - "triangleright": "▹", - "trianglerighteq": "⊵", - "tridot": "◬", - "trie": "≜", - "triminus": "⨺", - "TripleDot": "⃛", - "triplus": "⨹", - "trisb": "⧍", - "tritime": "⨻", - "trpezium": "⏢", - "Tscr": "𝒯", - "tscr": "𝓉", - "TScy": "Ц", - "tscy": "ц", - "TSHcy": "Ћ", - "tshcy": "ћ", - "Tstrok": "Ŧ", - "tstrok": "ŧ", - "twixt": "≬", - "twoheadleftarrow": "↞", - "twoheadrightarrow": "↠", - "Uacute": "Ú", - "uacute": "ú", - "uarr": "↑", - "Uarr": "↟", - "uArr": "⇑", - "Uarrocir": "⥉", - "Ubrcy": "Ў", - "ubrcy": "ў", - "Ubreve": "Ŭ", - "ubreve": "ŭ", - "Ucirc": "Û", - "ucirc": "û", - "Ucy": "У", - "ucy": "у", - "udarr": "⇅", - "Udblac": "Ű", - "udblac": "ű", - "udhar": "⥮", - "ufisht": "⥾", - "Ufr": "𝔘", - "ufr": "𝔲", - "Ugrave": "Ù", - "ugrave": "ù", - "uHar": "⥣", - "uharl": "↿", - "uharr": "↾", - "uhblk": "▀", - "ulcorn": "⌜", - "ulcorner": "⌜", - "ulcrop": "⌏", - "ultri": "◸", - "Umacr": "Ū", - "umacr": "ū", - "uml": "¨", - "UnderBar": "_", - "UnderBrace": "⏟", - "UnderBracket": "⎵", - "UnderParenthesis": "⏝", - "Union": "⋃", - "UnionPlus": "⊎", - "Uogon": "Ų", - "uogon": "ų", - "Uopf": "𝕌", - "uopf": "𝕦", - "UpArrowBar": "⤒", - "uparrow": "↑", - "UpArrow": "↑", - "Uparrow": "⇑", - "UpArrowDownArrow": "⇅", - "updownarrow": "↕", - "UpDownArrow": "↕", - "Updownarrow": "⇕", - "UpEquilibrium": "⥮", - "upharpoonleft": "↿", - "upharpoonright": "↾", - "uplus": "⊎", - "UpperLeftArrow": "↖", - "UpperRightArrow": "↗", - "upsi": "υ", - "Upsi": "ϒ", - "upsih": "ϒ", - "Upsilon": "Υ", - "upsilon": "υ", - "UpTeeArrow": "↥", - "UpTee": "⊥", - "upuparrows": "⇈", - "urcorn": "⌝", - "urcorner": "⌝", - "urcrop": "⌎", - "Uring": "Ů", - "uring": "ů", - "urtri": "◹", - "Uscr": "𝒰", - "uscr": "𝓊", - "utdot": "⋰", - "Utilde": "Ũ", - "utilde": "ũ", - "utri": "▵", - "utrif": "▴", - "uuarr": "⇈", - "Uuml": "Ü", - "uuml": "ü", - "uwangle": "⦧", - "vangrt": "⦜", - "varepsilon": "ϵ", - "varkappa": "ϰ", - "varnothing": "∅", - "varphi": "ϕ", - "varpi": "ϖ", - "varpropto": "∝", - "varr": "↕", - "vArr": "⇕", - "varrho": "ϱ", - "varsigma": "ς", - "varsubsetneq": "⊊︀", - "varsubsetneqq": "⫋︀", - "varsupsetneq": "⊋︀", - "varsupsetneqq": "⫌︀", - "vartheta": "ϑ", - "vartriangleleft": "⊲", - "vartriangleright": "⊳", - "vBar": "⫨", - "Vbar": "⫫", - "vBarv": "⫩", - "Vcy": "В", - "vcy": "в", - "vdash": "⊢", - "vDash": "⊨", - "Vdash": "⊩", - "VDash": "⊫", - "Vdashl": "⫦", - "veebar": "⊻", - "vee": "∨", - "Vee": "⋁", - "veeeq": "≚", - "vellip": "⋮", - "verbar": "|", - "Verbar": "‖", - "vert": "|", - "Vert": "‖", - "VerticalBar": "∣", - "VerticalLine": "|", - "VerticalSeparator": "❘", - "VerticalTilde": "≀", - "VeryThinSpace": " ", - "Vfr": "𝔙", - "vfr": "𝔳", - "vltri": "⊲", - "vnsub": "⊂⃒", - "vnsup": "⊃⃒", - "Vopf": "𝕍", - "vopf": "𝕧", - "vprop": "∝", - "vrtri": "⊳", - "Vscr": "𝒱", - "vscr": "𝓋", - "vsubnE": "⫋︀", - "vsubne": "⊊︀", - "vsupnE": "⫌︀", - "vsupne": "⊋︀", - "Vvdash": "⊪", - "vzigzag": "⦚", - "Wcirc": "Ŵ", - "wcirc": "ŵ", - "wedbar": "⩟", - "wedge": "∧", - "Wedge": "⋀", - "wedgeq": "≙", - "weierp": "℘", - "Wfr": "𝔚", - "wfr": "𝔴", - "Wopf": "𝕎", - "wopf": "𝕨", - "wp": "℘", - "wr": "≀", - "wreath": "≀", - "Wscr": "𝒲", - "wscr": "𝓌", - "xcap": "⋂", - "xcirc": "◯", - "xcup": "⋃", - "xdtri": "▽", - "Xfr": "𝔛", - "xfr": "𝔵", - "xharr": "⟷", - "xhArr": "⟺", - "Xi": "Ξ", - "xi": "ξ", - "xlarr": "⟵", - "xlArr": "⟸", - "xmap": "⟼", - "xnis": "⋻", - "xodot": "⨀", - "Xopf": "𝕏", - "xopf": "𝕩", - "xoplus": "⨁", - "xotime": "⨂", - "xrarr": "⟶", - "xrArr": "⟹", - "Xscr": "𝒳", - "xscr": "𝓍", - "xsqcup": "⨆", - "xuplus": "⨄", - "xutri": "△", - "xvee": "⋁", - "xwedge": "⋀", - "Yacute": "Ý", - "yacute": "ý", - "YAcy": "Я", - "yacy": "я", - "Ycirc": "Ŷ", - "ycirc": "ŷ", - "Ycy": "Ы", - "ycy": "ы", - "yen": "¥", - "Yfr": "𝔜", - "yfr": "𝔶", - "YIcy": "Ї", - "yicy": "ї", - "Yopf": "𝕐", - "yopf": "𝕪", - "Yscr": "𝒴", - "yscr": "𝓎", - "YUcy": "Ю", - "yucy": "ю", - "yuml": "ÿ", - "Yuml": "Ÿ", - "Zacute": "Ź", - "zacute": "ź", - "Zcaron": "Ž", - "zcaron": "ž", - "Zcy": "З", - "zcy": "з", - "Zdot": "Ż", - "zdot": "ż", - "zeetrf": "ℨ", - "ZeroWidthSpace": "", - "Zeta": "Ζ", - "zeta": "ζ", - "zfr": "𝔷", - "Zfr": "ℨ", - "ZHcy": "Ж", - "zhcy": "ж", - "zigrarr": "⇝", - "zopf": "𝕫", - "Zopf": "ℤ", - "Zscr": "𝒵", - "zscr": "𝓏", - "zwj": "", - "zwnj": "" - }; - -/***/ }, -/* 20 */ -/***/ function(module, exports) { - - module.exports = { - "Aacute": "Á", - "aacute": "á", - "Acirc": "Â", - "acirc": "â", - "acute": "´", - "AElig": "Æ", - "aelig": "æ", - "Agrave": "À", - "agrave": "à", - "amp": "&", - "AMP": "&", - "Aring": "Å", - "aring": "å", - "Atilde": "Ã", - "atilde": "ã", - "Auml": "Ä", - "auml": "ä", - "brvbar": "¦", - "Ccedil": "Ç", - "ccedil": "ç", - "cedil": "¸", - "cent": "¢", - "copy": "©", - "COPY": "©", - "curren": "¤", - "deg": "°", - "divide": "÷", - "Eacute": "É", - "eacute": "é", - "Ecirc": "Ê", - "ecirc": "ê", - "Egrave": "È", - "egrave": "è", - "ETH": "Ð", - "eth": "ð", - "Euml": "Ë", - "euml": "ë", - "frac12": "½", - "frac14": "¼", - "frac34": "¾", - "gt": ">", - "GT": ">", - "Iacute": "Í", - "iacute": "í", - "Icirc": "Î", - "icirc": "î", - "iexcl": "¡", - "Igrave": "Ì", - "igrave": "ì", - "iquest": "¿", - "Iuml": "Ï", - "iuml": "ï", - "laquo": "«", - "lt": "<", - "LT": "<", - "macr": "¯", - "micro": "µ", - "middot": "·", - "nbsp": " ", - "not": "¬", - "Ntilde": "Ñ", - "ntilde": "ñ", - "Oacute": "Ó", - "oacute": "ó", - "Ocirc": "Ô", - "ocirc": "ô", - "Ograve": "Ò", - "ograve": "ò", - "ordf": "ª", - "ordm": "º", - "Oslash": "Ø", - "oslash": "ø", - "Otilde": "Õ", - "otilde": "õ", - "Ouml": "Ö", - "ouml": "ö", - "para": "¶", - "plusmn": "±", - "pound": "£", - "quot": "\"", - "QUOT": "\"", - "raquo": "»", - "reg": "®", - "REG": "®", - "sect": "§", - "shy": "", - "sup1": "¹", - "sup2": "²", - "sup3": "³", - "szlig": "ß", - "THORN": "Þ", - "thorn": "þ", - "times": "×", - "Uacute": "Ú", - "uacute": "ú", - "Ucirc": "Û", - "ucirc": "û", - "Ugrave": "Ù", - "ugrave": "ù", - "uml": "¨", - "Uuml": "Ü", - "uuml": "ü", - "Yacute": "Ý", - "yacute": "ý", - "yen": "¥", - "yuml": "ÿ" - }; - -/***/ }, -/* 21 */ -/***/ function(module, exports) { - - module.exports = { - "amp": "&", - "apos": "'", - "gt": ">", - "lt": "<", - "quot": "\"" - }; - -/***/ }, -/* 22 */ -/***/ function(module, exports, __webpack_require__) { - - var ElementType = __webpack_require__(23); - - var re_whitespace = /\s+/g; - var NodePrototype = __webpack_require__(24); - var ElementPrototype = __webpack_require__(25); - - function DomHandler(callback, options, elementCB){ - if(typeof callback === "object"){ - elementCB = options; - options = callback; - callback = null; - } else if(typeof options === "function"){ - elementCB = options; - options = defaultOpts; - } - this._callback = callback; - this._options = options || defaultOpts; - this._elementCB = elementCB; - this.dom = []; - this._done = false; - this._tagStack = []; - this._parser = this._parser || null; - } - - //default options - var defaultOpts = { - normalizeWhitespace: false, //Replace all whitespace with single spaces - withStartIndices: false, //Add startIndex properties to nodes - }; - - DomHandler.prototype.onparserinit = function(parser){ - this._parser = parser; - }; - - //Resets the handler back to starting state - DomHandler.prototype.onreset = function(){ - DomHandler.call(this, this._callback, this._options, this._elementCB); - }; - - //Signals the handler that parsing is done - DomHandler.prototype.onend = function(){ - if(this._done) return; - this._done = true; - this._parser = null; - this._handleCallback(null); - }; - - DomHandler.prototype._handleCallback = - DomHandler.prototype.onerror = function(error){ - if(typeof this._callback === "function"){ - this._callback(error, this.dom); - } else { - if(error) throw error; - } - }; - - DomHandler.prototype.onclosetag = function(){ - //if(this._tagStack.pop().name !== name) this._handleCallback(Error("Tagname didn't match!")); - var elem = this._tagStack.pop(); - if(this._elementCB) this._elementCB(elem); - }; - - DomHandler.prototype._addDomElement = function(element){ - var parent = this._tagStack[this._tagStack.length - 1]; - var siblings = parent ? parent.children : this.dom; - var previousSibling = siblings[siblings.length - 1]; - - element.next = null; - - if(this._options.withStartIndices){ - element.startIndex = this._parser.startIndex; - } - - if (this._options.withDomLvl1) { - element.__proto__ = element.type === "tag" ? ElementPrototype : NodePrototype; - } - - if(previousSibling){ - element.prev = previousSibling; - previousSibling.next = element; - } else { - element.prev = null; - } - - siblings.push(element); - element.parent = parent || null; - }; - - DomHandler.prototype.onopentag = function(name, attribs){ - var element = { - type: name === "script" ? ElementType.Script : name === "style" ? ElementType.Style : ElementType.Tag, - name: name, - attribs: attribs, - children: [] - }; - - this._addDomElement(element); - - this._tagStack.push(element); - }; - - DomHandler.prototype.ontext = function(data){ - //the ignoreWhitespace is officially dropped, but for now, - //it's an alias for normalizeWhitespace - var normalize = this._options.normalizeWhitespace || this._options.ignoreWhitespace; - - var lastTag; - - if(!this._tagStack.length && this.dom.length && (lastTag = this.dom[this.dom.length-1]).type === ElementType.Text){ - if(normalize){ - lastTag.data = (lastTag.data + data).replace(re_whitespace, " "); - } else { - lastTag.data += data; - } - } else { - if( - this._tagStack.length && - (lastTag = this._tagStack[this._tagStack.length - 1]) && - (lastTag = lastTag.children[lastTag.children.length - 1]) && - lastTag.type === ElementType.Text - ){ - if(normalize){ - lastTag.data = (lastTag.data + data).replace(re_whitespace, " "); - } else { - lastTag.data += data; - } - } else { - if(normalize){ - data = data.replace(re_whitespace, " "); - } - - this._addDomElement({ - data: data, - type: ElementType.Text - }); - } - } - }; - - DomHandler.prototype.oncomment = function(data){ - var lastTag = this._tagStack[this._tagStack.length - 1]; - - if(lastTag && lastTag.type === ElementType.Comment){ - lastTag.data += data; - return; - } - - var element = { - data: data, - type: ElementType.Comment - }; - - this._addDomElement(element); - this._tagStack.push(element); - }; - - DomHandler.prototype.oncdatastart = function(){ - var element = { - children: [{ - data: "", - type: ElementType.Text - }], - type: ElementType.CDATA - }; - - this._addDomElement(element); - this._tagStack.push(element); - }; - - DomHandler.prototype.oncommentend = DomHandler.prototype.oncdataend = function(){ - this._tagStack.pop(); - }; - - DomHandler.prototype.onprocessinginstruction = function(name, data){ - this._addDomElement({ - name: name, - data: data, - type: ElementType.Directive - }); - }; - - module.exports = DomHandler; - - -/***/ }, -/* 23 */ -/***/ function(module, exports) { - - //Types of elements found in the DOM - module.exports = { - Text: "text", //Text - Directive: "directive", //<? ... ?> - Comment: "comment", //<!-- ... --> - Script: "script", //<script> tags - Style: "style", //<style> tags - Tag: "tag", //Any tag - CDATA: "cdata", //<![CDATA[ ... ]]> - Doctype: "doctype", - - isTag: function(elem){ - return elem.type === "tag" || elem.type === "script" || elem.type === "style"; - } - }; - - -/***/ }, -/* 24 */ -/***/ function(module, exports) { - - // This object will be used as the prototype for Nodes when creating a - // DOM-Level-1-compliant structure. - var NodePrototype = module.exports = { - get firstChild() { - var children = this.children; - return children && children[0] || null; - }, - get lastChild() { - var children = this.children; - return children && children[children.length - 1] || null; - }, - get nodeType() { - return nodeTypes[this.type] || nodeTypes.element; - } - }; - - var domLvl1 = { - tagName: "name", - childNodes: "children", - parentNode: "parent", - previousSibling: "prev", - nextSibling: "next", - nodeValue: "data" - }; - - var nodeTypes = { - element: 1, - text: 3, - cdata: 4, - comment: 8 - }; - - Object.keys(domLvl1).forEach(function(key) { - var shorthand = domLvl1[key]; - Object.defineProperty(NodePrototype, key, { - get: function() { - return this[shorthand] || null; - }, - set: function(val) { - this[shorthand] = val; - return val; - } - }); - }); - - -/***/ }, -/* 25 */ -/***/ function(module, exports, __webpack_require__) { - - // DOM-Level-1-compliant structure - var NodePrototype = __webpack_require__(24); - var ElementPrototype = module.exports = Object.create(NodePrototype); - - var domLvl1 = { - tagName: "name" - }; - - Object.keys(domLvl1).forEach(function(key) { - var shorthand = domLvl1[key]; - Object.defineProperty(ElementPrototype, key, { - get: function() { - return this[shorthand] || null; - }, - set: function(val) { - this[shorthand] = val; - return val; - } - }); - }); - - -/***/ }, -/* 26 */ -/***/ function(module, exports, __webpack_require__) { - - var index = __webpack_require__(14), - DomHandler = index.DomHandler, - DomUtils = index.DomUtils; - - //TODO: make this a streamable handler - function FeedHandler(callback, options){ - this.init(callback, options); - } - - __webpack_require__(2).inherits(FeedHandler, DomHandler); - - FeedHandler.prototype.init = DomHandler; - - function getElements(what, where){ - return DomUtils.getElementsByTagName(what, where, true); - } - function getOneElement(what, where){ - return DomUtils.getElementsByTagName(what, where, true, 1)[0]; - } - function fetch(what, where, recurse){ - return DomUtils.getText( - DomUtils.getElementsByTagName(what, where, recurse, 1) - ).trim(); - } - - function addConditionally(obj, prop, what, where, recurse){ - var tmp = fetch(what, where, recurse); - if(tmp) obj[prop] = tmp; - } - - var isValidFeed = function(value){ - return value === "rss" || value === "feed" || value === "rdf:RDF"; - }; - - FeedHandler.prototype.onend = function(){ - var feed = {}, - feedRoot = getOneElement(isValidFeed, this.dom), - tmp, childs; - - if(feedRoot){ - if(feedRoot.name === "feed"){ - childs = feedRoot.children; - - feed.type = "atom"; - addConditionally(feed, "id", "id", childs); - addConditionally(feed, "title", "title", childs); - if((tmp = getOneElement("link", childs)) && (tmp = tmp.attribs) && (tmp = tmp.href)) feed.link = tmp; - addConditionally(feed, "description", "subtitle", childs); - if((tmp = fetch("updated", childs))) feed.updated = new Date(tmp); - addConditionally(feed, "author", "email", childs, true); - - feed.items = getElements("entry", childs).map(function(item){ - var entry = {}, tmp; - - item = item.children; - - addConditionally(entry, "id", "id", item); - addConditionally(entry, "title", "title", item); - if((tmp = getOneElement("link", item)) && (tmp = tmp.attribs) && (tmp = tmp.href)) entry.link = tmp; - if((tmp = fetch("summary", item) || fetch("content", item))) entry.description = tmp; - if((tmp = fetch("updated", item))) entry.pubDate = new Date(tmp); - return entry; - }); - } else { - childs = getOneElement("channel", feedRoot.children).children; - - feed.type = feedRoot.name.substr(0, 3); - feed.id = ""; - addConditionally(feed, "title", "title", childs); - addConditionally(feed, "link", "link", childs); - addConditionally(feed, "description", "description", childs); - if((tmp = fetch("lastBuildDate", childs))) feed.updated = new Date(tmp); - addConditionally(feed, "author", "managingEditor", childs, true); - - feed.items = getElements("item", feedRoot.children).map(function(item){ - var entry = {}, tmp; - - item = item.children; - - addConditionally(entry, "id", "guid", item); - addConditionally(entry, "title", "title", item); - addConditionally(entry, "link", "link", item); - addConditionally(entry, "description", "description", item); - if((tmp = fetch("pubDate", item))) entry.pubDate = new Date(tmp); - return entry; - }); - } - } - this.dom = feed; - DomHandler.prototype._handleCallback.call( - this, feedRoot ? null : Error("couldn't find root of feed") - ); - }; - - module.exports = FeedHandler; - - -/***/ }, -/* 27 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = Stream; - - var Parser = __webpack_require__(28); - - function Stream(options){ - Parser.call(this, new Cbs(this), options); - } - - __webpack_require__(2).inherits(Stream, Parser); - - Stream.prototype.readable = true; - - function Cbs(scope){ - this.scope = scope; - } - - var EVENTS = __webpack_require__(14).EVENTS; - - Object.keys(EVENTS).forEach(function(name){ - if(EVENTS[name] === 0){ - Cbs.prototype["on" + name] = function(){ - this.scope.emit(name); - }; - } else if(EVENTS[name] === 1){ - Cbs.prototype["on" + name] = function(a){ - this.scope.emit(name, a); - }; - } else if(EVENTS[name] === 2){ - Cbs.prototype["on" + name] = function(a, b){ - this.scope.emit(name, a, b); - }; - } else { - throw Error("wrong number of arguments!"); - } - }); - -/***/ }, -/* 28 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = Stream; - - var Parser = __webpack_require__(15), - WritableStream = __webpack_require__(29).Writable || __webpack_require__(50).Writable; - - function Stream(cbs, options){ - var parser = this._parser = new Parser(cbs, options); - - WritableStream.call(this, {decodeStrings: false}); - - this.once("finish", function(){ - parser.end(); - }); - } - - __webpack_require__(2).inherits(Stream, WritableStream); - - WritableStream.prototype._write = function(chunk, encoding, cb){ - this._parser.write(chunk); - cb(); - }; - -/***/ }, -/* 29 */ -/***/ function(module, exports, __webpack_require__) { - - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - module.exports = Stream; - - var EE = __webpack_require__(1).EventEmitter; - var inherits = __webpack_require__(30); - - inherits(Stream, EE); - Stream.Readable = __webpack_require__(31); - Stream.Writable = __webpack_require__(46); - Stream.Duplex = __webpack_require__(47); - Stream.Transform = __webpack_require__(48); - Stream.PassThrough = __webpack_require__(49); - - // Backwards-compat with node 0.4.x - Stream.Stream = Stream; - - - - // old-style streams. Note that the pipe method (the only relevant - // part of this class) is overridden in the Readable class. - - function Stream() { - EE.call(this); - } - - Stream.prototype.pipe = function(dest, options) { - var source = this; - - function ondata(chunk) { - if (dest.writable) { - if (false === dest.write(chunk) && source.pause) { - source.pause(); - } - } - } - - source.on('data', ondata); - - function ondrain() { - if (source.readable && source.resume) { - source.resume(); - } - } - - dest.on('drain', ondrain); - - // If the 'end' option is not supplied, dest.end() will be called when - // source gets the 'end' or 'close' events. Only dest.end() once. - if (!dest._isStdio && (!options || options.end !== false)) { - source.on('end', onend); - source.on('close', onclose); - } - - var didOnEnd = false; - function onend() { - if (didOnEnd) return; - didOnEnd = true; - - dest.end(); - } - - - function onclose() { - if (didOnEnd) return; - didOnEnd = true; - - if (typeof dest.destroy === 'function') dest.destroy(); - } - - // don't leave dangling pipes when there are errors. - function onerror(er) { - cleanup(); - if (EE.listenerCount(this, 'error') === 0) { - throw er; // Unhandled stream error in pipe. - } - } - - source.on('error', onerror); - dest.on('error', onerror); - - // remove all the event listeners that were added. - function cleanup() { - source.removeListener('data', ondata); - dest.removeListener('drain', ondrain); - - source.removeListener('end', onend); - source.removeListener('close', onclose); - - source.removeListener('error', onerror); - dest.removeListener('error', onerror); - - source.removeListener('end', cleanup); - source.removeListener('close', cleanup); - - dest.removeListener('close', cleanup); - } - - source.on('end', cleanup); - source.on('close', cleanup); - - dest.on('close', cleanup); - - dest.emit('pipe', source); - - // Allow for unix-like usage: A.pipe(B).pipe(C) - return dest; - }; - - -/***/ }, -/* 30 */ -/***/ function(module, exports) { - - if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; - } else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } - } - - -/***/ }, -/* 31 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(process) {exports = module.exports = __webpack_require__(32); - exports.Stream = __webpack_require__(29); - exports.Readable = exports; - exports.Writable = __webpack_require__(42); - exports.Duplex = __webpack_require__(41); - exports.Transform = __webpack_require__(44); - exports.PassThrough = __webpack_require__(45); - if (!process.browser && process.env.READABLE_STREAM === 'disable') { - module.exports = __webpack_require__(29); - } - - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) - -/***/ }, -/* 32 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - module.exports = Readable; - - /*<replacement>*/ - var isArray = __webpack_require__(33); - /*</replacement>*/ - - - /*<replacement>*/ - var Buffer = __webpack_require__(34).Buffer; - /*</replacement>*/ - - Readable.ReadableState = ReadableState; - - var EE = __webpack_require__(1).EventEmitter; - - /*<replacement>*/ - if (!EE.listenerCount) EE.listenerCount = function(emitter, type) { - return emitter.listeners(type).length; - }; - /*</replacement>*/ - - var Stream = __webpack_require__(29); - - /*<replacement>*/ - var util = __webpack_require__(38); - util.inherits = __webpack_require__(39); - /*</replacement>*/ - - var StringDecoder; - - - /*<replacement>*/ - var debug = __webpack_require__(40); - if (debug && debug.debuglog) { - debug = debug.debuglog('stream'); - } else { - debug = function () {}; - } - /*</replacement>*/ - - - util.inherits(Readable, Stream); - - function ReadableState(options, stream) { - var Duplex = __webpack_require__(41); - - options = options || {}; - - // the point at which it stops calling _read() to fill the buffer - // Note: 0 is a valid value, means "don't call _read preemptively ever" - var hwm = options.highWaterMark; - var defaultHwm = options.objectMode ? 16 : 16 * 1024; - this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; - - // cast to ints. - this.highWaterMark = ~~this.highWaterMark; - - this.buffer = []; - this.length = 0; - this.pipes = null; - this.pipesCount = 0; - this.flowing = null; - this.ended = false; - this.endEmitted = false; - this.reading = false; - - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // whenever we return null, then we set a flag to say - // that we're awaiting a 'readable' event emission. - this.needReadable = false; - this.emittedReadable = false; - this.readableListening = false; - - - // object stream flag. Used to make read(n) ignore n and to - // make all the buffer merging and length checks go away - this.objectMode = !!options.objectMode; - - if (stream instanceof Duplex) - this.objectMode = this.objectMode || !!options.readableObjectMode; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // when piping, we only care about 'readable' events that happen - // after read()ing all the bytes and not getting any pushback. - this.ranOut = false; - - // the number of writers that are awaiting a drain event in .pipe()s - this.awaitDrain = 0; - - // if true, a maybeReadMore has been scheduled - this.readingMore = false; - - this.decoder = null; - this.encoding = null; - if (options.encoding) { - if (!StringDecoder) - StringDecoder = __webpack_require__(43).StringDecoder; - this.decoder = new StringDecoder(options.encoding); - this.encoding = options.encoding; - } - } - - function Readable(options) { - var Duplex = __webpack_require__(41); - - if (!(this instanceof Readable)) - return new Readable(options); - - this._readableState = new ReadableState(options, this); - - // legacy - this.readable = true; - - Stream.call(this); - } - - // Manually shove something into the read() buffer. - // This returns true if the highWaterMark has not been hit yet, - // similar to how Writable.write() returns true if you should - // write() some more. - Readable.prototype.push = function(chunk, encoding) { - var state = this._readableState; - - if (util.isString(chunk) && !state.objectMode) { - encoding = encoding || state.defaultEncoding; - if (encoding !== state.encoding) { - chunk = new Buffer(chunk, encoding); - encoding = ''; - } - } - - return readableAddChunk(this, state, chunk, encoding, false); - }; - - // Unshift should *always* be something directly out of read() - Readable.prototype.unshift = function(chunk) { - var state = this._readableState; - return readableAddChunk(this, state, chunk, '', true); - }; - - function readableAddChunk(stream, state, chunk, encoding, addToFront) { - var er = chunkInvalid(state, chunk); - if (er) { - stream.emit('error', er); - } else if (util.isNullOrUndefined(chunk)) { - state.reading = false; - if (!state.ended) - onEofChunk(stream, state); - } else if (state.objectMode || chunk && chunk.length > 0) { - if (state.ended && !addToFront) { - var e = new Error('stream.push() after EOF'); - stream.emit('error', e); - } else if (state.endEmitted && addToFront) { - var e = new Error('stream.unshift() after end event'); - stream.emit('error', e); - } else { - if (state.decoder && !addToFront && !encoding) - chunk = state.decoder.write(chunk); - - if (!addToFront) - state.reading = false; - - // if we want the data now, just emit it. - if (state.flowing && state.length === 0 && !state.sync) { - stream.emit('data', chunk); - stream.read(0); - } else { - // update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) - state.buffer.unshift(chunk); - else - state.buffer.push(chunk); - - if (state.needReadable) - emitReadable(stream); - } - - maybeReadMore(stream, state); - } - } else if (!addToFront) { - state.reading = false; - } - - return needMoreData(state); - } - - - - // if it's past the high water mark, we can push in some more. - // Also, if we have no data yet, we can stand some - // more bytes. This is to work around cases where hwm=0, - // such as the repl. Also, if the push() triggered a - // readable event, and the user called read(largeNumber) such that - // needReadable was set, then we ought to push more, so that another - // 'readable' event will be triggered. - function needMoreData(state) { - return !state.ended && - (state.needReadable || - state.length < state.highWaterMark || - state.length === 0); - } - - // backwards compatibility. - Readable.prototype.setEncoding = function(enc) { - if (!StringDecoder) - StringDecoder = __webpack_require__(43).StringDecoder; - this._readableState.decoder = new StringDecoder(enc); - this._readableState.encoding = enc; - return this; - }; - - // Don't raise the hwm > 128MB - var MAX_HWM = 0x800000; - function roundUpToNextPowerOf2(n) { - if (n >= MAX_HWM) { - n = MAX_HWM; - } else { - // Get the next highest power of 2 - n--; - for (var p = 1; p < 32; p <<= 1) n |= n >> p; - n++; - } - return n; - } - - function howMuchToRead(n, state) { - if (state.length === 0 && state.ended) - return 0; - - if (state.objectMode) - return n === 0 ? 0 : 1; - - if (isNaN(n) || util.isNull(n)) { - // only flow one buffer at a time - if (state.flowing && state.buffer.length) - return state.buffer[0].length; - else - return state.length; - } - - if (n <= 0) - return 0; - - // If we're asking for more than the target buffer level, - // then raise the water mark. Bump up to the next highest - // power of 2, to prevent increasing it excessively in tiny - // amounts. - if (n > state.highWaterMark) - state.highWaterMark = roundUpToNextPowerOf2(n); - - // don't have that much. return null, unless we've ended. - if (n > state.length) { - if (!state.ended) { - state.needReadable = true; - return 0; - } else - return state.length; - } - - return n; - } - - // you can override either this method, or the async _read(n) below. - Readable.prototype.read = function(n) { - debug('read', n); - var state = this._readableState; - var nOrig = n; - - if (!util.isNumber(n) || n > 0) - state.emittedReadable = false; - - // if we're doing read(0) to trigger a readable event, but we - // already have a bunch of data in the buffer, then just trigger - // the 'readable' event and move on. - if (n === 0 && - state.needReadable && - (state.length >= state.highWaterMark || state.ended)) { - debug('read: emitReadable', state.length, state.ended); - if (state.length === 0 && state.ended) - endReadable(this); - else - emitReadable(this); - return null; - } - - n = howMuchToRead(n, state); - - // if we've ended, and we're now clear, then finish it up. - if (n === 0 && state.ended) { - if (state.length === 0) - endReadable(this); - return null; - } - - // All the actual chunk generation logic needs to be - // *below* the call to _read. The reason is that in certain - // synthetic stream cases, such as passthrough streams, _read - // may be a completely synchronous operation which may change - // the state of the read buffer, providing enough data when - // before there was *not* enough. - // - // So, the steps are: - // 1. Figure out what the state of things will be after we do - // a read from the buffer. - // - // 2. If that resulting state will trigger a _read, then call _read. - // Note that this may be asynchronous, or synchronous. Yes, it is - // deeply ugly to write APIs this way, but that still doesn't mean - // that the Readable class should behave improperly, as streams are - // designed to be sync/async agnostic. - // Take note if the _read call is sync or async (ie, if the read call - // has returned yet), so that we know whether or not it's safe to emit - // 'readable' etc. - // - // 3. Actually pull the requested chunks out of the buffer and return. - - // if we need a readable event, then we need to do some reading. - var doRead = state.needReadable; - debug('need readable', doRead); - - // if we currently have less than the highWaterMark, then also read some - if (state.length === 0 || state.length - n < state.highWaterMark) { - doRead = true; - debug('length less than watermark', doRead); - } - - // however, if we've ended, then there's no point, and if we're already - // reading, then it's unnecessary. - if (state.ended || state.reading) { - doRead = false; - debug('reading or ended', doRead); - } - - if (doRead) { - debug('do read'); - state.reading = true; - state.sync = true; - // if the length is currently zero, then we *need* a readable event. - if (state.length === 0) - state.needReadable = true; - // call internal read method - this._read(state.highWaterMark); - state.sync = false; - } - - // If _read pushed data synchronously, then `reading` will be false, - // and we need to re-evaluate how much data we can return to the user. - if (doRead && !state.reading) - n = howMuchToRead(nOrig, state); - - var ret; - if (n > 0) - ret = fromList(n, state); - else - ret = null; - - if (util.isNull(ret)) { - state.needReadable = true; - n = 0; - } - - state.length -= n; - - // If we have nothing in the buffer, then we want to know - // as soon as we *do* get something into the buffer. - if (state.length === 0 && !state.ended) - state.needReadable = true; - - // If we tried to read() past the EOF, then emit end on the next tick. - if (nOrig !== n && state.ended && state.length === 0) - endReadable(this); - - if (!util.isNull(ret)) - this.emit('data', ret); - - return ret; - }; - - function chunkInvalid(state, chunk) { - var er = null; - if (!util.isBuffer(chunk) && - !util.isString(chunk) && - !util.isNullOrUndefined(chunk) && - !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - return er; - } - - - function onEofChunk(stream, state) { - if (state.decoder && !state.ended) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) { - state.buffer.push(chunk); - state.length += state.objectMode ? 1 : chunk.length; - } - } - state.ended = true; - - // emit 'readable' now to make sure it gets picked up. - emitReadable(stream); - } - - // Don't emit readable right away in sync mode, because this can trigger - // another read() call => stack overflow. This way, it might trigger - // a nextTick recursion warning, but that's not so bad. - function emitReadable(stream) { - var state = stream._readableState; - state.needReadable = false; - if (!state.emittedReadable) { - debug('emitReadable', state.flowing); - state.emittedReadable = true; - if (state.sync) - process.nextTick(function() { - emitReadable_(stream); - }); - else - emitReadable_(stream); - } - } - - function emitReadable_(stream) { - debug('emit readable'); - stream.emit('readable'); - flow(stream); - } - - - // at this point, the user has presumably seen the 'readable' event, - // and called read() to consume some data. that may have triggered - // in turn another _read(n) call, in which case reading = true if - // it's in progress. - // However, if we're not ended, or reading, and the length < hwm, - // then go ahead and try to read some more preemptively. - function maybeReadMore(stream, state) { - if (!state.readingMore) { - state.readingMore = true; - process.nextTick(function() { - maybeReadMore_(stream, state); - }); - } - } - - function maybeReadMore_(stream, state) { - var len = state.length; - while (!state.reading && !state.flowing && !state.ended && - state.length < state.highWaterMark) { - debug('maybeReadMore read 0'); - stream.read(0); - if (len === state.length) - // didn't get any data, stop spinning. - break; - else - len = state.length; - } - state.readingMore = false; - } - - // abstract method. to be overridden in specific implementation classes. - // call cb(er, data) where data is <= n in length. - // for virtual (non-string, non-buffer) streams, "length" is somewhat - // arbitrary, and perhaps not very meaningful. - Readable.prototype._read = function(n) { - this.emit('error', new Error('not implemented')); - }; - - Readable.prototype.pipe = function(dest, pipeOpts) { - var src = this; - var state = this._readableState; - - switch (state.pipesCount) { - case 0: - state.pipes = dest; - break; - case 1: - state.pipes = [state.pipes, dest]; - break; - default: - state.pipes.push(dest); - break; - } - state.pipesCount += 1; - debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); - - var doEnd = (!pipeOpts || pipeOpts.end !== false) && - dest !== process.stdout && - dest !== process.stderr; - - var endFn = doEnd ? onend : cleanup; - if (state.endEmitted) - process.nextTick(endFn); - else - src.once('end', endFn); - - dest.on('unpipe', onunpipe); - function onunpipe(readable) { - debug('onunpipe'); - if (readable === src) { - cleanup(); - } - } - - function onend() { - debug('onend'); - dest.end(); - } - - // when the dest drains, it reduces the awaitDrain counter - // on the source. This would be more elegant with a .once() - // handler in flow(), but adding and removing repeatedly is - // too slow. - var ondrain = pipeOnDrain(src); - dest.on('drain', ondrain); - - function cleanup() { - debug('cleanup'); - // cleanup event handlers once the pipe is broken - dest.removeListener('close', onclose); - dest.removeListener('finish', onfinish); - dest.removeListener('drain', ondrain); - dest.removeListener('error', onerror); - dest.removeListener('unpipe', onunpipe); - src.removeListener('end', onend); - src.removeListener('end', cleanup); - src.removeListener('data', ondata); - - // if the reader is waiting for a drain event from this - // specific writer, then it would cause it to never start - // flowing again. - // So, if this is awaiting a drain, then we just call it now. - // If we don't know, then assume that we are waiting for one. - if (state.awaitDrain && - (!dest._writableState || dest._writableState.needDrain)) - ondrain(); - } - - src.on('data', ondata); - function ondata(chunk) { - debug('ondata'); - var ret = dest.write(chunk); - if (false === ret) { - debug('false write response, pause', - src._readableState.awaitDrain); - src._readableState.awaitDrain++; - src.pause(); - } - } - - // if the dest has an error, then stop piping into it. - // however, don't suppress the throwing behavior for this. - function onerror(er) { - debug('onerror', er); - unpipe(); - dest.removeListener('error', onerror); - if (EE.listenerCount(dest, 'error') === 0) - dest.emit('error', er); - } - // This is a brutally ugly hack to make sure that our error handler - // is attached before any userland ones. NEVER DO THIS. - if (!dest._events || !dest._events.error) - dest.on('error', onerror); - else if (isArray(dest._events.error)) - dest._events.error.unshift(onerror); - else - dest._events.error = [onerror, dest._events.error]; - - - - // Both close and finish should trigger unpipe, but only once. - function onclose() { - dest.removeListener('finish', onfinish); - unpipe(); - } - dest.once('close', onclose); - function onfinish() { - debug('onfinish'); - dest.removeListener('close', onclose); - unpipe(); - } - dest.once('finish', onfinish); - - function unpipe() { - debug('unpipe'); - src.unpipe(dest); - } - - // tell the dest that it's being piped to - dest.emit('pipe', src); - - // start the flow if it hasn't been started already. - if (!state.flowing) { - debug('pipe resume'); - src.resume(); - } - - return dest; - }; - - function pipeOnDrain(src) { - return function() { - var state = src._readableState; - debug('pipeOnDrain', state.awaitDrain); - if (state.awaitDrain) - state.awaitDrain--; - if (state.awaitDrain === 0 && EE.listenerCount(src, 'data')) { - state.flowing = true; - flow(src); - } - }; - } - - - Readable.prototype.unpipe = function(dest) { - var state = this._readableState; - - // if we're not piping anywhere, then do nothing. - if (state.pipesCount === 0) - return this; - - // just one destination. most common case. - if (state.pipesCount === 1) { - // passed in one, but it's not the right one. - if (dest && dest !== state.pipes) - return this; - - if (!dest) - dest = state.pipes; - - // got a match. - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - if (dest) - dest.emit('unpipe', this); - return this; - } - - // slow case. multiple pipe destinations. - - if (!dest) { - // remove all. - var dests = state.pipes; - var len = state.pipesCount; - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - - for (var i = 0; i < len; i++) - dests[i].emit('unpipe', this); - return this; - } - - // try to find the right one. - var i = indexOf(state.pipes, dest); - if (i === -1) - return this; - - state.pipes.splice(i, 1); - state.pipesCount -= 1; - if (state.pipesCount === 1) - state.pipes = state.pipes[0]; - - dest.emit('unpipe', this); - - return this; - }; - - // set up data events if they are asked for - // Ensure readable listeners eventually get something - Readable.prototype.on = function(ev, fn) { - var res = Stream.prototype.on.call(this, ev, fn); - - // If listening to data, and it has not explicitly been paused, - // then call resume to start the flow of data on the next tick. - if (ev === 'data' && false !== this._readableState.flowing) { - this.resume(); - } - - if (ev === 'readable' && this.readable) { - var state = this._readableState; - if (!state.readableListening) { - state.readableListening = true; - state.emittedReadable = false; - state.needReadable = true; - if (!state.reading) { - var self = this; - process.nextTick(function() { - debug('readable nexttick read 0'); - self.read(0); - }); - } else if (state.length) { - emitReadable(this, state); - } - } - } - - return res; - }; - Readable.prototype.addListener = Readable.prototype.on; - - // pause() and resume() are remnants of the legacy readable stream API - // If the user uses them, then switch into old mode. - Readable.prototype.resume = function() { - var state = this._readableState; - if (!state.flowing) { - debug('resume'); - state.flowing = true; - if (!state.reading) { - debug('resume read 0'); - this.read(0); - } - resume(this, state); - } - return this; - }; - - function resume(stream, state) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - process.nextTick(function() { - resume_(stream, state); - }); - } - } - - function resume_(stream, state) { - state.resumeScheduled = false; - stream.emit('resume'); - flow(stream); - if (state.flowing && !state.reading) - stream.read(0); - } - - Readable.prototype.pause = function() { - debug('call pause flowing=%j', this._readableState.flowing); - if (false !== this._readableState.flowing) { - debug('pause'); - this._readableState.flowing = false; - this.emit('pause'); - } - return this; - }; - - function flow(stream) { - var state = stream._readableState; - debug('flow', state.flowing); - if (state.flowing) { - do { - var chunk = stream.read(); - } while (null !== chunk && state.flowing); - } - } - - // wrap an old-style stream as the async data source. - // This is *not* part of the readable stream interface. - // It is an ugly unfortunate mess of history. - Readable.prototype.wrap = function(stream) { - var state = this._readableState; - var paused = false; - - var self = this; - stream.on('end', function() { - debug('wrapped end'); - if (state.decoder && !state.ended) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) - self.push(chunk); - } - - self.push(null); - }); - - stream.on('data', function(chunk) { - debug('wrapped data'); - if (state.decoder) - chunk = state.decoder.write(chunk); - if (!chunk || !state.objectMode && !chunk.length) - return; - - var ret = self.push(chunk); - if (!ret) { - paused = true; - stream.pause(); - } - }); - - // proxy all the other methods. - // important when wrapping filters and duplexes. - for (var i in stream) { - if (util.isFunction(stream[i]) && util.isUndefined(this[i])) { - this[i] = function(method) { return function() { - return stream[method].apply(stream, arguments); - }}(i); - } - } - - // proxy certain important events. - var events = ['error', 'close', 'destroy', 'pause', 'resume']; - forEach(events, function(ev) { - stream.on(ev, self.emit.bind(self, ev)); - }); - - // when we try to consume some more bytes, simply unpause the - // underlying stream. - self._read = function(n) { - debug('wrapped _read', n); - if (paused) { - paused = false; - stream.resume(); - } - }; - - return self; - }; - - - - // exposed for testing purposes only. - Readable._fromList = fromList; - - // Pluck off n bytes from an array of buffers. - // Length is the combined lengths of all the buffers in the list. - function fromList(n, state) { - var list = state.buffer; - var length = state.length; - var stringMode = !!state.decoder; - var objectMode = !!state.objectMode; - var ret; - - // nothing in the list, definitely empty. - if (list.length === 0) - return null; - - if (length === 0) - ret = null; - else if (objectMode) - ret = list.shift(); - else if (!n || n >= length) { - // read it all, truncate the array. - if (stringMode) - ret = list.join(''); - else - ret = Buffer.concat(list, length); - list.length = 0; - } else { - // read just some of it. - if (n < list[0].length) { - // just take a part of the first list item. - // slice is the same for buffers and strings. - var buf = list[0]; - ret = buf.slice(0, n); - list[0] = buf.slice(n); - } else if (n === list[0].length) { - // first list is a perfect match - ret = list.shift(); - } else { - // complex case. - // we have enough to cover it, but it spans past the first buffer. - if (stringMode) - ret = ''; - else - ret = new Buffer(n); - - var c = 0; - for (var i = 0, l = list.length; i < l && c < n; i++) { - var buf = list[0]; - var cpy = Math.min(n - c, buf.length); - - if (stringMode) - ret += buf.slice(0, cpy); - else - buf.copy(ret, c, 0, cpy); - - if (cpy < buf.length) - list[0] = buf.slice(cpy); - else - list.shift(); - - c += cpy; - } - } - } - - return ret; - } - - function endReadable(stream) { - var state = stream._readableState; - - // If we get here before consuming all the bytes, then that is a - // bug in node. Should never happen. - if (state.length > 0) - throw new Error('endReadable called on non-empty stream'); - - if (!state.endEmitted) { - state.ended = true; - process.nextTick(function() { - // Check that we didn't get one last unshift. - if (!state.endEmitted && state.length === 0) { - state.endEmitted = true; - stream.readable = false; - stream.emit('end'); - } - }); - } - } - - function forEach (xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } - } - - function indexOf (xs, x) { - for (var i = 0, l = xs.length; i < l; i++) { - if (xs[i] === x) return i; - } - return -1; - } - - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) - -/***/ }, -/* 33 */ -/***/ function(module, exports) { - - module.exports = Array.isArray || function (arr) { - return Object.prototype.toString.call(arr) == '[object Array]'; - }; - - -/***/ }, -/* 34 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(Buffer, global) {/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> - * @license MIT - */ - /* eslint-disable no-proto */ - - 'use strict' - - var base64 = __webpack_require__(35) - var ieee754 = __webpack_require__(36) - var isArray = __webpack_require__(37) - - exports.Buffer = Buffer - exports.SlowBuffer = SlowBuffer - exports.INSPECT_MAX_BYTES = 50 - Buffer.poolSize = 8192 // not used by this implementation - - var rootParent = {} - - /** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Use Object implementation (most compatible, even IE6) - * - * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, - * Opera 11.6+, iOS 4.2+. - * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. - * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property - * on objects. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. - - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. - */ - Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined - ? global.TYPED_ARRAY_SUPPORT - : typedArraySupport() - - function typedArraySupport () { - function Bar () {} - try { - var arr = new Uint8Array(1) - arr.foo = function () { return 42 } - arr.constructor = Bar - return arr.foo() === 42 && // typed array instances can be augmented - arr.constructor === Bar && // constructor can be set - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` - } catch (e) { - return false - } - } - - function kMaxLength () { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff - } - - /** - * Class: Buffer - * ============= - * - * The Buffer constructor returns instances of `Uint8Array` that are augmented - * with function properties for all the node `Buffer` API functions. We use - * `Uint8Array` so that square bracket notation works as expected -- it returns - * a single octet. - * - * By augmenting the instances, we can avoid modifying the `Uint8Array` - * prototype. - */ - function Buffer (arg) { - if (!(this instanceof Buffer)) { - // Avoid going through an ArgumentsAdaptorTrampoline in the common case. - if (arguments.length > 1) return new Buffer(arg, arguments[1]) - return new Buffer(arg) - } - - if (!Buffer.TYPED_ARRAY_SUPPORT) { - this.length = 0 - this.parent = undefined - } - - // Common case. - if (typeof arg === 'number') { - return fromNumber(this, arg) - } - - // Slightly less common case. - if (typeof arg === 'string') { - return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8') - } - - // Unusual. - return fromObject(this, arg) - } - - function fromNumber (that, length) { - that = allocate(that, length < 0 ? 0 : checked(length) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < length; i++) { - that[i] = 0 - } - } - return that - } - - function fromString (that, string, encoding) { - if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8' - - // Assumption: byteLength() return value is always < kMaxLength. - var length = byteLength(string, encoding) | 0 - that = allocate(that, length) - - that.write(string, encoding) - return that - } - - function fromObject (that, object) { - if (Buffer.isBuffer(object)) return fromBuffer(that, object) - - if (isArray(object)) return fromArray(that, object) - - if (object == null) { - throw new TypeError('must start with number, buffer, array or string') - } - - if (typeof ArrayBuffer !== 'undefined') { - if (object.buffer instanceof ArrayBuffer) { - return fromTypedArray(that, object) - } - if (object instanceof ArrayBuffer) { - return fromArrayBuffer(that, object) - } - } - - if (object.length) return fromArrayLike(that, object) - - return fromJsonObject(that, object) - } - - function fromBuffer (that, buffer) { - var length = checked(buffer.length) | 0 - that = allocate(that, length) - buffer.copy(that, 0, 0, length) - return that - } - - function fromArray (that, array) { - var length = checked(array.length) | 0 - that = allocate(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that - } - - // Duplicate of fromArray() to keep fromArray() monomorphic. - function fromTypedArray (that, array) { - var length = checked(array.length) | 0 - that = allocate(that, length) - // Truncating the elements is probably not what people expect from typed - // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior - // of the old Buffer constructor. - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that - } - - function fromArrayBuffer (that, array) { - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - array.byteLength - that = Buffer._augment(new Uint8Array(array)) - } else { - // Fallback: Return an object instance of the Buffer class - that = fromTypedArray(that, new Uint8Array(array)) - } - return that - } - - function fromArrayLike (that, array) { - var length = checked(array.length) | 0 - that = allocate(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that - } - - // Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object. - // Returns a zero-length buffer for inputs that don't conform to the spec. - function fromJsonObject (that, object) { - var array - var length = 0 - - if (object.type === 'Buffer' && isArray(object.data)) { - array = object.data - length = checked(array.length) | 0 - } - that = allocate(that, length) - - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that - } - - if (Buffer.TYPED_ARRAY_SUPPORT) { - Buffer.prototype.__proto__ = Uint8Array.prototype - Buffer.__proto__ = Uint8Array - } else { - // pre-set for values that may exist in the future - Buffer.prototype.length = undefined - Buffer.prototype.parent = undefined - } - - function allocate (that, length) { - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = Buffer._augment(new Uint8Array(length)) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that.length = length - that._isBuffer = true - } - - var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1 - if (fromPool) that.parent = rootParent - - return that - } - - function checked (length) { - // Note: cannot use `length < kMaxLength` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') - } - return length | 0 - } - - function SlowBuffer (subject, encoding) { - if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding) - - var buf = new Buffer(subject, encoding) - delete buf.parent - return buf - } - - Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) - } - - Buffer.compare = function compare (a, b) { - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') - } - - if (a === b) return 0 - - var x = a.length - var y = b.length - - var i = 0 - var len = Math.min(x, y) - while (i < len) { - if (a[i] !== b[i]) break - - ++i - } - - if (i !== len) { - x = a[i] - y = b[i] - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 - } - - Buffer.isEncoding = function isEncoding (encoding) { - switch (String(encoding).toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'binary': - case 'base64': - case 'raw': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } - } - - Buffer.concat = function concat (list, length) { - if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.') - - if (list.length === 0) { - return new Buffer(0) - } - - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; i++) { - length += list[i].length - } - } - - var buf = new Buffer(length) - var pos = 0 - for (i = 0; i < list.length; i++) { - var item = list[i] - item.copy(buf, pos) - pos += item.length - } - return buf - } - - function byteLength (string, encoding) { - if (typeof string !== 'string') string = '' + string - - var len = string.length - if (len === 0) return 0 - - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'binary': - // Deprecated - case 'raw': - case 'raws': - return len - case 'utf8': - case 'utf-8': - return utf8ToBytes(string).length - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return len * 2 - case 'hex': - return len >>> 1 - case 'base64': - return base64ToBytes(string).length - default: - if (loweredCase) return utf8ToBytes(string).length // assume utf8 - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } - } - Buffer.byteLength = byteLength - - function slowToString (encoding, start, end) { - var loweredCase = false - - start = start | 0 - end = end === undefined || end === Infinity ? this.length : end | 0 - - if (!encoding) encoding = 'utf8' - if (start < 0) start = 0 - if (end > this.length) end = this.length - if (end <= start) return '' - - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) - - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) - - case 'ascii': - return asciiSlice(this, start, end) - - case 'binary': - return binarySlice(this, start, end) - - case 'base64': - return base64Slice(this, start, end) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } - } - - Buffer.prototype.toString = function toString () { - var length = this.length | 0 - if (length === 0) return '' - if (arguments.length === 0) return utf8Slice(this, 0, length) - return slowToString.apply(this, arguments) - } - - Buffer.prototype.equals = function equals (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return true - return Buffer.compare(this, b) === 0 - } - - Buffer.prototype.inspect = function inspect () { - var str = '' - var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) str += ' ... ' - } - return '<Buffer ' + str + '>' - } - - Buffer.prototype.compare = function compare (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return 0 - return Buffer.compare(this, b) - } - - Buffer.prototype.indexOf = function indexOf (val, byteOffset) { - if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff - else if (byteOffset < -0x80000000) byteOffset = -0x80000000 - byteOffset >>= 0 - - if (this.length === 0) return -1 - if (byteOffset >= this.length) return -1 - - // Negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0) - - if (typeof val === 'string') { - if (val.length === 0) return -1 // special case: looking for empty string always fails - return String.prototype.indexOf.call(this, val, byteOffset) - } - if (Buffer.isBuffer(val)) { - return arrayIndexOf(this, val, byteOffset) - } - if (typeof val === 'number') { - if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') { - return Uint8Array.prototype.indexOf.call(this, val, byteOffset) - } - return arrayIndexOf(this, [ val ], byteOffset) - } - - function arrayIndexOf (arr, val, byteOffset) { - var foundIndex = -1 - for (var i = 0; byteOffset + i < arr.length; i++) { - if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex - } else { - foundIndex = -1 - } - } - return -1 - } - - throw new TypeError('val must be string, number or Buffer') - } - - // `get` is deprecated - Buffer.prototype.get = function get (offset) { - console.log('.get() is deprecated. Access using array indexes instead.') - return this.readUInt8(offset) - } - - // `set` is deprecated - Buffer.prototype.set = function set (v, offset) { - console.log('.set() is deprecated. Access using array indexes instead.') - return this.writeUInt8(v, offset) - } - - function hexWrite (buf, string, offset, length) { - offset = Number(offset) || 0 - var remaining = buf.length - offset - if (!length) { - length = remaining - } else { - length = Number(length) - if (length > remaining) { - length = remaining - } - } - - // must be an even number of digits - var strLen = string.length - if (strLen % 2 !== 0) throw new Error('Invalid hex string') - - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; i++) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) throw new Error('Invalid hex string') - buf[offset + i] = parsed - } - return i - } - - function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) - } - - function asciiWrite (buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) - } - - function binaryWrite (buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) - } - - function base64Write (buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) - } - - function ucs2Write (buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) - } - - Buffer.prototype.write = function write (string, offset, length, encoding) { - // Buffer#write(string) - if (offset === undefined) { - encoding = 'utf8' - length = this.length - offset = 0 - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - encoding = offset - length = this.length - offset = 0 - // Buffer#write(string, offset[, length][, encoding]) - } else if (isFinite(offset)) { - offset = offset | 0 - if (isFinite(length)) { - length = length | 0 - if (encoding === undefined) encoding = 'utf8' - } else { - encoding = length - length = undefined - } - // legacy write(string, encoding, offset, length) - remove in v0.13 - } else { - var swap = encoding - encoding = offset - offset = length | 0 - length = swap - } - - var remaining = this.length - offset - if (length === undefined || length > remaining) length = remaining - - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('attempt to write outside buffer bounds') - } - - if (!encoding) encoding = 'utf8' - - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) - - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) - - case 'ascii': - return asciiWrite(this, string, offset, length) - - case 'binary': - return binaryWrite(this, string, offset, length) - - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } - } - - Buffer.prototype.toJSON = function toJSON () { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) - } - } - - function base64Slice (buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } - } - - function utf8Slice (buf, start, end) { - end = Math.min(buf.length, end) - var res = [] - - var i = start - while (i < end) { - var firstByte = buf[i] - var codePoint = null - var bytesPerSequence = (firstByte > 0xEF) ? 4 - : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 - - if (i + bytesPerSequence <= end) { - var secondByte, thirdByte, fourthByte, tempCodePoint - - switch (bytesPerSequence) { - case 1: - if (firstByte < 0x80) { - codePoint = firstByte - } - break - case 2: - secondByte = buf[i + 1] - if ((secondByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) - if (tempCodePoint > 0x7F) { - codePoint = tempCodePoint - } - } - break - case 3: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) - if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { - codePoint = tempCodePoint - } - } - break - case 4: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - fourthByte = buf[i + 3] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) - if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { - codePoint = tempCodePoint - } - } - } - } - - if (codePoint === null) { - // we did not generate a valid codePoint so insert a - // replacement char (U+FFFD) and advance only 1 byte - codePoint = 0xFFFD - bytesPerSequence = 1 - } else if (codePoint > 0xFFFF) { - // encode to utf16 (surrogate pair dance) - codePoint -= 0x10000 - res.push(codePoint >>> 10 & 0x3FF | 0xD800) - codePoint = 0xDC00 | codePoint & 0x3FF - } - - res.push(codePoint) - i += bytesPerSequence - } - - return decodeCodePointsArray(res) - } - - // Based on http://stackoverflow.com/a/22747272/680742, the browser with - // the lowest limit is Chrome, with 0x10000 args. - // We go 1 magnitude less, for safety - var MAX_ARGUMENTS_LENGTH = 0x1000 - - function decodeCodePointsArray (codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() - } - - // Decode in chunks to avoid "call stack size exceeded". - var res = '' - var i = 0 - while (i < len) { - res += String.fromCharCode.apply( - String, - codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) - ) - } - return res - } - - function asciiSlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; i++) { - ret += String.fromCharCode(buf[i] & 0x7F) - } - return ret - } - - function binarySlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; i++) { - ret += String.fromCharCode(buf[i]) - } - return ret - } - - function hexSlice (buf, start, end) { - var len = buf.length - - if (!start || start < 0) start = 0 - if (!end || end < 0 || end > len) end = len - - var out = '' - for (var i = start; i < end; i++) { - out += toHex(buf[i]) - } - return out - } - - function utf16leSlice (buf, start, end) { - var bytes = buf.slice(start, end) - var res = '' - for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) - } - return res - } - - Buffer.prototype.slice = function slice (start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end - - if (start < 0) { - start += len - if (start < 0) start = 0 - } else if (start > len) { - start = len - } - - if (end < 0) { - end += len - if (end < 0) end = 0 - } else if (end > len) { - end = len - } - - if (end < start) end = start - - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = Buffer._augment(this.subarray(start, end)) - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; i++) { - newBuf[i] = this[i + start] - } - } - - if (newBuf.length) newBuf.parent = this.parent || this - - return newBuf - } - - /* - * Need to make sure that buffer isn't trying to write out of bounds. - */ - function checkOffset (offset, ext, length) { - if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') - if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') - } - - Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - - return val - } - - Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } - - return val - } - - Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - return this[offset] - } - - Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return this[offset] | (this[offset + 1] << 8) - } - - Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return (this[offset] << 8) | this[offset + 1] - } - - Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) - } - - Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) - } - - Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val - } - - Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val - } - - Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - if (!(this[offset] & 0x80)) return (this[offset]) - return ((0xff - this[offset] + 1) * -1) - } - - Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val - } - - Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val - } - - Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) - } - - Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) - } - - Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, true, 23, 4) - } - - Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, false, 23, 4) - } - - Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, true, 52, 8) - } - - Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, false, 52, 8) - } - - function checkInt (buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance') - if (value > max || value < min) throw new RangeError('value is out of bounds') - if (offset + ext > buf.length) throw new RangeError('index out of range') - } - - Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) - - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength - } - - Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) - - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength - } - - Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - this[offset] = (value & 0xff) - return offset + 1 - } - - function objectWriteUInt16 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } - } - - Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 - } - - Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 - } - - function objectWriteUInt32 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffffffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } - } - - Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 - } - - Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 - } - - Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = 0 - var mul = 1 - var sub = value < 0 ? 1 : 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength - } - - Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = byteLength - 1 - var mul = 1 - var sub = value < 0 ? 1 : 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength - } - - Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - if (value < 0) value = 0xff + value + 1 - this[offset] = (value & 0xff) - return offset + 1 - } - - Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 - } - - Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 - } - - Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 - } - - Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (value < 0) value = 0xffffffff + value + 1 - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 - } - - function checkIEEE754 (buf, value, offset, ext, max, min) { - if (value > max || value < min) throw new RangeError('value is out of bounds') - if (offset + ext > buf.length) throw new RangeError('index out of range') - if (offset < 0) throw new RangeError('index out of range') - } - - function writeFloat (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) - } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 - } - - Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) - } - - Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) - } - - function writeDouble (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 - } - - Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) - } - - Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) - } - - // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) - Buffer.prototype.copy = function copy (target, targetStart, start, end) { - if (!start) start = 0 - if (!end && end !== 0) end = this.length - if (targetStart >= target.length) targetStart = target.length - if (!targetStart) targetStart = 0 - if (end > 0 && end < start) end = start - - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 - - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') - if (end < 0) throw new RangeError('sourceEnd out of bounds') - - // Are we oob? - if (end > this.length) end = this.length - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start - } - - var len = end - start - var i - - if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (i = len - 1; i >= 0; i--) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; i++) { - target[i + targetStart] = this[i + start] - } - } else { - target._set(this.subarray(start, start + len), targetStart) - } - - return len - } - - // fill(value, start=0, end=buffer.length) - Buffer.prototype.fill = function fill (value, start, end) { - if (!value) value = 0 - if (!start) start = 0 - if (!end) end = this.length - - if (end < start) throw new RangeError('end < start') - - // Fill 0 bytes; we're done - if (end === start) return - if (this.length === 0) return - - if (start < 0 || start >= this.length) throw new RangeError('start out of bounds') - if (end < 0 || end > this.length) throw new RangeError('end out of bounds') - - var i - if (typeof value === 'number') { - for (i = start; i < end; i++) { - this[i] = value - } - } else { - var bytes = utf8ToBytes(value.toString()) - var len = bytes.length - for (i = start; i < end; i++) { - this[i] = bytes[i % len] - } - } - - return this - } - - /** - * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. - * Added in Node 0.12. Only available in browsers that support ArrayBuffer. - */ - Buffer.prototype.toArrayBuffer = function toArrayBuffer () { - if (typeof Uint8Array !== 'undefined') { - if (Buffer.TYPED_ARRAY_SUPPORT) { - return (new Buffer(this)).buffer - } else { - var buf = new Uint8Array(this.length) - for (var i = 0, len = buf.length; i < len; i += 1) { - buf[i] = this[i] - } - return buf.buffer - } - } else { - throw new TypeError('Buffer.toArrayBuffer not supported in this browser') - } - } - - // HELPER FUNCTIONS - // ================ - - var BP = Buffer.prototype - - /** - * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods - */ - Buffer._augment = function _augment (arr) { - arr.constructor = Buffer - arr._isBuffer = true - - // save reference to original Uint8Array set method before overwriting - arr._set = arr.set - - // deprecated - arr.get = BP.get - arr.set = BP.set - - arr.write = BP.write - arr.toString = BP.toString - arr.toLocaleString = BP.toString - arr.toJSON = BP.toJSON - arr.equals = BP.equals - arr.compare = BP.compare - arr.indexOf = BP.indexOf - arr.copy = BP.copy - arr.slice = BP.slice - arr.readUIntLE = BP.readUIntLE - arr.readUIntBE = BP.readUIntBE - arr.readUInt8 = BP.readUInt8 - arr.readUInt16LE = BP.readUInt16LE - arr.readUInt16BE = BP.readUInt16BE - arr.readUInt32LE = BP.readUInt32LE - arr.readUInt32BE = BP.readUInt32BE - arr.readIntLE = BP.readIntLE - arr.readIntBE = BP.readIntBE - arr.readInt8 = BP.readInt8 - arr.readInt16LE = BP.readInt16LE - arr.readInt16BE = BP.readInt16BE - arr.readInt32LE = BP.readInt32LE - arr.readInt32BE = BP.readInt32BE - arr.readFloatLE = BP.readFloatLE - arr.readFloatBE = BP.readFloatBE - arr.readDoubleLE = BP.readDoubleLE - arr.readDoubleBE = BP.readDoubleBE - arr.writeUInt8 = BP.writeUInt8 - arr.writeUIntLE = BP.writeUIntLE - arr.writeUIntBE = BP.writeUIntBE - arr.writeUInt16LE = BP.writeUInt16LE - arr.writeUInt16BE = BP.writeUInt16BE - arr.writeUInt32LE = BP.writeUInt32LE - arr.writeUInt32BE = BP.writeUInt32BE - arr.writeIntLE = BP.writeIntLE - arr.writeIntBE = BP.writeIntBE - arr.writeInt8 = BP.writeInt8 - arr.writeInt16LE = BP.writeInt16LE - arr.writeInt16BE = BP.writeInt16BE - arr.writeInt32LE = BP.writeInt32LE - arr.writeInt32BE = BP.writeInt32BE - arr.writeFloatLE = BP.writeFloatLE - arr.writeFloatBE = BP.writeFloatBE - arr.writeDoubleLE = BP.writeDoubleLE - arr.writeDoubleBE = BP.writeDoubleBE - arr.fill = BP.fill - arr.inspect = BP.inspect - arr.toArrayBuffer = BP.toArrayBuffer - - return arr - } - - var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g - - function base64clean (str) { - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).replace(INVALID_BASE64_RE, '') - // Node converts strings with length < 2 to '' - if (str.length < 2) return '' - // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not - while (str.length % 4 !== 0) { - str = str + '=' - } - return str - } - - function stringtrim (str) { - if (str.trim) return str.trim() - return str.replace(/^\s+|\s+$/g, '') - } - - function toHex (n) { - if (n < 16) return '0' + n.toString(16) - return n.toString(16) - } - - function utf8ToBytes (string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] - - for (var i = 0; i < length; i++) { - codePoint = string.charCodeAt(i) - - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } - - // valid lead - leadSurrogate = codePoint - - continue - } - - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - leadSurrogate = codePoint - continue - } - - // valid surrogate pair - codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - } - - leadSurrogate = null - - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) break - bytes.push(codePoint) - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) break - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) break - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) break - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else { - throw new Error('Invalid code point') - } - } - - return bytes - } - - function asciiToBytes (str) { - var byteArray = [] - for (var i = 0; i < str.length; i++) { - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push(str.charCodeAt(i) & 0xFF) - } - return byteArray - } - - function utf16leToBytes (str, units) { - var c, hi, lo - var byteArray = [] - for (var i = 0; i < str.length; i++) { - if ((units -= 2) < 0) break - - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } - - return byteArray - } - - function base64ToBytes (str) { - return base64.toByteArray(base64clean(str)) - } - - function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; i++) { - if ((i + offset >= dst.length) || (i >= src.length)) break - dst[i + offset] = src[i] - } - return i - } - - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(34).Buffer, (function() { return this; }()))) - -/***/ }, -/* 35 */ -/***/ function(module, exports, __webpack_require__) { - - var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - - ;(function (exports) { - 'use strict'; - - var Arr = (typeof Uint8Array !== 'undefined') - ? Uint8Array - : Array - - var PLUS = '+'.charCodeAt(0) - var SLASH = '/'.charCodeAt(0) - var NUMBER = '0'.charCodeAt(0) - var LOWER = 'a'.charCodeAt(0) - var UPPER = 'A'.charCodeAt(0) - var PLUS_URL_SAFE = '-'.charCodeAt(0) - var SLASH_URL_SAFE = '_'.charCodeAt(0) - - function decode (elt) { - var code = elt.charCodeAt(0) - if (code === PLUS || - code === PLUS_URL_SAFE) - return 62 // '+' - if (code === SLASH || - code === SLASH_URL_SAFE) - return 63 // '/' - if (code < NUMBER) - return -1 //no match - if (code < NUMBER + 10) - return code - NUMBER + 26 + 26 - if (code < UPPER + 26) - return code - UPPER - if (code < LOWER + 26) - return code - LOWER + 26 - } - - function b64ToByteArray (b64) { - var i, j, l, tmp, placeHolders, arr - - if (b64.length % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - var len = b64.length - placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 - - // base64 is 4/3 + up to two characters of the original data - arr = new Arr(b64.length * 3 / 4 - placeHolders) - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? b64.length - 4 : b64.length - - var L = 0 - - function push (v) { - arr[L++] = v - } - - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) - push((tmp & 0xFF0000) >> 16) - push((tmp & 0xFF00) >> 8) - push(tmp & 0xFF) - } - - if (placeHolders === 2) { - tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) - push(tmp & 0xFF) - } else if (placeHolders === 1) { - tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) - push((tmp >> 8) & 0xFF) - push(tmp & 0xFF) - } - - return arr - } - - function uint8ToBase64 (uint8) { - var i, - extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes - output = "", - temp, length - - function encode (num) { - return lookup.charAt(num) - } - - function tripletToBase64 (num) { - return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) - } - - // go through the array every three bytes, we'll deal with trailing stuff later - for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { - temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output += tripletToBase64(temp) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - switch (extraBytes) { - case 1: - temp = uint8[uint8.length - 1] - output += encode(temp >> 2) - output += encode((temp << 4) & 0x3F) - output += '==' - break - case 2: - temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) - output += encode(temp >> 10) - output += encode((temp >> 4) & 0x3F) - output += encode((temp << 2) & 0x3F) - output += '=' - break - } - - return output - } - - exports.toByteArray = b64ToByteArray - exports.fromByteArray = uint8ToBase64 - }( false ? (this.base64js = {}) : exports)) - - -/***/ }, -/* 36 */ -/***/ function(module, exports) { - - exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) - } - - exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 - } - - -/***/ }, -/* 37 */ -/***/ function(module, exports) { - - var toString = {}.toString; - - module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; - }; - - -/***/ }, -/* 38 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(Buffer) {// Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - // NOTE: These type checking functions intentionally don't use `instanceof` - // because it is fragile and can be easily faked with `Object.create()`. - - function isArray(arg) { - if (Array.isArray) { - return Array.isArray(arg); - } - return objectToString(arg) === '[object Array]'; - } - exports.isArray = isArray; - - function isBoolean(arg) { - return typeof arg === 'boolean'; - } - exports.isBoolean = isBoolean; - - function isNull(arg) { - return arg === null; - } - exports.isNull = isNull; - - function isNullOrUndefined(arg) { - return arg == null; - } - exports.isNullOrUndefined = isNullOrUndefined; - - function isNumber(arg) { - return typeof arg === 'number'; - } - exports.isNumber = isNumber; - - function isString(arg) { - return typeof arg === 'string'; - } - exports.isString = isString; - - function isSymbol(arg) { - return typeof arg === 'symbol'; - } - exports.isSymbol = isSymbol; - - function isUndefined(arg) { - return arg === void 0; - } - exports.isUndefined = isUndefined; - - function isRegExp(re) { - return objectToString(re) === '[object RegExp]'; - } - exports.isRegExp = isRegExp; - - function isObject(arg) { - return typeof arg === 'object' && arg !== null; - } - exports.isObject = isObject; - - function isDate(d) { - return objectToString(d) === '[object Date]'; - } - exports.isDate = isDate; - - function isError(e) { - return (objectToString(e) === '[object Error]' || e instanceof Error); - } - exports.isError = isError; - - function isFunction(arg) { - return typeof arg === 'function'; - } - exports.isFunction = isFunction; - - function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; - } - exports.isPrimitive = isPrimitive; - - exports.isBuffer = Buffer.isBuffer; - - function objectToString(o) { - return Object.prototype.toString.call(o); - } - - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(34).Buffer)) - -/***/ }, -/* 39 */ -/***/ function(module, exports) { - - if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; - } else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } - } - - -/***/ }, -/* 40 */ -/***/ function(module, exports) { - - /* (ignored) */ - -/***/ }, -/* 41 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - // a duplex stream is just a stream that is both readable and writable. - // Since JS doesn't have multiple prototypal inheritance, this class - // prototypally inherits from Readable, and then parasitically from - // Writable. - - module.exports = Duplex; - - /*<replacement>*/ - var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) keys.push(key); - return keys; - } - /*</replacement>*/ - - - /*<replacement>*/ - var util = __webpack_require__(38); - util.inherits = __webpack_require__(39); - /*</replacement>*/ - - var Readable = __webpack_require__(32); - var Writable = __webpack_require__(42); - - util.inherits(Duplex, Readable); - - forEach(objectKeys(Writable.prototype), function(method) { - if (!Duplex.prototype[method]) - Duplex.prototype[method] = Writable.prototype[method]; - }); - - function Duplex(options) { - if (!(this instanceof Duplex)) - return new Duplex(options); - - Readable.call(this, options); - Writable.call(this, options); - - if (options && options.readable === false) - this.readable = false; - - if (options && options.writable === false) - this.writable = false; - - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) - this.allowHalfOpen = false; - - this.once('end', onend); - } - - // the no-half-open enforcer - function onend() { - // if we allow half-open state, or if the writable side ended, - // then we're ok. - if (this.allowHalfOpen || this._writableState.ended) - return; - - // no more data can be written. - // But allow more writes to happen in this tick. - process.nextTick(this.end.bind(this)); - } - - function forEach (xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } - } - - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) - -/***/ }, -/* 42 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - // A bit simpler than readable streams. - // Implement an async ._write(chunk, cb), and it'll handle all - // the drain event emission and buffering. - - module.exports = Writable; - - /*<replacement>*/ - var Buffer = __webpack_require__(34).Buffer; - /*</replacement>*/ - - Writable.WritableState = WritableState; - - - /*<replacement>*/ - var util = __webpack_require__(38); - util.inherits = __webpack_require__(39); - /*</replacement>*/ - - var Stream = __webpack_require__(29); - - util.inherits(Writable, Stream); - - function WriteReq(chunk, encoding, cb) { - this.chunk = chunk; - this.encoding = encoding; - this.callback = cb; - } - - function WritableState(options, stream) { - var Duplex = __webpack_require__(41); - - options = options || {}; - - // the point at which write() starts returning false - // Note: 0 is a valid value, means that we always return false if - // the entire buffer is not flushed immediately on write() - var hwm = options.highWaterMark; - var defaultHwm = options.objectMode ? 16 : 16 * 1024; - this.highWaterMark = (hwm || hwm === 0) ? hwm : defaultHwm; - - // object stream flag to indicate whether or not this stream - // contains buffers or objects. - this.objectMode = !!options.objectMode; - - if (stream instanceof Duplex) - this.objectMode = this.objectMode || !!options.writableObjectMode; - - // cast to ints. - this.highWaterMark = ~~this.highWaterMark; - - this.needDrain = false; - // at the start of calling end() - this.ending = false; - // when end() has been called, and returned - this.ended = false; - // when 'finish' is emitted - this.finished = false; - - // should we decode strings into buffers before passing to _write? - // this is here so that some node-core streams can optimize string - // handling at a lower level. - var noDecode = options.decodeStrings === false; - this.decodeStrings = !noDecode; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // not an actual buffer we keep track of, but a measurement - // of how much we're waiting to get pushed to some underlying - // socket or file. - this.length = 0; - - // a flag to see when we're in the middle of a write. - this.writing = false; - - // when true all writes will be buffered until .uncork() call - this.corked = 0; - - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // a flag to know if we're processing previously buffered items, which - // may call the _write() callback in the same tick, so that we don't - // end up in an overlapped onwrite situation. - this.bufferProcessing = false; - - // the callback that's passed to _write(chunk,cb) - this.onwrite = function(er) { - onwrite(stream, er); - }; - - // the callback that the user supplies to write(chunk,encoding,cb) - this.writecb = null; - - // the amount that is being written when _write is called. - this.writelen = 0; - - this.buffer = []; - - // number of pending user-supplied write callbacks - // this must be 0 before 'finish' can be emitted - this.pendingcb = 0; - - // emit prefinish if the only thing we're waiting for is _write cbs - // This is relevant for synchronous Transform streams - this.prefinished = false; - - // True if the error was already emitted and should not be thrown again - this.errorEmitted = false; - } - - function Writable(options) { - var Duplex = __webpack_require__(41); - - // Writable ctor is applied to Duplexes, though they're not - // instanceof Writable, they're instanceof Readable. - if (!(this instanceof Writable) && !(this instanceof Duplex)) - return new Writable(options); - - this._writableState = new WritableState(options, this); - - // legacy. - this.writable = true; - - Stream.call(this); - } - - // Otherwise people can pipe Writable streams, which is just wrong. - Writable.prototype.pipe = function() { - this.emit('error', new Error('Cannot pipe. Not readable.')); - }; - - - function writeAfterEnd(stream, state, cb) { - var er = new Error('write after end'); - // TODO: defer error events consistently everywhere, not just the cb - stream.emit('error', er); - process.nextTick(function() { - cb(er); - }); - } - - // If we get something that is not a buffer, string, null, or undefined, - // and we're not in objectMode, then that's an error. - // Otherwise stream chunks are all considered to be of length=1, and the - // watermarks determine how many objects to keep in the buffer, rather than - // how many bytes or characters. - function validChunk(stream, state, chunk, cb) { - var valid = true; - if (!util.isBuffer(chunk) && - !util.isString(chunk) && - !util.isNullOrUndefined(chunk) && - !state.objectMode) { - var er = new TypeError('Invalid non-string/buffer chunk'); - stream.emit('error', er); - process.nextTick(function() { - cb(er); - }); - valid = false; - } - return valid; - } - - Writable.prototype.write = function(chunk, encoding, cb) { - var state = this._writableState; - var ret = false; - - if (util.isFunction(encoding)) { - cb = encoding; - encoding = null; - } - - if (util.isBuffer(chunk)) - encoding = 'buffer'; - else if (!encoding) - encoding = state.defaultEncoding; - - if (!util.isFunction(cb)) - cb = function() {}; - - if (state.ended) - writeAfterEnd(this, state, cb); - else if (validChunk(this, state, chunk, cb)) { - state.pendingcb++; - ret = writeOrBuffer(this, state, chunk, encoding, cb); - } - - return ret; - }; - - Writable.prototype.cork = function() { - var state = this._writableState; - - state.corked++; - }; - - Writable.prototype.uncork = function() { - var state = this._writableState; - - if (state.corked) { - state.corked--; - - if (!state.writing && - !state.corked && - !state.finished && - !state.bufferProcessing && - state.buffer.length) - clearBuffer(this, state); - } - }; - - function decodeChunk(state, chunk, encoding) { - if (!state.objectMode && - state.decodeStrings !== false && - util.isString(chunk)) { - chunk = new Buffer(chunk, encoding); - } - return chunk; - } - - // if we're already writing something, then just put this - // in the queue, and wait our turn. Otherwise, call _write - // If we return false, then we need a drain event, so set that flag. - function writeOrBuffer(stream, state, chunk, encoding, cb) { - chunk = decodeChunk(state, chunk, encoding); - if (util.isBuffer(chunk)) - encoding = 'buffer'; - var len = state.objectMode ? 1 : chunk.length; - - state.length += len; - - var ret = state.length < state.highWaterMark; - // we must ensure that previous needDrain will not be reset to false. - if (!ret) - state.needDrain = true; - - if (state.writing || state.corked) - state.buffer.push(new WriteReq(chunk, encoding, cb)); - else - doWrite(stream, state, false, len, chunk, encoding, cb); - - return ret; - } - - function doWrite(stream, state, writev, len, chunk, encoding, cb) { - state.writelen = len; - state.writecb = cb; - state.writing = true; - state.sync = true; - if (writev) - stream._writev(chunk, state.onwrite); - else - stream._write(chunk, encoding, state.onwrite); - state.sync = false; - } - - function onwriteError(stream, state, sync, er, cb) { - if (sync) - process.nextTick(function() { - state.pendingcb--; - cb(er); - }); - else { - state.pendingcb--; - cb(er); - } - - stream._writableState.errorEmitted = true; - stream.emit('error', er); - } - - function onwriteStateUpdate(state) { - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; - } - - function onwrite(stream, er) { - var state = stream._writableState; - var sync = state.sync; - var cb = state.writecb; - - onwriteStateUpdate(state); - - if (er) - onwriteError(stream, state, sync, er, cb); - else { - // Check if we're actually ready to finish, but don't emit yet - var finished = needFinish(stream, state); - - if (!finished && - !state.corked && - !state.bufferProcessing && - state.buffer.length) { - clearBuffer(stream, state); - } - - if (sync) { - process.nextTick(function() { - afterWrite(stream, state, finished, cb); - }); - } else { - afterWrite(stream, state, finished, cb); - } - } - } - - function afterWrite(stream, state, finished, cb) { - if (!finished) - onwriteDrain(stream, state); - state.pendingcb--; - cb(); - finishMaybe(stream, state); - } - - // Must force callback to be called on nextTick, so that we don't - // emit 'drain' before the write() consumer gets the 'false' return - // value, and has a chance to attach a 'drain' listener. - function onwriteDrain(stream, state) { - if (state.length === 0 && state.needDrain) { - state.needDrain = false; - stream.emit('drain'); - } - } - - - // if there's something in the buffer waiting, then process it - function clearBuffer(stream, state) { - state.bufferProcessing = true; - - if (stream._writev && state.buffer.length > 1) { - // Fast case, write everything using _writev() - var cbs = []; - for (var c = 0; c < state.buffer.length; c++) - cbs.push(state.buffer[c].callback); - - // count the one we are adding, as well. - // TODO(isaacs) clean this up - state.pendingcb++; - doWrite(stream, state, true, state.length, state.buffer, '', function(err) { - for (var i = 0; i < cbs.length; i++) { - state.pendingcb--; - cbs[i](err); - } - }); - - // Clear buffer - state.buffer = []; - } else { - // Slow case, write chunks one-by-one - for (var c = 0; c < state.buffer.length; c++) { - var entry = state.buffer[c]; - var chunk = entry.chunk; - var encoding = entry.encoding; - var cb = entry.callback; - var len = state.objectMode ? 1 : chunk.length; - - doWrite(stream, state, false, len, chunk, encoding, cb); - - // if we didn't call the onwrite immediately, then - // it means that we need to wait until it does. - // also, that means that the chunk and cb are currently - // being processed, so move the buffer counter past them. - if (state.writing) { - c++; - break; - } - } - - if (c < state.buffer.length) - state.buffer = state.buffer.slice(c); - else - state.buffer.length = 0; - } - - state.bufferProcessing = false; - } - - Writable.prototype._write = function(chunk, encoding, cb) { - cb(new Error('not implemented')); - - }; - - Writable.prototype._writev = null; - - Writable.prototype.end = function(chunk, encoding, cb) { - var state = this._writableState; - - if (util.isFunction(chunk)) { - cb = chunk; - chunk = null; - encoding = null; - } else if (util.isFunction(encoding)) { - cb = encoding; - encoding = null; - } - - if (!util.isNullOrUndefined(chunk)) - this.write(chunk, encoding); - - // .end() fully uncorks - if (state.corked) { - state.corked = 1; - this.uncork(); - } - - // ignore unnecessary end() calls. - if (!state.ending && !state.finished) - endWritable(this, state, cb); - }; - - - function needFinish(stream, state) { - return (state.ending && - state.length === 0 && - !state.finished && - !state.writing); - } - - function prefinish(stream, state) { - if (!state.prefinished) { - state.prefinished = true; - stream.emit('prefinish'); - } - } - - function finishMaybe(stream, state) { - var need = needFinish(stream, state); - if (need) { - if (state.pendingcb === 0) { - prefinish(stream, state); - state.finished = true; - stream.emit('finish'); - } else - prefinish(stream, state); - } - return need; - } - - function endWritable(stream, state, cb) { - state.ending = true; - finishMaybe(stream, state); - if (cb) { - if (state.finished) - process.nextTick(cb); - else - stream.once('finish', cb); - } - state.ended = true; - } - - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) - -/***/ }, -/* 43 */ -/***/ function(module, exports, __webpack_require__) { - - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - var Buffer = __webpack_require__(34).Buffer; - - var isBufferEncoding = Buffer.isEncoding - || function(encoding) { - switch (encoding && encoding.toLowerCase()) { - case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true; - default: return false; - } - } - - - function assertEncoding(encoding) { - if (encoding && !isBufferEncoding(encoding)) { - throw new Error('Unknown encoding: ' + encoding); - } - } - - // StringDecoder provides an interface for efficiently splitting a series of - // buffers into a series of JS strings without breaking apart multi-byte - // characters. CESU-8 is handled as part of the UTF-8 encoding. - // - // @TODO Handling all encodings inside a single object makes it very difficult - // to reason about this code, so it should be split up in the future. - // @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code - // points as used by CESU-8. - var StringDecoder = exports.StringDecoder = function(encoding) { - this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); - assertEncoding(encoding); - switch (this.encoding) { - case 'utf8': - // CESU-8 represents each of Surrogate Pair by 3-bytes - this.surrogateSize = 3; - break; - case 'ucs2': - case 'utf16le': - // UTF-16 represents each of Surrogate Pair by 2-bytes - this.surrogateSize = 2; - this.detectIncompleteChar = utf16DetectIncompleteChar; - break; - case 'base64': - // Base-64 stores 3 bytes in 4 chars, and pads the remainder. - this.surrogateSize = 3; - this.detectIncompleteChar = base64DetectIncompleteChar; - break; - default: - this.write = passThroughWrite; - return; - } - - // Enough space to store all bytes of a single character. UTF-8 needs 4 - // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). - this.charBuffer = new Buffer(6); - // Number of bytes received for the current incomplete multi-byte character. - this.charReceived = 0; - // Number of bytes expected for the current incomplete multi-byte character. - this.charLength = 0; - }; - - - // write decodes the given buffer and returns it as JS string that is - // guaranteed to not contain any partial multi-byte characters. Any partial - // character found at the end of the buffer is buffered up, and will be - // returned when calling write again with the remaining bytes. - // - // Note: Converting a Buffer containing an orphan surrogate to a String - // currently works, but converting a String to a Buffer (via `new Buffer`, or - // Buffer#write) will replace incomplete surrogates with the unicode - // replacement character. See https://codereview.chromium.org/121173009/ . - StringDecoder.prototype.write = function(buffer) { - var charStr = ''; - // if our last write ended with an incomplete multibyte character - while (this.charLength) { - // determine how many remaining bytes this buffer has to offer for this char - var available = (buffer.length >= this.charLength - this.charReceived) ? - this.charLength - this.charReceived : - buffer.length; - - // add the new bytes to the char buffer - buffer.copy(this.charBuffer, this.charReceived, 0, available); - this.charReceived += available; - - if (this.charReceived < this.charLength) { - // still not enough chars in this buffer? wait for more ... - return ''; - } - - // remove bytes belonging to the current character from the buffer - buffer = buffer.slice(available, buffer.length); - - // get the character that was split - charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); - - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - var charCode = charStr.charCodeAt(charStr.length - 1); - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - this.charLength += this.surrogateSize; - charStr = ''; - continue; - } - this.charReceived = this.charLength = 0; - - // if there are no more bytes in this buffer, just emit our char - if (buffer.length === 0) { - return charStr; - } - break; - } - - // determine and set charLength / charReceived - this.detectIncompleteChar(buffer); - - var end = buffer.length; - if (this.charLength) { - // buffer the incomplete character bytes we got - buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); - end -= this.charReceived; - } - - charStr += buffer.toString(this.encoding, 0, end); - - var end = charStr.length - 1; - var charCode = charStr.charCodeAt(end); - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - var size = this.surrogateSize; - this.charLength += size; - this.charReceived += size; - this.charBuffer.copy(this.charBuffer, size, 0, size); - buffer.copy(this.charBuffer, 0, 0, size); - return charStr.substring(0, end); - } - - // or just emit the charStr - return charStr; - }; - - // detectIncompleteChar determines if there is an incomplete UTF-8 character at - // the end of the given buffer. If so, it sets this.charLength to the byte - // length that character, and sets this.charReceived to the number of bytes - // that are available for this character. - StringDecoder.prototype.detectIncompleteChar = function(buffer) { - // determine how many bytes we have to check at the end of this buffer - var i = (buffer.length >= 3) ? 3 : buffer.length; - - // Figure out if one of the last i bytes of our buffer announces an - // incomplete char. - for (; i > 0; i--) { - var c = buffer[buffer.length - i]; - - // See http://en.wikipedia.org/wiki/UTF-8#Description - - // 110XXXXX - if (i == 1 && c >> 5 == 0x06) { - this.charLength = 2; - break; - } - - // 1110XXXX - if (i <= 2 && c >> 4 == 0x0E) { - this.charLength = 3; - break; - } - - // 11110XXX - if (i <= 3 && c >> 3 == 0x1E) { - this.charLength = 4; - break; - } - } - this.charReceived = i; - }; - - StringDecoder.prototype.end = function(buffer) { - var res = ''; - if (buffer && buffer.length) - res = this.write(buffer); - - if (this.charReceived) { - var cr = this.charReceived; - var buf = this.charBuffer; - var enc = this.encoding; - res += buf.slice(0, cr).toString(enc); - } - - return res; - }; - - function passThroughWrite(buffer) { - return buffer.toString(this.encoding); - } - - function utf16DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 2; - this.charLength = this.charReceived ? 2 : 0; - } - - function base64DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 3; - this.charLength = this.charReceived ? 3 : 0; - } - - -/***/ }, -/* 44 */ -/***/ function(module, exports, __webpack_require__) { - - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - - // a transform stream is a readable/writable stream where you do - // something with the data. Sometimes it's called a "filter", - // but that's not a great name for it, since that implies a thing where - // some bits pass through, and others are simply ignored. (That would - // be a valid example of a transform, of course.) - // - // While the output is causally related to the input, it's not a - // necessarily symmetric or synchronous transformation. For example, - // a zlib stream might take multiple plain-text writes(), and then - // emit a single compressed chunk some time in the future. - // - // Here's how this works: - // - // The Transform stream has all the aspects of the readable and writable - // stream classes. When you write(chunk), that calls _write(chunk,cb) - // internally, and returns false if there's a lot of pending writes - // buffered up. When you call read(), that calls _read(n) until - // there's enough pending readable data buffered up. - // - // In a transform stream, the written data is placed in a buffer. When - // _read(n) is called, it transforms the queued up data, calling the - // buffered _write cb's as it consumes chunks. If consuming a single - // written chunk would result in multiple output chunks, then the first - // outputted bit calls the readcb, and subsequent chunks just go into - // the read buffer, and will cause it to emit 'readable' if necessary. - // - // This way, back-pressure is actually determined by the reading side, - // since _read has to be called to start processing a new chunk. However, - // a pathological inflate type of transform can cause excessive buffering - // here. For example, imagine a stream where every byte of input is - // interpreted as an integer from 0-255, and then results in that many - // bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in - // 1kb of data being output. In this case, you could write a very small - // amount of input, and end up with a very large amount of output. In - // such a pathological inflating mechanism, there'd be no way to tell - // the system to stop doing the transform. A single 4MB write could - // cause the system to run out of memory. - // - // However, even in such a pathological case, only a single written chunk - // would be consumed, and then the rest would wait (un-transformed) until - // the results of the previous transformed chunk were consumed. - - module.exports = Transform; - - var Duplex = __webpack_require__(41); - - /*<replacement>*/ - var util = __webpack_require__(38); - util.inherits = __webpack_require__(39); - /*</replacement>*/ - - util.inherits(Transform, Duplex); - - - function TransformState(options, stream) { - this.afterTransform = function(er, data) { - return afterTransform(stream, er, data); - }; - - this.needTransform = false; - this.transforming = false; - this.writecb = null; - this.writechunk = null; - } - - function afterTransform(stream, er, data) { - var ts = stream._transformState; - ts.transforming = false; - - var cb = ts.writecb; - - if (!cb) - return stream.emit('error', new Error('no writecb in Transform class')); - - ts.writechunk = null; - ts.writecb = null; - - if (!util.isNullOrUndefined(data)) - stream.push(data); - - if (cb) - cb(er); - - var rs = stream._readableState; - rs.reading = false; - if (rs.needReadable || rs.length < rs.highWaterMark) { - stream._read(rs.highWaterMark); - } - } - - - function Transform(options) { - if (!(this instanceof Transform)) - return new Transform(options); - - Duplex.call(this, options); - - this._transformState = new TransformState(options, this); - - // when the writable side finishes, then flush out anything remaining. - var stream = this; - - // start out asking for a readable event once data is transformed. - this._readableState.needReadable = true; - - // we have implemented the _read method, and done the other things - // that Readable wants before the first _read call, so unset the - // sync guard flag. - this._readableState.sync = false; - - this.once('prefinish', function() { - if (util.isFunction(this._flush)) - this._flush(function(er) { - done(stream, er); - }); - else - done(stream); - }); - } - - Transform.prototype.push = function(chunk, encoding) { - this._transformState.needTransform = false; - return Duplex.prototype.push.call(this, chunk, encoding); - }; - - // This is the part where you do stuff! - // override this function in implementation classes. - // 'chunk' is an input chunk. - // - // Call `push(newChunk)` to pass along transformed output - // to the readable side. You may call 'push' zero or more times. - // - // Call `cb(err)` when you are done with this chunk. If you pass - // an error, then that'll put the hurt on the whole operation. If you - // never call cb(), then you'll never get another chunk. - Transform.prototype._transform = function(chunk, encoding, cb) { - throw new Error('not implemented'); - }; - - Transform.prototype._write = function(chunk, encoding, cb) { - var ts = this._transformState; - ts.writecb = cb; - ts.writechunk = chunk; - ts.writeencoding = encoding; - if (!ts.transforming) { - var rs = this._readableState; - if (ts.needTransform || - rs.needReadable || - rs.length < rs.highWaterMark) - this._read(rs.highWaterMark); - } - }; - - // Doesn't matter what the args are here. - // _transform does all the work. - // That we got here means that the readable side wants more data. - Transform.prototype._read = function(n) { - var ts = this._transformState; - - if (!util.isNull(ts.writechunk) && ts.writecb && !ts.transforming) { - ts.transforming = true; - this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); - } else { - // mark that we need a transform, so that any data that comes in - // will get processed, now that we've asked for it. - ts.needTransform = true; - } - }; - - - function done(stream, er) { - if (er) - return stream.emit('error', er); - - // if there's nothing in the write buffer, then that means - // that nothing more will ever be provided - var ws = stream._writableState; - var ts = stream._transformState; - - if (ws.length) - throw new Error('calling transform done when ws.length != 0'); - - if (ts.transforming) - throw new Error('calling transform done when still transforming'); - - return stream.push(null); - } - - -/***/ }, -/* 45 */ -/***/ function(module, exports, __webpack_require__) { - - // Copyright Joyent, Inc. and other Node contributors. - // - // Permission is hereby granted, free of charge, to any person obtaining a - // copy of this software and associated documentation files (the - // "Software"), to deal in the Software without restriction, including - // without limitation the rights to use, copy, modify, merge, publish, - // distribute, sublicense, and/or sell copies of the Software, and to permit - // persons to whom the Software is furnished to do so, subject to the - // following conditions: - // - // The above copyright notice and this permission notice shall be included - // in all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - // USE OR OTHER DEALINGS IN THE SOFTWARE. - - // a passthrough stream. - // basically just the most minimal sort of Transform stream. - // Every written chunk gets output as-is. - - module.exports = PassThrough; - - var Transform = __webpack_require__(44); - - /*<replacement>*/ - var util = __webpack_require__(38); - util.inherits = __webpack_require__(39); - /*</replacement>*/ - - util.inherits(PassThrough, Transform); - - function PassThrough(options) { - if (!(this instanceof PassThrough)) - return new PassThrough(options); - - Transform.call(this, options); - } - - PassThrough.prototype._transform = function(chunk, encoding, cb) { - cb(null, chunk); - }; - - -/***/ }, -/* 46 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = __webpack_require__(42) - - -/***/ }, -/* 47 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = __webpack_require__(41) - - -/***/ }, -/* 48 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = __webpack_require__(44) - - -/***/ }, -/* 49 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = __webpack_require__(45) - - -/***/ }, -/* 50 */ -/***/ function(module, exports) { - - /* (ignored) */ - -/***/ }, -/* 51 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = ProxyHandler; - - function ProxyHandler(cbs){ - this._cbs = cbs || {}; - } - - var EVENTS = __webpack_require__(14).EVENTS; - Object.keys(EVENTS).forEach(function(name){ - if(EVENTS[name] === 0){ - name = "on" + name; - ProxyHandler.prototype[name] = function(){ - if(this._cbs[name]) this._cbs[name](); - }; - } else if(EVENTS[name] === 1){ - name = "on" + name; - ProxyHandler.prototype[name] = function(a){ - if(this._cbs[name]) this._cbs[name](a); - }; - } else if(EVENTS[name] === 2){ - name = "on" + name; - ProxyHandler.prototype[name] = function(a, b){ - if(this._cbs[name]) this._cbs[name](a, b); - }; - } else { - throw Error("wrong number of arguments"); - } - }); - -/***/ }, -/* 52 */ -/***/ function(module, exports, __webpack_require__) { - - var DomUtils = module.exports; - - [ - __webpack_require__(53), - __webpack_require__(59), - __webpack_require__(60), - __webpack_require__(61), - __webpack_require__(62), - __webpack_require__(63) - ].forEach(function(ext){ - Object.keys(ext).forEach(function(key){ - DomUtils[key] = ext[key].bind(DomUtils); - }); - }); - - -/***/ }, -/* 53 */ -/***/ function(module, exports, __webpack_require__) { - - var ElementType = __webpack_require__(23), - getOuterHTML = __webpack_require__(54), - isTag = ElementType.isTag; - - module.exports = { - getInnerHTML: getInnerHTML, - getOuterHTML: getOuterHTML, - getText: getText - }; - - function getInnerHTML(elem, opts){ - return elem.children ? elem.children.map(function(elem){ - return getOuterHTML(elem, opts); - }).join("") : ""; - } - - function getText(elem){ - if(Array.isArray(elem)) return elem.map(getText).join(""); - if(isTag(elem) || elem.type === ElementType.CDATA) return getText(elem.children); - if(elem.type === ElementType.Text) return elem.data; - return ""; - } - - -/***/ }, -/* 54 */ -/***/ function(module, exports, __webpack_require__) { - - /* - Module dependencies - */ - var ElementType = __webpack_require__(55); - var entities = __webpack_require__(56); - - /* - Boolean Attributes - */ - var booleanAttributes = { - __proto__: null, - allowfullscreen: true, - async: true, - autofocus: true, - autoplay: true, - checked: true, - controls: true, - default: true, - defer: true, - disabled: true, - hidden: true, - ismap: true, - loop: true, - multiple: true, - muted: true, - open: true, - readonly: true, - required: true, - reversed: true, - scoped: true, - seamless: true, - selected: true, - typemustmatch: true - }; - - var unencodedElements = { - __proto__: null, - style: true, - script: true, - xmp: true, - iframe: true, - noembed: true, - noframes: true, - plaintext: true, - noscript: true - }; - - /* - Format attributes - */ - function formatAttrs(attributes, opts) { - if (!attributes) return; - - var output = '', - value; - - // Loop through the attributes - for (var key in attributes) { - value = attributes[key]; - if (output) { - output += ' '; - } - - if (!value && booleanAttributes[key]) { - output += key; - } else { - output += key + '="' + (opts.decodeEntities ? entities.encodeXML(value) : value) + '"'; - } - } - - return output; - } - - /* - Self-enclosing tags (stolen from node-htmlparser) - */ - var singleTag = { - __proto__: null, - area: true, - base: true, - basefont: true, - br: true, - col: true, - command: true, - embed: true, - frame: true, - hr: true, - img: true, - input: true, - isindex: true, - keygen: true, - link: true, - meta: true, - param: true, - source: true, - track: true, - wbr: true, - }; - - - var render = module.exports = function(dom, opts) { - if (!Array.isArray(dom) && !dom.cheerio) dom = [dom]; - opts = opts || {}; - - var output = ''; - - for(var i = 0; i < dom.length; i++){ - var elem = dom[i]; - - if (elem.type === 'root') - output += render(elem.children, opts); - else if (ElementType.isTag(elem)) - output += renderTag(elem, opts); - else if (elem.type === ElementType.Directive) - output += renderDirective(elem); - else if (elem.type === ElementType.Comment) - output += renderComment(elem); - else if (elem.type === ElementType.CDATA) - output += renderCdata(elem); - else - output += renderText(elem, opts); - } - - return output; - }; - - function renderTag(elem, opts) { - // Handle SVG - if (elem.name === "svg") opts = {decodeEntities: opts.decodeEntities, xmlMode: true}; - - var tag = '<' + elem.name, - attribs = formatAttrs(elem.attribs, opts); - - if (attribs) { - tag += ' ' + attribs; - } - - if ( - opts.xmlMode - && (!elem.children || elem.children.length === 0) - ) { - tag += '/>'; - } else { - tag += '>'; - if (elem.children) { - tag += render(elem.children, opts); - } - - if (!singleTag[elem.name] || opts.xmlMode) { - tag += '</' + elem.name + '>'; - } - } - - return tag; - } - - function renderDirective(elem) { - return '<' + elem.data + '>'; - } - - function renderText(elem, opts) { - var data = elem.data || ''; - - // if entities weren't decoded, no need to encode them back - if (opts.decodeEntities && !(elem.parent && elem.parent.name in unencodedElements)) { - data = entities.encodeXML(data); - } - - return data; - } - - function renderCdata(elem) { - return '<![CDATA[' + elem.children[0].data + ']]>'; - } - - function renderComment(elem) { - return '<!--' + elem.data + '-->'; - } - - -/***/ }, -/* 55 */ -/***/ function(module, exports) { - - //Types of elements found in the DOM - module.exports = { - Text: "text", //Text - Directive: "directive", //<? ... ?> - Comment: "comment", //<!-- ... --> - Script: "script", //<script> tags - Style: "style", //<style> tags - Tag: "tag", //Any tag - CDATA: "cdata", //<![CDATA[ ... ]]> - - isTag: function(elem){ - return elem.type === "tag" || elem.type === "script" || elem.type === "style"; - } - }; - -/***/ }, -/* 56 */ -/***/ function(module, exports, __webpack_require__) { - - var encode = __webpack_require__(57), - decode = __webpack_require__(58); - - exports.decode = function(data, level){ - return (!level || level <= 0 ? decode.XML : decode.HTML)(data); - }; - - exports.decodeStrict = function(data, level){ - return (!level || level <= 0 ? decode.XML : decode.HTMLStrict)(data); - }; - - exports.encode = function(data, level){ - return (!level || level <= 0 ? encode.XML : encode.HTML)(data); - }; - - exports.encodeXML = encode.XML; - - exports.encodeHTML4 = - exports.encodeHTML5 = - exports.encodeHTML = encode.HTML; - - exports.decodeXML = - exports.decodeXMLStrict = decode.XML; - - exports.decodeHTML4 = - exports.decodeHTML5 = - exports.decodeHTML = decode.HTML; - - exports.decodeHTML4Strict = - exports.decodeHTML5Strict = - exports.decodeHTMLStrict = decode.HTMLStrict; - - exports.escape = encode.escape; - - -/***/ }, -/* 57 */ -/***/ function(module, exports, __webpack_require__) { - - var inverseXML = getInverseObj(__webpack_require__(21)), - xmlReplacer = getInverseReplacer(inverseXML); - - exports.XML = getInverse(inverseXML, xmlReplacer); - - var inverseHTML = getInverseObj(__webpack_require__(19)), - htmlReplacer = getInverseReplacer(inverseHTML); - - exports.HTML = getInverse(inverseHTML, htmlReplacer); - - function getInverseObj(obj){ - return Object.keys(obj).sort().reduce(function(inverse, name){ - inverse[obj[name]] = "&" + name + ";"; - return inverse; - }, {}); - } - - function getInverseReplacer(inverse){ - var single = [], - multiple = []; - - Object.keys(inverse).forEach(function(k){ - if(k.length === 1){ - single.push("\\" + k); - } else { - multiple.push(k); - } - }); - - //TODO add ranges - multiple.unshift("[" + single.join("") + "]"); - - return new RegExp(multiple.join("|"), "g"); - } - - var re_nonASCII = /[^\0-\x7F]/g, - re_astralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; - - function singleCharReplacer(c){ - return "&#x" + c.charCodeAt(0).toString(16).toUpperCase() + ";"; - } - - function astralReplacer(c){ - // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae - var high = c.charCodeAt(0); - var low = c.charCodeAt(1); - var codePoint = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000; - return "&#x" + codePoint.toString(16).toUpperCase() + ";"; - } - - function getInverse(inverse, re){ - function func(name){ - return inverse[name]; - } - - return function(data){ - return data - .replace(re, func) - .replace(re_astralSymbols, astralReplacer) - .replace(re_nonASCII, singleCharReplacer); - }; - } - - var re_xmlChars = getInverseReplacer(inverseXML); - - function escapeXML(data){ - return data - .replace(re_xmlChars, singleCharReplacer) - .replace(re_astralSymbols, astralReplacer) - .replace(re_nonASCII, singleCharReplacer); - } - - exports.escape = escapeXML; - - -/***/ }, -/* 58 */ -/***/ function(module, exports, __webpack_require__) { - - var entityMap = __webpack_require__(19), - legacyMap = __webpack_require__(20), - xmlMap = __webpack_require__(21), - decodeCodePoint = __webpack_require__(17); - - var decodeXMLStrict = getStrictDecoder(xmlMap), - decodeHTMLStrict = getStrictDecoder(entityMap); - - function getStrictDecoder(map){ - var keys = Object.keys(map).join("|"), - replace = getReplacer(map); - - keys += "|#[xX][\\da-fA-F]+|#\\d+"; - - var re = new RegExp("&(?:" + keys + ");", "g"); - - return function(str){ - return String(str).replace(re, replace); - }; - } - - var decodeHTML = (function(){ - var legacy = Object.keys(legacyMap) - .sort(sorter); - - var keys = Object.keys(entityMap) - .sort(sorter); - - for(var i = 0, j = 0; i < keys.length; i++){ - if(legacy[j] === keys[i]){ - keys[i] += ";?"; - j++; - } else { - keys[i] += ";"; - } - } - - var re = new RegExp("&(?:" + keys.join("|") + "|#[xX][\\da-fA-F]+;?|#\\d+;?)", "g"), - replace = getReplacer(entityMap); - - function replacer(str){ - if(str.substr(-1) !== ";") str += ";"; - return replace(str); - } - - //TODO consider creating a merged map - return function(str){ - return String(str).replace(re, replacer); - }; - }()); - - function sorter(a, b){ - return a < b ? 1 : -1; - } - - function getReplacer(map){ - return function replace(str){ - if(str.charAt(1) === "#"){ - if(str.charAt(2) === "X" || str.charAt(2) === "x"){ - return decodeCodePoint(parseInt(str.substr(3), 16)); - } - return decodeCodePoint(parseInt(str.substr(2), 10)); - } - return map[str.slice(1, -1)]; - }; - } - - module.exports = { - XML: decodeXMLStrict, - HTML: decodeHTML, - HTMLStrict: decodeHTMLStrict - }; - -/***/ }, -/* 59 */ -/***/ function(module, exports) { - - var getChildren = exports.getChildren = function(elem){ - return elem.children; - }; - - var getParent = exports.getParent = function(elem){ - return elem.parent; - }; - - exports.getSiblings = function(elem){ - var parent = getParent(elem); - return parent ? getChildren(parent) : [elem]; - }; - - exports.getAttributeValue = function(elem, name){ - return elem.attribs && elem.attribs[name]; - }; - - exports.hasAttrib = function(elem, name){ - return !!elem.attribs && hasOwnProperty.call(elem.attribs, name); - }; - - exports.getName = function(elem){ - return elem.name; - }; - - -/***/ }, -/* 60 */ -/***/ function(module, exports) { - - exports.removeElement = function(elem){ - if(elem.prev) elem.prev.next = elem.next; - if(elem.next) elem.next.prev = elem.prev; - - if(elem.parent){ - var childs = elem.parent.children; - childs.splice(childs.lastIndexOf(elem), 1); - } - }; - - exports.replaceElement = function(elem, replacement){ - var prev = replacement.prev = elem.prev; - if(prev){ - prev.next = replacement; - } - - var next = replacement.next = elem.next; - if(next){ - next.prev = replacement; - } - - var parent = replacement.parent = elem.parent; - if(parent){ - var childs = parent.children; - childs[childs.lastIndexOf(elem)] = replacement; - } - }; - - exports.appendChild = function(elem, child){ - child.parent = elem; - - if(elem.children.push(child) !== 1){ - var sibling = elem.children[elem.children.length - 2]; - sibling.next = child; - child.prev = sibling; - child.next = null; - } - }; - - exports.append = function(elem, next){ - var parent = elem.parent, - currNext = elem.next; - - next.next = currNext; - next.prev = elem; - elem.next = next; - next.parent = parent; - - if(currNext){ - currNext.prev = next; - if(parent){ - var childs = parent.children; - childs.splice(childs.lastIndexOf(currNext), 0, next); - } - } else if(parent){ - parent.children.push(next); - } - }; - - exports.prepend = function(elem, prev){ - var parent = elem.parent; - if(parent){ - var childs = parent.children; - childs.splice(childs.lastIndexOf(elem), 0, prev); - } - - if(elem.prev){ - elem.prev.next = prev; - } - - prev.parent = parent; - prev.prev = elem.prev; - prev.next = elem; - elem.prev = prev; - }; - - - - -/***/ }, -/* 61 */ -/***/ function(module, exports, __webpack_require__) { - - var isTag = __webpack_require__(23).isTag; - - module.exports = { - filter: filter, - find: find, - findOneChild: findOneChild, - findOne: findOne, - existsOne: existsOne, - findAll: findAll - }; - - function filter(test, element, recurse, limit){ - if(!Array.isArray(element)) element = [element]; - - if(typeof limit !== "number" || !isFinite(limit)){ - limit = Infinity; - } - return find(test, element, recurse !== false, limit); - } - - function find(test, elems, recurse, limit){ - var result = [], childs; - - for(var i = 0, j = elems.length; i < j; i++){ - if(test(elems[i])){ - result.push(elems[i]); - if(--limit <= 0) break; - } - - childs = elems[i].children; - if(recurse && childs && childs.length > 0){ - childs = find(test, childs, recurse, limit); - result = result.concat(childs); - limit -= childs.length; - if(limit <= 0) break; - } - } - - return result; - } - - function findOneChild(test, elems){ - for(var i = 0, l = elems.length; i < l; i++){ - if(test(elems[i])) return elems[i]; - } - - return null; - } - - function findOne(test, elems){ - var elem = null; - - for(var i = 0, l = elems.length; i < l && !elem; i++){ - if(!isTag(elems[i])){ - continue; - } else if(test(elems[i])){ - elem = elems[i]; - } else if(elems[i].children.length > 0){ - elem = findOne(test, elems[i].children); - } - } - - return elem; - } - - function existsOne(test, elems){ - for(var i = 0, l = elems.length; i < l; i++){ - if( - isTag(elems[i]) && ( - test(elems[i]) || ( - elems[i].children.length > 0 && - existsOne(test, elems[i].children) - ) - ) - ){ - return true; - } - } - - return false; - } - - function findAll(test, elems){ - var result = []; - for(var i = 0, j = elems.length; i < j; i++){ - if(!isTag(elems[i])) continue; - if(test(elems[i])) result.push(elems[i]); - - if(elems[i].children.length > 0){ - result = result.concat(findAll(test, elems[i].children)); - } - } - return result; - } - - -/***/ }, -/* 62 */ -/***/ function(module, exports, __webpack_require__) { - - var ElementType = __webpack_require__(23); - var isTag = exports.isTag = ElementType.isTag; - - exports.testElement = function(options, element){ - for(var key in options){ - if(!options.hasOwnProperty(key)); - else if(key === "tag_name"){ - if(!isTag(element) || !options.tag_name(element.name)){ - return false; - } - } else if(key === "tag_type"){ - if(!options.tag_type(element.type)) return false; - } else if(key === "tag_contains"){ - if(isTag(element) || !options.tag_contains(element.data)){ - return false; - } - } else if(!element.attribs || !options[key](element.attribs[key])){ - return false; - } - } - return true; - }; - - var Checks = { - tag_name: function(name){ - if(typeof name === "function"){ - return function(elem){ return isTag(elem) && name(elem.name); }; - } else if(name === "*"){ - return isTag; - } else { - return function(elem){ return isTag(elem) && elem.name === name; }; - } - }, - tag_type: function(type){ - if(typeof type === "function"){ - return function(elem){ return type(elem.type); }; - } else { - return function(elem){ return elem.type === type; }; - } - }, - tag_contains: function(data){ - if(typeof data === "function"){ - return function(elem){ return !isTag(elem) && data(elem.data); }; - } else { - return function(elem){ return !isTag(elem) && elem.data === data; }; - } - } - }; - - function getAttribCheck(attrib, value){ - if(typeof value === "function"){ - return function(elem){ return elem.attribs && value(elem.attribs[attrib]); }; - } else { - return function(elem){ return elem.attribs && elem.attribs[attrib] === value; }; - } - } - - function combineFuncs(a, b){ - return function(elem){ - return a(elem) || b(elem); - }; - } - - exports.getElements = function(options, element, recurse, limit){ - var funcs = Object.keys(options).map(function(key){ - var value = options[key]; - return key in Checks ? Checks[key](value) : getAttribCheck(key, value); - }); - - return funcs.length === 0 ? [] : this.filter( - funcs.reduce(combineFuncs), - element, recurse, limit - ); - }; - - exports.getElementById = function(id, element, recurse){ - if(!Array.isArray(element)) element = [element]; - return this.findOne(getAttribCheck("id", id), element, recurse !== false); - }; - - exports.getElementsByTagName = function(name, element, recurse, limit){ - return this.filter(Checks.tag_name(name), element, recurse, limit); - }; - - exports.getElementsByTagType = function(type, element, recurse, limit){ - return this.filter(Checks.tag_type(type), element, recurse, limit); - }; - - -/***/ }, -/* 63 */ -/***/ function(module, exports) { - - // removeSubsets - // Given an array of nodes, remove any member that is contained by another. - exports.removeSubsets = function(nodes) { - var idx = nodes.length, node, ancestor, replace; - - // Check if each node (or one of its ancestors) is already contained in the - // array. - while (--idx > -1) { - node = ancestor = nodes[idx]; - - // Temporarily remove the node under consideration - nodes[idx] = null; - replace = true; - - while (ancestor) { - if (nodes.indexOf(ancestor) > -1) { - replace = false; - nodes.splice(idx, 1); - break; - } - ancestor = ancestor.parent; - } - - // If the node has been found to be unique, re-insert it. - if (replace) { - nodes[idx] = node; - } - } - - return nodes; - }; - - // Source: http://dom.spec.whatwg.org/#dom-node-comparedocumentposition - var POSITION = { - DISCONNECTED: 1, - PRECEDING: 2, - FOLLOWING: 4, - CONTAINS: 8, - CONTAINED_BY: 16 - }; - - // Compare the position of one node against another node in any other document. - // The return value is a bitmask with the following values: - // - // document order: - // > There is an ordering, document order, defined on all the nodes in the - // > document corresponding to the order in which the first character of the - // > XML representation of each node occurs in the XML representation of the - // > document after expansion of general entities. Thus, the document element - // > node will be the first node. Element nodes occur before their children. - // > Thus, document order orders element nodes in order of the occurrence of - // > their start-tag in the XML (after expansion of entities). The attribute - // > nodes of an element occur after the element and before its children. The - // > relative order of attribute nodes is implementation-dependent./ - // Source: - // http://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-document-order - // - // @argument {Node} nodaA The first node to use in the comparison - // @argument {Node} nodeB The second node to use in the comparison - // - // @return {Number} A bitmask describing the input nodes' relative position. - // See http://dom.spec.whatwg.org/#dom-node-comparedocumentposition for - // a description of these values. - var comparePos = exports.compareDocumentPosition = function(nodeA, nodeB) { - var aParents = []; - var bParents = []; - var current, sharedParent, siblings, aSibling, bSibling, idx; - - if (nodeA === nodeB) { - return 0; - } - - current = nodeA; - while (current) { - aParents.unshift(current); - current = current.parent; - } - current = nodeB; - while (current) { - bParents.unshift(current); - current = current.parent; - } - - idx = 0; - while (aParents[idx] === bParents[idx]) { - idx++; - } - - if (idx === 0) { - return POSITION.DISCONNECTED; - } - - sharedParent = aParents[idx - 1]; - siblings = sharedParent.children; - aSibling = aParents[idx]; - bSibling = bParents[idx]; - - if (siblings.indexOf(aSibling) > siblings.indexOf(bSibling)) { - if (sharedParent === nodeB) { - return POSITION.FOLLOWING | POSITION.CONTAINED_BY; - } - return POSITION.FOLLOWING; - } else { - if (sharedParent === nodeA) { - return POSITION.PRECEDING | POSITION.CONTAINS; - } - return POSITION.PRECEDING; - } - }; - - // Sort an array of nodes based on their relative position in the document and - // remove any duplicate nodes. If the array contains nodes that do not belong - // to the same document, sort order is unspecified. - // - // @argument {Array} nodes Array of DOM nodes - // - // @returns {Array} collection of unique nodes, sorted in document order - exports.uniqueSort = function(nodes) { - var idx = nodes.length, node, position; - - nodes = nodes.slice(); - - while (--idx > -1) { - node = nodes[idx]; - position = nodes.indexOf(node); - if (position > -1 && position < idx) { - nodes.splice(idx, 1); - } - } - nodes.sort(function(a, b) { - var relative = comparePos(a, b); - if (relative & POSITION.PRECEDING) { - return -1; - } else if (relative & POSITION.FOLLOWING) { - return 1; - } - return 0; - }); - - return nodes; - }; - - -/***/ }, -/* 64 */ -/***/ function(module, exports, __webpack_require__) { - - module.exports = CollectingHandler; - - function CollectingHandler(cbs){ - this._cbs = cbs || {}; - this.events = []; - } - - var EVENTS = __webpack_require__(14).EVENTS; - Object.keys(EVENTS).forEach(function(name){ - if(EVENTS[name] === 0){ - name = "on" + name; - CollectingHandler.prototype[name] = function(){ - this.events.push([name]); - if(this._cbs[name]) this._cbs[name](); - }; - } else if(EVENTS[name] === 1){ - name = "on" + name; - CollectingHandler.prototype[name] = function(a){ - this.events.push([name, a]); - if(this._cbs[name]) this._cbs[name](a); - }; - } else if(EVENTS[name] === 2){ - name = "on" + name; - CollectingHandler.prototype[name] = function(a, b){ - this.events.push([name, a, b]); - if(this._cbs[name]) this._cbs[name](a, b); - }; - } else { - throw Error("wrong number of arguments"); - } - }); - - CollectingHandler.prototype.onreset = function(){ - this.events = []; - if(this._cbs.onreset) this._cbs.onreset(); - }; - - CollectingHandler.prototype.restart = function(){ - if(this._cbs.onreset) this._cbs.onreset(); - - for(var i = 0, len = this.events.length; i < len; i++){ - if(this._cbs[this.events[i][0]]){ - - var num = this.events[i].length; - - if(num === 1){ - this._cbs[this.events[i][0]](); - } else if(num === 2){ - this._cbs[this.events[i][0]](this.events[i][1]); - } else { - this._cbs[this.events[i][0]](this.events[i][1], this.events[i][2]); - } - } - } - }; - - -/***/ }, -/* 65 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var normalizeOpts = __webpack_require__(66) - , resolveLength = __webpack_require__(67) - , plain = __webpack_require__(73); - - module.exports = function (fn/*, options*/) { - var options = normalizeOpts(arguments[1]), length; - - if (!options.normalizer) { - length = options.length = resolveLength(options.length, fn.length, options.async); - if (length !== 0) { - if (options.primitive) { - if (length === false) { - options.normalizer = __webpack_require__(110); - } else if (length > 1) { - options.normalizer = __webpack_require__(111)(length); - } - } else { - if (length === false) options.normalizer = __webpack_require__(112)(); - else if (length === 1) options.normalizer = __webpack_require__(114)(); - else options.normalizer = __webpack_require__(115)(length); - } - } - } - - // Assure extensions - if (options.async) __webpack_require__(116); - if (options.dispose) __webpack_require__(119); - if (options.maxAge) __webpack_require__(120); - if (options.max) __webpack_require__(123); - if (options.refCounter) __webpack_require__(125); - - return plain(fn, options); - }; - - -/***/ }, -/* 66 */ -/***/ function(module, exports) { - - 'use strict'; - - var forEach = Array.prototype.forEach, create = Object.create; - - var process = function (src, obj) { - var key; - for (key in src) obj[key] = src[key]; - }; - - module.exports = function (options/*, …options*/) { - var result = create(null); - forEach.call(arguments, function (options) { - if (options == null) return; - process(Object(options), result); - }); - return result; - }; - - -/***/ }, -/* 67 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var toPosInt = __webpack_require__(68); - - module.exports = function (optsLength, fnLength, isAsync) { - var length; - if (isNaN(optsLength)) { - length = fnLength; - if (!(length >= 0)) return 1; - if (isAsync && length) return length - 1; - return length; - } - if (optsLength === false) return false; - return toPosInt(optsLength); - }; - - -/***/ }, -/* 68 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var toInteger = __webpack_require__(69) - - , max = Math.max; - - module.exports = function (value) { return max(0, toInteger(value)); }; - - -/***/ }, -/* 69 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var sign = __webpack_require__(70) - - , abs = Math.abs, floor = Math.floor; - - module.exports = function (value) { - if (isNaN(value)) return 0; - value = Number(value); - if ((value === 0) || !isFinite(value)) return value; - return sign(value) * floor(abs(value)); - }; - - -/***/ }, -/* 70 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - module.exports = __webpack_require__(71)() - ? Math.sign - : __webpack_require__(72); - - -/***/ }, -/* 71 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function () { - var sign = Math.sign; - if (typeof sign !== 'function') return false; - return ((sign(10) === 1) && (sign(-20) === -1)); - }; - - -/***/ }, -/* 72 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function (value) { - value = Number(value); - if (isNaN(value) || (value === 0)) return value; - return (value > 0) ? 1 : -1; - }; - - -/***/ }, -/* 73 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var callable = __webpack_require__(74) - , forEach = __webpack_require__(75) - , extensions = __webpack_require__(78) - , configure = __webpack_require__(79) - , resolveLength = __webpack_require__(67) - - , hasOwnProperty = Object.prototype.hasOwnProperty; - - module.exports = function self(fn/*, options */) { - var options, length, conf; - - callable(fn); - options = Object(arguments[1]); - - // Do not memoize already memoized function - if (hasOwnProperty.call(fn, '__memoized__') && !options.force) return fn; - - // Resolve length; - length = resolveLength(options.length, fn.length, options.async && extensions.async); - - // Configure cache map - conf = configure(fn, length, options); - - // Bind eventual extensions - forEach(extensions, function (fn, name) { - if (options[name]) fn(options[name], conf, options); - }); - - if (self.__profiler__) self.__profiler__(conf); - - conf.updateEnv(); - return conf.memoized; - }; - - -/***/ }, -/* 74 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function (fn) { - if (typeof fn !== 'function') throw new TypeError(fn + " is not a function"); - return fn; - }; - - -/***/ }, -/* 75 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - module.exports = __webpack_require__(76)('forEach'); - - -/***/ }, -/* 76 */ -/***/ function(module, exports, __webpack_require__) { - - // Internal method, used by iteration functions. - // Calls a function for each key-value pair found in object - // Optionally takes compareFn to iterate object in specific order - - 'use strict'; - - var callable = __webpack_require__(74) - , value = __webpack_require__(77) - - , bind = Function.prototype.bind, call = Function.prototype.call, keys = Object.keys - , propertyIsEnumerable = Object.prototype.propertyIsEnumerable; - - module.exports = function (method, defVal) { - return function (obj, cb/*, thisArg, compareFn*/) { - var list, thisArg = arguments[2], compareFn = arguments[3]; - obj = Object(value(obj)); - callable(cb); - - list = keys(obj); - if (compareFn) { - list.sort((typeof compareFn === 'function') ? bind.call(compareFn, obj) : undefined); - } - if (typeof method !== 'function') method = list[method]; - return call.call(method, list, function (key, index) { - if (!propertyIsEnumerable.call(obj, key)) return defVal; - return call.call(cb, thisArg, obj[key], key, obj, index); - }); - }; - }; - - -/***/ }, -/* 77 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function (value) { - if (value == null) throw new TypeError("Cannot use null or undefined"); - return value; - }; - - -/***/ }, -/* 78 */ -/***/ function(module, exports) { - - 'use strict'; - - -/***/ }, -/* 79 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var customError = __webpack_require__(80) - , defineLength = __webpack_require__(87) - , d = __webpack_require__(89) - , ee = __webpack_require__(94).methods - , resolveResolve = __webpack_require__(95) - , resolveNormalize = __webpack_require__(109) - - , apply = Function.prototype.apply, call = Function.prototype.call - , create = Object.create, hasOwnProperty = Object.prototype.hasOwnProperty - , defineProperties = Object.defineProperties - , on = ee.on, emit = ee.emit; - - module.exports = function (original, length, options) { - var cache = create(null), conf, memLength, get, set, del, clear, extDel, normalizer - , getListeners, setListeners, deleteListeners, memoized, resolve; - if (length !== false) memLength = length; - else if (isNaN(original.length)) memLength = 1; - else memLength = original.length; - - if (options.normalizer) { - normalizer = resolveNormalize(options.normalizer); - get = normalizer.get; - set = normalizer.set; - del = normalizer.delete; - clear = normalizer.clear; - } - if (options.resolvers != null) resolve = resolveResolve(options.resolvers); - - if (get) { - memoized = defineLength(function (arg) { - var id, result, args = arguments; - if (resolve) args = resolve(args); - id = get(args); - if (id !== null) { - if (hasOwnProperty.call(cache, id)) { - if (getListeners) conf.emit('get', id, args, this); - return cache[id]; - } - } - if (args.length === 1) result = call.call(original, this, args[0]); - else result = apply.call(original, this, args); - if (id === null) { - id = get(args); - if (id !== null) throw customError("Circular invocation", 'CIRCULAR_INVOCATION'); - id = set(args); - } else if (hasOwnProperty.call(cache, id)) { - throw customError("Circular invocation", 'CIRCULAR_INVOCATION'); - } - cache[id] = result; - if (setListeners) conf.emit('set', id); - return result; - }, memLength); - } else if (length === 0) { - memoized = function () { - var result; - if (hasOwnProperty.call(cache, 'data')) { - if (getListeners) conf.emit('get', 'data', arguments, this); - return cache.data; - } - if (!arguments.length) result = call.call(original, this); - else result = apply.call(original, this, arguments); - if (hasOwnProperty.call(cache, 'data')) { - throw customError("Circular invocation", 'CIRCULAR_INVOCATION'); - } - cache.data = result; - if (setListeners) conf.emit('set', 'data'); - return result; - }; - } else { - memoized = function (arg) { - var result, args = arguments, id; - if (resolve) args = resolve(arguments); - id = String(args[0]); - if (hasOwnProperty.call(cache, id)) { - if (getListeners) conf.emit('get', id, args, this); - return cache[id]; - } - if (args.length === 1) result = call.call(original, this, args[0]); - else result = apply.call(original, this, args); - if (hasOwnProperty.call(cache, id)) { - throw customError("Circular invocation", 'CIRCULAR_INVOCATION'); - } - cache[id] = result; - if (setListeners) conf.emit('set', id); - return result; - }; - } - conf = { - original: original, - memoized: memoized, - get: function (args) { - if (resolve) args = resolve(args); - if (get) return get(args); - return String(args[0]); - }, - has: function (id) { return hasOwnProperty.call(cache, id); }, - delete: function (id) { - var result; - if (!hasOwnProperty.call(cache, id)) return; - if (del) del(id); - result = cache[id]; - delete cache[id]; - if (deleteListeners) conf.emit('delete', id, result); - }, - clear: function () { - var oldCache = cache; - if (clear) clear(); - cache = create(null); - conf.emit('clear', oldCache); - }, - on: function (type, listener) { - if (type === 'get') getListeners = true; - else if (type === 'set') setListeners = true; - else if (type === 'delete') deleteListeners = true; - return on.call(this, type, listener); - }, - emit: emit, - updateEnv: function () { original = conf.original; } - }; - if (get) { - extDel = defineLength(function (arg) { - var id, args = arguments; - if (resolve) args = resolve(args); - id = get(args); - if (id === null) return; - conf.delete(id); - }, memLength); - } else if (length === 0) { - extDel = function () { return conf.delete('data'); }; - } else { - extDel = function (arg) { - if (resolve) arg = resolve(arguments)[0]; - return conf.delete(arg); - }; - } - defineProperties(memoized, { - __memoized__: d(true), - delete: d(extDel), - clear: d(conf.clear) - }); - return conf; - }; - - -/***/ }, -/* 80 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var assign = __webpack_require__(81) - - , captureStackTrace = Error.captureStackTrace; - - exports = module.exports = function (message/*, code, ext*/) { - var err = new Error(), code = arguments[1], ext = arguments[2]; - if (ext == null) { - if (code && (typeof code === 'object')) { - ext = code; - code = null; - } - } - if (ext != null) assign(err, ext); - err.message = String(message); - if (code != null) err.code = String(code); - if (captureStackTrace) captureStackTrace(err, exports); - return err; - }; - - -/***/ }, -/* 81 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - module.exports = __webpack_require__(82)() - ? Object.assign - : __webpack_require__(83); - - -/***/ }, -/* 82 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function () { - var assign = Object.assign, obj; - if (typeof assign !== 'function') return false; - obj = { foo: 'raz' }; - assign(obj, { bar: 'dwa' }, { trzy: 'trzy' }); - return (obj.foo + obj.bar + obj.trzy) === 'razdwatrzy'; - }; - - -/***/ }, -/* 83 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var keys = __webpack_require__(84) - , value = __webpack_require__(77) - - , max = Math.max; - - module.exports = function (dest, src/*, …srcn*/) { - var error, i, l = max(arguments.length, 2), assign; - dest = Object(value(dest)); - assign = function (key) { - try { dest[key] = src[key]; } catch (e) { - if (!error) error = e; - } - }; - for (i = 1; i < l; ++i) { - src = arguments[i]; - keys(src).forEach(assign); - } - if (error !== undefined) throw error; - return dest; - }; - - -/***/ }, -/* 84 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - module.exports = __webpack_require__(85)() - ? Object.keys - : __webpack_require__(86); - - -/***/ }, -/* 85 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function () { - try { - Object.keys('primitive'); - return true; - } catch (e) { return false; } - }; - - -/***/ }, -/* 86 */ -/***/ function(module, exports) { - - 'use strict'; - - var keys = Object.keys; - - module.exports = function (object) { - return keys(object == null ? object : Object(object)); - }; - - -/***/ }, -/* 87 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var toPosInt = __webpack_require__(68) - - , test = function (a, b) {}, desc, defineProperty - , generate, mixin; - - try { - Object.defineProperty(test, 'length', { configurable: true, writable: false, - enumerable: false, value: 1 }); - } catch (ignore) {} - - if (test.length === 1) { - // ES6 - desc = { configurable: true, writable: false, enumerable: false }; - defineProperty = Object.defineProperty; - module.exports = function (fn, length) { - length = toPosInt(length); - if (fn.length === length) return fn; - desc.value = length; - return defineProperty(fn, 'length', desc); - }; - } else { - mixin = __webpack_require__(88); - generate = (function () { - var cache = []; - return function (l) { - var args, i = 0; - if (cache[l]) return cache[l]; - args = []; - while (l--) args.push('a' + (++i).toString(36)); - return new Function('fn', 'return function (' + args.join(', ') + - ') { return fn.apply(this, arguments); };'); - }; - }()); - module.exports = function (src, length) { - var target; - length = toPosInt(length); - if (src.length === length) return src; - target = generate(length)(src); - try { mixin(target, src); } catch (ignore) {} - return target; - }; - } - - -/***/ }, -/* 88 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var value = __webpack_require__(77) - - , defineProperty = Object.defineProperty - , getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor - , getOwnPropertyNames = Object.getOwnPropertyNames; - - module.exports = function (target, source) { - var error; - target = Object(value(target)); - getOwnPropertyNames(Object(value(source))).forEach(function (name) { - try { - defineProperty(target, name, getOwnPropertyDescriptor(source, name)); - } catch (e) { error = e; } - }); - if (error !== undefined) throw error; - return target; - }; - - -/***/ }, -/* 89 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var assign = __webpack_require__(81) - , normalizeOpts = __webpack_require__(66) - , isCallable = __webpack_require__(90) - , contains = __webpack_require__(91) - - , d; - - d = module.exports = function (dscr, value/*, options*/) { - var c, e, w, options, desc; - if ((arguments.length < 2) || (typeof dscr !== 'string')) { - options = value; - value = dscr; - dscr = null; - } else { - options = arguments[2]; - } - if (dscr == null) { - c = w = true; - e = false; - } else { - c = contains.call(dscr, 'c'); - e = contains.call(dscr, 'e'); - w = contains.call(dscr, 'w'); - } - - desc = { value: value, configurable: c, enumerable: e, writable: w }; - return !options ? desc : assign(normalizeOpts(options), desc); - }; - - d.gs = function (dscr, get, set/*, options*/) { - var c, e, options, desc; - if (typeof dscr !== 'string') { - options = set; - set = get; - get = dscr; - dscr = null; - } else { - options = arguments[3]; - } - if (get == null) { - get = undefined; - } else if (!isCallable(get)) { - options = get; - get = set = undefined; - } else if (set == null) { - set = undefined; - } else if (!isCallable(set)) { - options = set; - set = undefined; - } - if (dscr == null) { - c = true; - e = false; - } else { - c = contains.call(dscr, 'c'); - e = contains.call(dscr, 'e'); - } - - desc = { get: get, set: set, configurable: c, enumerable: e }; - return !options ? desc : assign(normalizeOpts(options), desc); - }; - - -/***/ }, -/* 90 */ -/***/ function(module, exports) { - - // Deprecated - - 'use strict'; - - module.exports = function (obj) { return typeof obj === 'function'; }; - - -/***/ }, -/* 91 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - module.exports = __webpack_require__(92)() - ? String.prototype.contains - : __webpack_require__(93); - - -/***/ }, -/* 92 */ -/***/ function(module, exports) { - - 'use strict'; - - var str = 'razdwatrzy'; - - module.exports = function () { - if (typeof str.contains !== 'function') return false; - return ((str.contains('dwa') === true) && (str.contains('foo') === false)); - }; - - -/***/ }, -/* 93 */ -/***/ function(module, exports) { - - 'use strict'; - - var indexOf = String.prototype.indexOf; - - module.exports = function (searchString/*, position*/) { - return indexOf.call(this, searchString, arguments[1]) > -1; - }; - - -/***/ }, -/* 94 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var d = __webpack_require__(89) - , callable = __webpack_require__(74) - - , apply = Function.prototype.apply, call = Function.prototype.call - , create = Object.create, defineProperty = Object.defineProperty - , defineProperties = Object.defineProperties - , hasOwnProperty = Object.prototype.hasOwnProperty - , descriptor = { configurable: true, enumerable: false, writable: true } - - , on, once, off, emit, methods, descriptors, base; - - on = function (type, listener) { - var data; - - callable(listener); - - if (!hasOwnProperty.call(this, '__ee__')) { - data = descriptor.value = create(null); - defineProperty(this, '__ee__', descriptor); - descriptor.value = null; - } else { - data = this.__ee__; - } - if (!data[type]) data[type] = listener; - else if (typeof data[type] === 'object') data[type].push(listener); - else data[type] = [data[type], listener]; - - return this; - }; - - once = function (type, listener) { - var once, self; - - callable(listener); - self = this; - on.call(this, type, once = function () { - off.call(self, type, once); - apply.call(listener, this, arguments); - }); - - once.__eeOnceListener__ = listener; - return this; - }; - - off = function (type, listener) { - var data, listeners, candidate, i; - - callable(listener); - - if (!hasOwnProperty.call(this, '__ee__')) return this; - data = this.__ee__; - if (!data[type]) return this; - listeners = data[type]; - - if (typeof listeners === 'object') { - for (i = 0; (candidate = listeners[i]); ++i) { - if ((candidate === listener) || - (candidate.__eeOnceListener__ === listener)) { - if (listeners.length === 2) data[type] = listeners[i ? 0 : 1]; - else listeners.splice(i, 1); - } - } - } else { - if ((listeners === listener) || - (listeners.__eeOnceListener__ === listener)) { - delete data[type]; - } - } - - return this; - }; - - emit = function (type) { - var i, l, listener, listeners, args; - - if (!hasOwnProperty.call(this, '__ee__')) return; - listeners = this.__ee__[type]; - if (!listeners) return; - - if (typeof listeners === 'object') { - l = arguments.length; - args = new Array(l - 1); - for (i = 1; i < l; ++i) args[i - 1] = arguments[i]; - - listeners = listeners.slice(); - for (i = 0; (listener = listeners[i]); ++i) { - apply.call(listener, this, args); - } - } else { - switch (arguments.length) { - case 1: - call.call(listeners, this); - break; - case 2: - call.call(listeners, this, arguments[1]); - break; - case 3: - call.call(listeners, this, arguments[1], arguments[2]); - break; - default: - l = arguments.length; - args = new Array(l - 1); - for (i = 1; i < l; ++i) { - args[i - 1] = arguments[i]; - } - apply.call(listeners, this, args); - } - } - }; - - methods = { - on: on, - once: once, - off: off, - emit: emit - }; - - descriptors = { - on: d(on), - once: d(once), - off: d(off), - emit: d(emit) - }; - - base = defineProperties({}, descriptors); - - module.exports = exports = function (o) { - return (o == null) ? create(base) : defineProperties(Object(o), descriptors); - }; - exports.methods = methods; - - -/***/ }, -/* 95 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var toArray = __webpack_require__(96) - , callable = __webpack_require__(74) - - , slice = Array.prototype.slice - , resolveArgs; - - resolveArgs = function (args) { - return this.map(function (r, i) { - return r ? r(args[i]) : args[i]; - }).concat(slice.call(args, this.length)); - }; - - module.exports = function (resolvers) { - resolvers = toArray(resolvers); - resolvers.forEach(function (r) { - if (r != null) callable(r); - }); - return resolveArgs.bind(resolvers); - }; - - -/***/ }, -/* 96 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var from = __webpack_require__(97) - - , isArray = Array.isArray; - - module.exports = function (arrayLike) { - return isArray(arrayLike) ? arrayLike : from(arrayLike); - }; - - -/***/ }, -/* 97 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - module.exports = __webpack_require__(98)() - ? Array.from - : __webpack_require__(99); - - -/***/ }, -/* 98 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function () { - var from = Array.from, arr, result; - if (typeof from !== 'function') return false; - arr = ['raz', 'dwa']; - result = from(arr); - return Boolean(result && (result !== arr) && (result[1] === 'dwa')); - }; - - -/***/ }, -/* 99 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var iteratorSymbol = __webpack_require__(100).iterator - , isArguments = __webpack_require__(105) - , isFunction = __webpack_require__(106) - , toPosInt = __webpack_require__(68) - , callable = __webpack_require__(74) - , validValue = __webpack_require__(77) - , isString = __webpack_require__(108) - - , isArray = Array.isArray, call = Function.prototype.call - , desc = { configurable: true, enumerable: true, writable: true, value: null } - , defineProperty = Object.defineProperty; - - module.exports = function (arrayLike/*, mapFn, thisArg*/) { - var mapFn = arguments[1], thisArg = arguments[2], Constructor, i, j, arr, l, code, iterator - , result, getIterator, value; - - arrayLike = Object(validValue(arrayLike)); - - if (mapFn != null) callable(mapFn); - if (!this || (this === Array) || !isFunction(this)) { - // Result: Plain array - if (!mapFn) { - if (isArguments(arrayLike)) { - // Source: Arguments - l = arrayLike.length; - if (l !== 1) return Array.apply(null, arrayLike); - arr = new Array(1); - arr[0] = arrayLike[0]; - return arr; - } - if (isArray(arrayLike)) { - // Source: Array - arr = new Array(l = arrayLike.length); - for (i = 0; i < l; ++i) arr[i] = arrayLike[i]; - return arr; - } - } - arr = []; - } else { - // Result: Non plain array - Constructor = this; - } - - if (!isArray(arrayLike)) { - if ((getIterator = arrayLike[iteratorSymbol]) !== undefined) { - // Source: Iterator - iterator = callable(getIterator).call(arrayLike); - if (Constructor) arr = new Constructor(); - result = iterator.next(); - i = 0; - while (!result.done) { - value = mapFn ? call.call(mapFn, thisArg, result.value, i) : result.value; - if (!Constructor) { - arr[i] = value; - } else { - desc.value = value; - defineProperty(arr, i, desc); - } - result = iterator.next(); - ++i; - } - l = i; - } else if (isString(arrayLike)) { - // Source: String - l = arrayLike.length; - if (Constructor) arr = new Constructor(); - for (i = 0, j = 0; i < l; ++i) { - value = arrayLike[i]; - if ((i + 1) < l) { - code = value.charCodeAt(0); - if ((code >= 0xD800) && (code <= 0xDBFF)) value += arrayLike[++i]; - } - value = mapFn ? call.call(mapFn, thisArg, value, j) : value; - if (!Constructor) { - arr[j] = value; - } else { - desc.value = value; - defineProperty(arr, j, desc); - } - ++j; - } - l = j; - } - } - if (l === undefined) { - // Source: array or array-like - l = toPosInt(arrayLike.length); - if (Constructor) arr = new Constructor(l); - for (i = 0; i < l; ++i) { - value = mapFn ? call.call(mapFn, thisArg, arrayLike[i], i) : arrayLike[i]; - if (!Constructor) { - arr[i] = value; - } else { - desc.value = value; - defineProperty(arr, i, desc); - } - } - } - if (Constructor) { - desc.value = null; - arr.length = l; - } - return arr; - }; - - -/***/ }, -/* 100 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - module.exports = __webpack_require__(101)() ? Symbol : __webpack_require__(102); - - -/***/ }, -/* 101 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function () { - var symbol; - if (typeof Symbol !== 'function') return false; - symbol = Symbol('test symbol'); - try { String(symbol); } catch (e) { return false; } - if (typeof Symbol.iterator === 'symbol') return true; - - // Return 'true' for polyfills - if (typeof Symbol.isConcatSpreadable !== 'object') return false; - if (typeof Symbol.iterator !== 'object') return false; - if (typeof Symbol.toPrimitive !== 'object') return false; - if (typeof Symbol.toStringTag !== 'object') return false; - if (typeof Symbol.unscopables !== 'object') return false; - - return true; - }; - - -/***/ }, -/* 102 */ -/***/ function(module, exports, __webpack_require__) { - - // ES2015 Symbol polyfill for environments that do not support it (or partially support it_ - - 'use strict'; - - var d = __webpack_require__(89) - , validateSymbol = __webpack_require__(103) - - , create = Object.create, defineProperties = Object.defineProperties - , defineProperty = Object.defineProperty, objPrototype = Object.prototype - , NativeSymbol, SymbolPolyfill, HiddenSymbol, globalSymbols = create(null); - - if (typeof Symbol === 'function') NativeSymbol = Symbol; - - var generateName = (function () { - var created = create(null); - return function (desc) { - var postfix = 0, name, ie11BugWorkaround; - while (created[desc + (postfix || '')]) ++postfix; - desc += (postfix || ''); - created[desc] = true; - name = '@@' + desc; - defineProperty(objPrototype, name, d.gs(null, function (value) { - // For IE11 issue see: - // https://connect.microsoft.com/IE/feedbackdetail/view/1928508/ - // ie11-broken-getters-on-dom-objects - // https://github.com/medikoo/es6-symbol/issues/12 - if (ie11BugWorkaround) return; - ie11BugWorkaround = true; - defineProperty(this, name, d(value)); - ie11BugWorkaround = false; - })); - return name; - }; - }()); - - // Internal constructor (not one exposed) for creating Symbol instances. - // This one is used to ensure that `someSymbol instanceof Symbol` always return false - HiddenSymbol = function Symbol(description) { - if (this instanceof HiddenSymbol) throw new TypeError('TypeError: Symbol is not a constructor'); - return SymbolPolyfill(description); - }; - - // Exposed `Symbol` constructor - // (returns instances of HiddenSymbol) - module.exports = SymbolPolyfill = function Symbol(description) { - var symbol; - if (this instanceof Symbol) throw new TypeError('TypeError: Symbol is not a constructor'); - symbol = create(HiddenSymbol.prototype); - description = (description === undefined ? '' : String(description)); - return defineProperties(symbol, { - __description__: d('', description), - __name__: d('', generateName(description)) - }); - }; - defineProperties(SymbolPolyfill, { - for: d(function (key) { - if (globalSymbols[key]) return globalSymbols[key]; - return (globalSymbols[key] = SymbolPolyfill(String(key))); - }), - keyFor: d(function (s) { - var key; - validateSymbol(s); - for (key in globalSymbols) if (globalSymbols[key] === s) return key; - }), - - // If there's native implementation of given symbol, let's fallback to it - // to ensure proper interoperability with other native functions e.g. Array.from - hasInstance: d('', (NativeSymbol && NativeSymbol.hasInstance) || SymbolPolyfill('hasInstance')), - isConcatSpreadable: d('', (NativeSymbol && NativeSymbol.isConcatSpreadable) || - SymbolPolyfill('isConcatSpreadable')), - iterator: d('', (NativeSymbol && NativeSymbol.iterator) || SymbolPolyfill('iterator')), - match: d('', (NativeSymbol && NativeSymbol.match) || SymbolPolyfill('match')), - replace: d('', (NativeSymbol && NativeSymbol.replace) || SymbolPolyfill('replace')), - search: d('', (NativeSymbol && NativeSymbol.search) || SymbolPolyfill('search')), - species: d('', (NativeSymbol && NativeSymbol.species) || SymbolPolyfill('species')), - split: d('', (NativeSymbol && NativeSymbol.split) || SymbolPolyfill('split')), - toPrimitive: d('', (NativeSymbol && NativeSymbol.toPrimitive) || SymbolPolyfill('toPrimitive')), - toStringTag: d('', (NativeSymbol && NativeSymbol.toStringTag) || SymbolPolyfill('toStringTag')), - unscopables: d('', (NativeSymbol && NativeSymbol.unscopables) || SymbolPolyfill('unscopables')) - }); - - // Internal tweaks for real symbol producer - defineProperties(HiddenSymbol.prototype, { - constructor: d(SymbolPolyfill), - toString: d('', function () { return this.__name__; }) - }); - - // Proper implementation of methods exposed on Symbol.prototype - // They won't be accessible on produced symbol instances as they derive from HiddenSymbol.prototype - defineProperties(SymbolPolyfill.prototype, { - toString: d(function () { return 'Symbol (' + validateSymbol(this).__description__ + ')'; }), - valueOf: d(function () { return validateSymbol(this); }) - }); - defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toPrimitive, d('', - function () { return validateSymbol(this); })); - defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toStringTag, d('c', 'Symbol')); - - // Proper implementaton of toPrimitive and toStringTag for returned symbol instances - defineProperty(HiddenSymbol.prototype, SymbolPolyfill.toStringTag, - d('c', SymbolPolyfill.prototype[SymbolPolyfill.toStringTag])); - - // Note: It's important to define `toPrimitive` as last one, as some implementations - // implement `toPrimitive` natively without implementing `toStringTag` (or other specified symbols) - // And that may invoke error in definition flow: - // See: https://github.com/medikoo/es6-symbol/issues/13#issuecomment-164146149 - defineProperty(HiddenSymbol.prototype, SymbolPolyfill.toPrimitive, - d('c', SymbolPolyfill.prototype[SymbolPolyfill.toPrimitive])); - - -/***/ }, -/* 103 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var isSymbol = __webpack_require__(104); - - module.exports = function (value) { - if (!isSymbol(value)) throw new TypeError(value + " is not a symbol"); - return value; - }; - - -/***/ }, -/* 104 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function (x) { - return (x && ((typeof x === 'symbol') || (x['@@toStringTag'] === 'Symbol'))) || false; - }; - - -/***/ }, -/* 105 */ -/***/ function(module, exports) { - - 'use strict'; - - var toString = Object.prototype.toString - - , id = toString.call((function () { return arguments; }())); - - module.exports = function (x) { return (toString.call(x) === id); }; - - -/***/ }, -/* 106 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var toString = Object.prototype.toString - - , id = toString.call(__webpack_require__(107)); - - module.exports = function (f) { - return (typeof f === "function") && (toString.call(f) === id); - }; - - -/***/ }, -/* 107 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function () {}; - - -/***/ }, -/* 108 */ -/***/ function(module, exports) { - - 'use strict'; - - var toString = Object.prototype.toString - - , id = toString.call(''); - - module.exports = function (x) { - return (typeof x === 'string') || (x && (typeof x === 'object') && - ((x instanceof String) || (toString.call(x) === id))) || false; - }; - - -/***/ }, -/* 109 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var callable = __webpack_require__(74); - - module.exports = function (userNormalizer) { - var normalizer; - if (typeof userNormalizer === 'function') return { set: userNormalizer, get: userNormalizer }; - normalizer = { get: callable(userNormalizer.get) }; - if (userNormalizer.set !== undefined) { - normalizer.set = callable(userNormalizer.set); - normalizer.delete = callable(userNormalizer.delete); - normalizer.clear = callable(userNormalizer.clear); - return normalizer; - } - normalizer.set = normalizer.get; - return normalizer; - }; - - -/***/ }, -/* 110 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function (args) { - var id, i, length = args.length; - if (!length) return '\u0002'; - id = String(args[i = 0]); - while (--length) id += '\u0001' + args[++i]; - return id; - }; - - -/***/ }, -/* 111 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = function (length) { - if (!length) { - return function () { return ''; }; - } - return function (args) { - var id = String(args[0]), i = 0, l = length; - while (--l) { id += '\u0001' + args[++i]; } - return id; - }; - }; - - -/***/ }, -/* 112 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var indexOf = __webpack_require__(113) - , create = Object.create; - - module.exports = function () { - var lastId = 0, map = [], cache = create(null); - return { - get: function (args) { - var index = 0, set = map, i, length = args.length; - if (length === 0) return set[length] || null; - if ((set = set[length])) { - while (index < (length - 1)) { - i = indexOf.call(set[0], args[index]); - if (i === -1) return null; - set = set[1][i]; - ++index; - } - i = indexOf.call(set[0], args[index]); - if (i === -1) return null; - return set[1][i] || null; - } - return null; - }, - set: function (args) { - var index = 0, set = map, i, length = args.length; - if (length === 0) { - set[length] = ++lastId; - } else { - if (!set[length]) { - set[length] = [[], []]; - } - set = set[length]; - while (index < (length - 1)) { - i = indexOf.call(set[0], args[index]); - if (i === -1) { - i = set[0].push(args[index]) - 1; - set[1].push([[], []]); - } - set = set[1][i]; - ++index; - } - i = indexOf.call(set[0], args[index]); - if (i === -1) { - i = set[0].push(args[index]) - 1; - } - set[1][i] = ++lastId; - } - cache[lastId] = args; - return lastId; - }, - delete: function (id) { - var index = 0, set = map, i, args = cache[id], length = args.length - , path = []; - if (length === 0) { - delete set[length]; - } else if ((set = set[length])) { - while (index < (length - 1)) { - i = indexOf.call(set[0], args[index]); - if (i === -1) { - return; - } - path.push(set, i); - set = set[1][i]; - ++index; - } - i = indexOf.call(set[0], args[index]); - if (i === -1) { - return; - } - id = set[1][i]; - set[0].splice(i, 1); - set[1].splice(i, 1); - while (!set[0].length && path.length) { - i = path.pop(); - set = path.pop(); - set[0].splice(i, 1); - set[1].splice(i, 1); - } - } - delete cache[id]; - }, - clear: function () { - map = []; - cache = create(null); - } - }; - }; - - -/***/ }, -/* 113 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var toPosInt = __webpack_require__(68) - , value = __webpack_require__(77) - - , indexOf = Array.prototype.indexOf - , hasOwnProperty = Object.prototype.hasOwnProperty - , abs = Math.abs, floor = Math.floor; - - module.exports = function (searchElement/*, fromIndex*/) { - var i, l, fromIndex, val; - if (searchElement === searchElement) { //jslint: ignore - return indexOf.apply(this, arguments); - } - - l = toPosInt(value(this).length); - fromIndex = arguments[1]; - if (isNaN(fromIndex)) fromIndex = 0; - else if (fromIndex >= 0) fromIndex = floor(fromIndex); - else fromIndex = toPosInt(this.length) - floor(abs(fromIndex)); - - for (i = fromIndex; i < l; ++i) { - if (hasOwnProperty.call(this, i)) { - val = this[i]; - if (val !== val) return i; //jslint: ignore - } - } - return -1; - }; - - -/***/ }, -/* 114 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var indexOf = __webpack_require__(113); - - module.exports = function () { - var lastId = 0, argsMap = [], cache = []; - return { - get: function (args) { - var index = indexOf.call(argsMap, args[0]); - return (index === -1) ? null : cache[index]; - }, - set: function (args) { - argsMap.push(args[0]); - cache.push(++lastId); - return lastId; - }, - delete: function (id) { - var index = indexOf.call(cache, id); - if (index !== -1) { - argsMap.splice(index, 1); - cache.splice(index, 1); - } - }, - clear: function () { - argsMap = []; - cache = []; - } - }; - }; - - -/***/ }, -/* 115 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var indexOf = __webpack_require__(113) - , create = Object.create; - - module.exports = function (length) { - var lastId = 0, map = [[], []], cache = create(null); - return { - get: function (args) { - var index = 0, set = map, i; - while (index < (length - 1)) { - i = indexOf.call(set[0], args[index]); - if (i === -1) return null; - set = set[1][i]; - ++index; - } - i = indexOf.call(set[0], args[index]); - if (i === -1) return null; - return set[1][i] || null; - }, - set: function (args) { - var index = 0, set = map, i; - while (index < (length - 1)) { - i = indexOf.call(set[0], args[index]); - if (i === -1) { - i = set[0].push(args[index]) - 1; - set[1].push([[], []]); - } - set = set[1][i]; - ++index; - } - i = indexOf.call(set[0], args[index]); - if (i === -1) { - i = set[0].push(args[index]) - 1; - } - set[1][i] = ++lastId; - cache[lastId] = args; - return lastId; - }, - delete: function (id) { - var index = 0, set = map, i, path = [], args = cache[id]; - while (index < (length - 1)) { - i = indexOf.call(set[0], args[index]); - if (i === -1) { - return; - } - path.push(set, i); - set = set[1][i]; - ++index; - } - i = indexOf.call(set[0], args[index]); - if (i === -1) { - return; - } - id = set[1][i]; - set[0].splice(i, 1); - set[1].splice(i, 1); - while (!set[0].length && path.length) { - i = path.pop(); - set = path.pop(); - set[0].splice(i, 1); - set[1].splice(i, 1); - } - delete cache[id]; - }, - clear: function () { - map = [[], []]; - cache = create(null); - } - }; - }; - - -/***/ }, -/* 116 */ -/***/ function(module, exports, __webpack_require__) { - - // Support for asynchronous functions - - 'use strict'; - - var aFrom = __webpack_require__(97) - , mixin = __webpack_require__(88) - , defineLength = __webpack_require__(87) - , nextTick = __webpack_require__(117) - - , slice = Array.prototype.slice - , apply = Function.prototype.apply, create = Object.create - , hasOwnProperty = Object.prototype.hasOwnProperty; - - __webpack_require__(78).async = function (tbi, conf) { - var waiting = create(null), cache = create(null) - , base = conf.memoized, original = conf.original - , currentCallback, currentContext, currentArgs; - - // Initial - conf.memoized = defineLength(function (arg) { - var args = arguments, last = args[args.length - 1]; - if (typeof last === 'function') { - currentCallback = last; - args = slice.call(args, 0, -1); - } - return base.apply(currentContext = this, currentArgs = args); - }, base); - try { mixin(conf.memoized, base); } catch (ignore) {} - - // From cache (sync) - conf.on('get', function (id) { - var cb, context, args; - if (!currentCallback) return; - - // Unresolved - if (waiting[id]) { - if (typeof waiting[id] === 'function') waiting[id] = [waiting[id], currentCallback]; - else waiting[id].push(currentCallback); - currentCallback = null; - return; - } - - // Resolved, assure next tick invocation - cb = currentCallback; - context = currentContext; - args = currentArgs; - currentCallback = currentContext = currentArgs = null; - nextTick(function () { - var data; - if (hasOwnProperty.call(cache, id)) { - data = cache[id]; - conf.emit('getasync', id, args, context); - apply.call(cb, data.context, data.args); - } else { - // Purged in a meantime, we shouldn't rely on cached value, recall - currentCallback = cb; - currentContext = context; - currentArgs = args; - base.apply(context, args); - } - }); - }); - - // Not from cache - conf.original = function () { - var args, cb, origCb, result; - if (!currentCallback) return apply.call(original, this, arguments); - args = aFrom(arguments); - cb = function self(err) { - var cb, args, id = self.id; - if (id == null) { - // Shouldn't happen, means async callback was called sync way - nextTick(apply.bind(self, this, arguments)); - return; - } - delete self.id; - cb = waiting[id]; - delete waiting[id]; - if (!cb) { - // Already processed, - // outcome of race condition: asyncFn(1, cb), asyncFn.clear(), asyncFn(1, cb) - return; - } - args = aFrom(arguments); - if (conf.has(id)) { - if (err) { - conf.delete(id); - } else { - cache[id] = { context: this, args: args }; - conf.emit('setasync', id, (typeof cb === 'function') ? 1 : cb.length); - } - } - if (typeof cb === 'function') { - result = apply.call(cb, this, args); - } else { - cb.forEach(function (cb) { result = apply.call(cb, this, args); }, this); - } - return result; - }; - origCb = currentCallback; - currentCallback = currentContext = currentArgs = null; - args.push(cb); - result = apply.call(original, this, args); - cb.cb = origCb; - currentCallback = cb; - return result; - }; - - // After not from cache call - conf.on('set', function (id) { - if (!currentCallback) { - conf.delete(id); - return; - } - if (waiting[id]) { - // Race condition: asyncFn(1, cb), asyncFn.clear(), asyncFn(1, cb) - if (typeof waiting[id] === 'function') waiting[id] = [waiting[id], currentCallback.cb]; - else waiting[id].push(currentCallback.cb); - } else { - waiting[id] = currentCallback.cb; - } - delete currentCallback.cb; - currentCallback.id = id; - currentCallback = null; - }); - - // On delete - conf.on('delete', function (id) { - var result; - // If false, we don't have value yet, so we assume that intention is not - // to memoize this call. After value is obtained we don't cache it but - // gracefully pass to callback - if (hasOwnProperty.call(waiting, id)) return; - if (!cache[id]) return; - result = cache[id]; - delete cache[id]; - conf.emit('deleteasync', id, result); - }); - - // On clear - conf.on('clear', function () { - var oldCache = cache; - cache = create(null); - conf.emit('clearasync', oldCache); - }); - }; - - -/***/ }, -/* 117 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(process, setImmediate) {'use strict'; - - var callable, byObserver; - - callable = function (fn) { - if (typeof fn !== 'function') throw new TypeError(fn + " is not a function"); - return fn; - }; - - byObserver = function (Observer) { - var node = document.createTextNode(''), queue, i = 0; - new Observer(function () { - var data; - if (!queue) return; - data = queue; - queue = null; - if (typeof data === 'function') { - data(); - return; - } - data.forEach(function (fn) { fn(); }); - }).observe(node, { characterData: true }); - return function (fn) { - callable(fn); - if (queue) { - if (typeof queue === 'function') queue = [queue, fn]; - else queue.push(fn); - return; - } - queue = fn; - node.data = (i = ++i % 2); - }; - }; - - module.exports = (function () { - // Node.js - if ((typeof process !== 'undefined') && process && - (typeof process.nextTick === 'function')) { - return process.nextTick; - } - - // MutationObserver= - if ((typeof document === 'object') && document) { - if (typeof MutationObserver === 'function') { - return byObserver(MutationObserver); - } - if (typeof WebKitMutationObserver === 'function') { - return byObserver(WebKitMutationObserver); - } - } - - // W3C Draft - // http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html - if (typeof setImmediate === 'function') { - return function (cb) { setImmediate(callable(cb)); }; - } - - // Wide available standard - if (typeof setTimeout === 'function') { - return function (cb) { setTimeout(callable(cb), 0); }; - } - - return null; - }()); - - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3), __webpack_require__(118).setImmediate)) - -/***/ }, -/* 118 */ -/***/ function(module, exports, __webpack_require__) { - - /* WEBPACK VAR INJECTION */(function(setImmediate, clearImmediate) {var nextTick = __webpack_require__(3).nextTick; - var apply = Function.prototype.apply; - var slice = Array.prototype.slice; - var immediateIds = {}; - var nextImmediateId = 0; - - // DOM APIs, for completeness - - exports.setTimeout = function() { - return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); - }; - exports.setInterval = function() { - return new Timeout(apply.call(setInterval, window, arguments), clearInterval); - }; - exports.clearTimeout = - exports.clearInterval = function(timeout) { timeout.close(); }; - - function Timeout(id, clearFn) { - this._id = id; - this._clearFn = clearFn; - } - Timeout.prototype.unref = Timeout.prototype.ref = function() {}; - Timeout.prototype.close = function() { - this._clearFn.call(window, this._id); - }; - - // Does not start the time, just sets up the members needed. - exports.enroll = function(item, msecs) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = msecs; - }; - - exports.unenroll = function(item) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = -1; - }; - - exports._unrefActive = exports.active = function(item) { - clearTimeout(item._idleTimeoutId); - - var msecs = item._idleTimeout; - if (msecs >= 0) { - item._idleTimeoutId = setTimeout(function onTimeout() { - if (item._onTimeout) - item._onTimeout(); - }, msecs); - } - }; - - // That's not how node.js implements it but the exposed api is the same. - exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) { - var id = nextImmediateId++; - var args = arguments.length < 2 ? false : slice.call(arguments, 1); - - immediateIds[id] = true; - - nextTick(function onNextTick() { - if (immediateIds[id]) { - // fn.call() is faster so we optimize for the common use-case - // @see http://jsperf.com/call-apply-segu - if (args) { - fn.apply(null, args); - } else { - fn.call(null); - } - // Prevent ids from leaking - exports.clearImmediate(id); - } - }); - - return id; - }; - - exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) { - delete immediateIds[id]; - }; - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(118).setImmediate, __webpack_require__(118).clearImmediate)) - -/***/ }, -/* 119 */ -/***/ function(module, exports, __webpack_require__) { - - // Call dispose callback on each cache purge - - 'use strict'; - - var callable = __webpack_require__(74) - , forEach = __webpack_require__(75) - , extensions = __webpack_require__(78) - - , slice = Array.prototype.slice, apply = Function.prototype.apply; - - extensions.dispose = function (dispose, conf, options) { - var del; - callable(dispose); - if (options.async && extensions.async) { - conf.on('deleteasync', del = function (id, result) { - apply.call(dispose, null, slice.call(result.args, 1)); - }); - conf.on('clearasync', function (cache) { - forEach(cache, function (result, id) { del(id, result); }); - }); - return; - } - conf.on('delete', del = function (id, result) { dispose(result); }); - conf.on('clear', function (cache) { - forEach(cache, function (result, id) { del(id, result); }); - }); - }; - - -/***/ }, -/* 120 */ -/***/ function(module, exports, __webpack_require__) { - - // Timeout cached values - - 'use strict'; - - var aFrom = __webpack_require__(97) - , noop = __webpack_require__(107) - , forEach = __webpack_require__(75) - , timeout = __webpack_require__(121) - , extensions = __webpack_require__(78) - - , max = Math.max, min = Math.min, create = Object.create; - - extensions.maxAge = function (maxAge, conf, options) { - var timeouts, postfix, preFetchAge, preFetchTimeouts; - - maxAge = timeout(maxAge); - if (!maxAge) return; - - timeouts = create(null); - postfix = (options.async && extensions.async) ? 'async' : ''; - conf.on('set' + postfix, function (id) { - timeouts[id] = setTimeout(function () { conf.delete(id); }, maxAge); - if (!preFetchTimeouts) return; - if (preFetchTimeouts[id]) clearTimeout(preFetchTimeouts[id]); - preFetchTimeouts[id] = setTimeout(function () { - delete preFetchTimeouts[id]; - }, preFetchAge); - }); - conf.on('delete' + postfix, function (id) { - clearTimeout(timeouts[id]); - delete timeouts[id]; - if (!preFetchTimeouts) return; - clearTimeout(preFetchTimeouts[id]); - delete preFetchTimeouts[id]; - }); - - if (options.preFetch) { - if ((options.preFetch === true) || isNaN(options.preFetch)) { - preFetchAge = 0.333; - } else { - preFetchAge = max(min(Number(options.preFetch), 1), 0); - } - if (preFetchAge) { - preFetchTimeouts = {}; - preFetchAge = (1 - preFetchAge) * maxAge; - conf.on('get' + postfix, function (id, args, context) { - if (!preFetchTimeouts[id]) { - preFetchTimeouts[id] = setTimeout(function () { - delete preFetchTimeouts[id]; - conf.delete(id); - if (options.async) { - args = aFrom(args); - args.push(noop); - } - conf.memoized.apply(context, args); - }, 0); - } - }); - } - } - - conf.on('clear' + postfix, function () { - forEach(timeouts, function (id) { clearTimeout(id); }); - timeouts = {}; - if (preFetchTimeouts) { - forEach(preFetchTimeouts, function (id) { clearTimeout(id); }); - preFetchTimeouts = {}; - } - }); - }; - - -/***/ }, -/* 121 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var toPosInt = __webpack_require__(68) - , maxTimeout = __webpack_require__(122); - - module.exports = function (value) { - value = toPosInt(value); - if (value > maxTimeout) throw new TypeError(value + " exceeds maximum possible timeout"); - return value; - }; - - -/***/ }, -/* 122 */ -/***/ function(module, exports) { - - 'use strict'; - - module.exports = 2147483647; - - -/***/ }, -/* 123 */ -/***/ function(module, exports, __webpack_require__) { - - // Limit cache size, LRU (least recently used) algorithm. - - 'use strict'; - - var toPosInteger = __webpack_require__(68) - , lruQueue = __webpack_require__(124) - , extensions = __webpack_require__(78); - - extensions.max = function (max, conf, options) { - var postfix, queue, hit; - - max = toPosInteger(max); - if (!max) return; - - queue = lruQueue(max); - postfix = (options.async && extensions.async) ? 'async' : ''; - - conf.on('set' + postfix, hit = function (id) { - id = queue.hit(id); - if (id === undefined) return; - conf.delete(id); - }); - conf.on('get' + postfix, hit); - conf.on('delete' + postfix, queue.delete); - conf.on('clear' + postfix, queue.clear); - }; - - -/***/ }, -/* 124 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var toPosInt = __webpack_require__(68) - - , create = Object.create, hasOwnProperty = Object.prototype.hasOwnProperty; - - module.exports = function (limit) { - var size = 0, base = 1, queue = create(null), map = create(null), index = 0, del; - limit = toPosInt(limit); - return { - hit: function (id) { - var oldIndex = map[id], nuIndex = ++index; - queue[nuIndex] = id; - map[id] = nuIndex; - if (!oldIndex) { - ++size; - if (size <= limit) return; - id = queue[base]; - del(id); - return id; - } - delete queue[oldIndex]; - if (base !== oldIndex) return; - while (!hasOwnProperty.call(queue, ++base)) continue; //jslint: skip - }, - delete: del = function (id) { - var oldIndex = map[id]; - if (!oldIndex) return; - delete queue[oldIndex]; - delete map[id]; - --size; - if (base !== oldIndex) return; - if (!size) { - index = 0; - base = 1; - return; - } - while (!hasOwnProperty.call(queue, ++base)) continue; //jslint: skip - }, - clear: function () { - size = 0; - base = 1; - queue = create(null); - map = create(null); - index = 0; - } - }; - }; - - -/***/ }, -/* 125 */ -/***/ function(module, exports, __webpack_require__) { - - // Reference counter, useful for garbage collector like functionality - - 'use strict'; - - var d = __webpack_require__(89) - , extensions = __webpack_require__(78) - - , create = Object.create, defineProperties = Object.defineProperties; - - extensions.refCounter = function (ignore, conf, options) { - var cache, postfix; - - cache = create(null); - postfix = (options.async && extensions.async) ? 'async' : ''; - - conf.on('set' + postfix, function (id, length) { cache[id] = length || 1; }); - conf.on('get' + postfix, function (id) { ++cache[id]; }); - conf.on('delete' + postfix, function (id) { delete cache[id]; }); - conf.on('clear' + postfix, function () { cache = {}; }); - - defineProperties(conf.memoized, { - deleteRef: d(function () { - var id = conf.get(arguments); - if (id === null) return null; - if (!cache[id]) return null; - if (!--cache[id]) { - conf.delete(id); - return true; - } - return false; - }), - getRefCount: d(function () { - var id = conf.get(arguments); - if (id === null) return 0; - if (!cache[id]) return 0; - return cache[id]; - }) - }); - }; - - -/***/ } -/******/ ]); \ No newline at end of file diff --git a/vm.min.js b/vm.min.js deleted file mode 100644 index d11a6ccad..000000000 --- a/vm.min.js +++ /dev/null @@ -1,11 +0,0 @@ -!function(t){function e(n){if(r[n])return r[n].exports;var i=r[n]={exports:{},id:n,loaded:!1};return t[n].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){function n(){var t=this;i.call(t),t.runtime=new s,t.blockListener=function(e){if("object"==typeof e&&"string"==typeof e.blockId)switch(e.type){case"create":t.runtime.createBlock(a(e),!1);break;case"change":t.runtime.changeBlock({id:e.blockId,element:e.element,name:e.name,value:e.newValue});break;case"move":t.runtime.moveBlock({id:e.blockId,oldParent:e.oldParentId,oldField:e.oldInputName,newParent:e.newParentId,newField:e.newInputName});break;case"delete":t.runtime.deleteBlock({id:e.blockId})}},t.flyoutBlockListener=function(e){switch(e.type){case"create":t.runtime.createBlock(a(e),!0);break;case"change":t.runtime.changeBlock({id:e.blockId,element:e.element,name:e.name,value:e.newValue});break;case"delete":t.runtime.deleteBlock({id:e.blockId})}}}var i=r(1),o=r(2),s=r(6),a=r(13);o.inherits(n,i),t.exports=n,"undefined"!=typeof window&&(window.VirtualMachine=t.exports)},function(t,e){function r(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function n(t){return"function"==typeof t}function i(t){return"number"==typeof t}function o(t){return"object"==typeof t&&null!==t}function s(t){return void 0===t}t.exports=r,r.EventEmitter=r,r.prototype._events=void 0,r.prototype._maxListeners=void 0,r.defaultMaxListeners=10,r.prototype.setMaxListeners=function(t){if(!i(t)||0>t||isNaN(t))throw TypeError("n must be a positive number");return this._maxListeners=t,this},r.prototype.emit=function(t){var e,r,i,a,c,u;if(this._events||(this._events={}),"error"===t&&(!this._events.error||o(this._events.error)&&!this._events.error.length)){if(e=arguments[1],e instanceof Error)throw e;throw TypeError('Uncaught, unspecified "error" event.')}if(r=this._events[t],s(r))return!1;if(n(r))switch(arguments.length){case 1:r.call(this);break;case 2:r.call(this,arguments[1]);break;case 3:r.call(this,arguments[1],arguments[2]);break;default:a=Array.prototype.slice.call(arguments,1),r.apply(this,a)}else if(o(r))for(a=Array.prototype.slice.call(arguments,1),u=r.slice(),i=u.length,c=0;i>c;c++)u[c].apply(this,a);return!0},r.prototype.addListener=function(t,e){var i;if(!n(e))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",t,n(e.listener)?e.listener:e),this._events[t]?o(this._events[t])?this._events[t].push(e):this._events[t]=[this._events[t],e]:this._events[t]=e,o(this._events[t])&&!this._events[t].warned&&(i=s(this._maxListeners)?r.defaultMaxListeners:this._maxListeners,i&&i>0&&this._events[t].length>i&&(this._events[t].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[t].length),"function"==typeof console.trace&&console.trace())),this},r.prototype.on=r.prototype.addListener,r.prototype.once=function(t,e){function r(){this.removeListener(t,r),i||(i=!0,e.apply(this,arguments))}if(!n(e))throw TypeError("listener must be a function");var i=!1;return r.listener=e,this.on(t,r),this},r.prototype.removeListener=function(t,e){var r,i,s,a;if(!n(e))throw TypeError("listener must be a function");if(!this._events||!this._events[t])return this;if(r=this._events[t],s=r.length,i=-1,r===e||n(r.listener)&&r.listener===e)delete this._events[t],this._events.removeListener&&this.emit("removeListener",t,e);else if(o(r)){for(a=s;a-- >0;)if(r[a]===e||r[a].listener&&r[a].listener===e){i=a;break}if(0>i)return this;1===r.length?(r.length=0,delete this._events[t]):r.splice(i,1),this._events.removeListener&&this.emit("removeListener",t,e)}return this},r.prototype.removeAllListeners=function(t){var e,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[t]&&delete this._events[t],this;if(0===arguments.length){for(e in this._events)"removeListener"!==e&&this.removeAllListeners(e);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[t],n(r))this.removeListener(t,r);else if(r)for(;r.length;)this.removeListener(t,r[r.length-1]);return delete this._events[t],this},r.prototype.listeners=function(t){var e;return e=this._events&&this._events[t]?n(this._events[t])?[this._events[t]]:this._events[t].slice():[]},r.prototype.listenerCount=function(t){if(this._events){var e=this._events[t];if(n(e))return 1;if(e)return e.length}return 0},r.listenerCount=function(t,e){return t.listenerCount(e)}},function(t,e,r){(function(t,n){function i(t,r){var n={seen:[],stylize:s};return arguments.length>=3&&(n.depth=arguments[2]),arguments.length>=4&&(n.colors=arguments[3]),g(r)?n.showHidden=r:r&&e._extend(n,r),w(n.showHidden)&&(n.showHidden=!1),w(n.depth)&&(n.depth=2),w(n.colors)&&(n.colors=!1),w(n.customInspect)&&(n.customInspect=!0),n.colors&&(n.stylize=o),c(n,t,n.depth)}function o(t,e){var r=i.styles[e];return r?"["+i.colors[r][0]+"m"+t+"["+i.colors[r][1]+"m":t}function s(t,e){return t}function a(t){var e={};return t.forEach(function(t,r){e[t]=!0}),e}function c(t,r,n){if(t.customInspect&&r&&T(r.inspect)&&r.inspect!==e.inspect&&(!r.constructor||r.constructor.prototype!==r)){var i=r.inspect(n,t);return y(i)||(i=c(t,i,n)),i}var o=u(t,r);if(o)return o;var s=Object.keys(r),g=a(s);if(t.showHidden&&(s=Object.getOwnPropertyNames(r)),k(r)&&(s.indexOf("message")>=0||s.indexOf("description")>=0))return l(r);if(0===s.length){if(T(r)){var _=r.name?": "+r.name:"";return t.stylize("[Function"+_+"]","special")}if(S(r))return t.stylize(RegExp.prototype.toString.call(r),"regexp");if(E(r))return t.stylize(Date.prototype.toString.call(r),"date");if(k(r))return l(r)}var m="",b=!1,v=["{","}"];if(d(r)&&(b=!0,v=["[","]"]),T(r)){var w=r.name?": "+r.name:"";m=" [Function"+w+"]"}if(S(r)&&(m=" "+RegExp.prototype.toString.call(r)),E(r)&&(m=" "+Date.prototype.toUTCString.call(r)),k(r)&&(m=" "+l(r)),0===s.length&&(!b||0==r.length))return v[0]+m+v[1];if(0>n)return S(r)?t.stylize(RegExp.prototype.toString.call(r),"regexp"):t.stylize("[Object]","special");t.seen.push(r);var x;return x=b?h(t,r,n,g,s):s.map(function(e){return f(t,r,n,g,e,b)}),t.seen.pop(),p(x,m,v)}function u(t,e){if(w(e))return t.stylize("undefined","undefined");if(y(e)){var r="'"+JSON.stringify(e).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(r,"string")}return b(e)?t.stylize(""+e,"number"):g(e)?t.stylize(""+e,"boolean"):_(e)?t.stylize("null","null"):void 0}function l(t){return"["+Error.prototype.toString.call(t)+"]"}function h(t,e,r,n,i){for(var o=[],s=0,a=e.length;a>s;++s)I(e,String(s))?o.push(f(t,e,r,n,String(s),!0)):o.push("");return i.forEach(function(i){i.match(/^\d+$/)||o.push(f(t,e,r,n,i,!0))}),o}function f(t,e,r,n,i,o){var s,a,u;if(u=Object.getOwnPropertyDescriptor(e,i)||{value:e[i]},u.get?a=u.set?t.stylize("[Getter/Setter]","special"):t.stylize("[Getter]","special"):u.set&&(a=t.stylize("[Setter]","special")),I(n,i)||(s="["+i+"]"),a||(t.seen.indexOf(u.value)<0?(a=_(r)?c(t,u.value,null):c(t,u.value,r-1),a.indexOf("\n")>-1&&(a=o?a.split("\n").map(function(t){return" "+t}).join("\n").substr(2):"\n"+a.split("\n").map(function(t){return" "+t}).join("\n"))):a=t.stylize("[Circular]","special")),w(s)){if(o&&i.match(/^\d+$/))return a;s=JSON.stringify(""+i),s.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(s=s.substr(1,s.length-2),s=t.stylize(s,"name")):(s=s.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),s=t.stylize(s,"string"))}return s+": "+a}function p(t,e,r){var n=0,i=t.reduce(function(t,e){return n++,e.indexOf("\n")>=0&&n++,t+e.replace(/\u001b\[\d\d?m/g,"").length+1},0);return i>60?r[0]+(""===e?"":e+"\n ")+" "+t.join(",\n ")+" "+r[1]:r[0]+e+" "+t.join(", ")+" "+r[1]}function d(t){return Array.isArray(t)}function g(t){return"boolean"==typeof t}function _(t){return null===t}function m(t){return null==t}function b(t){return"number"==typeof t}function y(t){return"string"==typeof t}function v(t){return"symbol"==typeof t}function w(t){return void 0===t}function S(t){return x(t)&&"[object RegExp]"===L(t)}function x(t){return"object"==typeof t&&null!==t}function E(t){return x(t)&&"[object Date]"===L(t)}function k(t){return x(t)&&("[object Error]"===L(t)||t instanceof Error)}function T(t){return"function"==typeof t}function A(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"==typeof t||"undefined"==typeof t}function L(t){return Object.prototype.toString.call(t)}function O(t){return 10>t?"0"+t.toString(10):t.toString(10)}function C(){var t=new Date,e=[O(t.getHours()),O(t.getMinutes()),O(t.getSeconds())].join(":");return[t.getDate(),R[t.getMonth()],e].join(" ")}function I(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var B=/%[sdj%]/g;e.format=function(t){if(!y(t)){for(var e=[],r=0;r<arguments.length;r++)e.push(i(arguments[r]));return e.join(" ")}for(var r=1,n=arguments,o=n.length,s=String(t).replace(B,function(t){if("%%"===t)return"%";if(r>=o)return t;switch(t){case"%s":return String(n[r++]);case"%d":return Number(n[r++]);case"%j":try{return JSON.stringify(n[r++])}catch(e){return"[Circular]"}default:return t}}),a=n[r];o>r;a=n[++r])s+=_(a)||!x(a)?" "+a:" "+i(a);return s},e.deprecate=function(r,i){function o(){if(!s){if(n.throwDeprecation)throw new Error(i);n.traceDeprecation?console.trace(i):console.error(i),s=!0}return r.apply(this,arguments)}if(w(t.process))return function(){return e.deprecate(r,i).apply(this,arguments)};if(n.noDeprecation===!0)return r;var s=!1;return o};var D,N={};e.debuglog=function(t){if(w(D)&&(D=n.env.NODE_DEBUG||""),t=t.toUpperCase(),!N[t])if(new RegExp("\\b"+t+"\\b","i").test(D)){var r=n.pid;N[t]=function(){var n=e.format.apply(e,arguments);console.error("%s %d: %s",t,r,n)}}else N[t]=function(){};return N[t]},e.inspect=i,i.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},i.styles={special:"cyan",number:"yellow","boolean":"yellow",undefined:"grey","null":"bold",string:"green",date:"magenta",regexp:"red"},e.isArray=d,e.isBoolean=g,e.isNull=_,e.isNullOrUndefined=m,e.isNumber=b,e.isString=y,e.isSymbol=v,e.isUndefined=w,e.isRegExp=S,e.isObject=x,e.isDate=E,e.isError=k,e.isFunction=T,e.isPrimitive=A,e.isBuffer=r(4);var R=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];e.log=function(){console.log("%s - %s",C(),e.format.apply(e,arguments))},e.inherits=r(5),e._extend=function(t,e){if(!e||!x(e))return t;for(var r=Object.keys(e),n=r.length;n--;)t[r[n]]=e[r[n]];return t}}).call(e,function(){return this}(),r(3))},function(t,e){function r(){u=!1,s.length?c=s.concat(c):l=-1,c.length&&n()}function n(){if(!u){var t=setTimeout(r);u=!0;for(var e=c.length;e;){for(s=c,c=[];++l<e;)s&&s[l].run();l=-1,e=c.length}s=null,u=!1,clearTimeout(t)}}function i(t,e){this.fun=t,this.array=e}function o(){}var s,a=t.exports={},c=[],u=!1,l=-1;a.nextTick=function(t){var e=new Array(arguments.length-1);if(arguments.length>1)for(var r=1;r<arguments.length;r++)e[r-1]=arguments[r];c.push(new i(t,e)),1!==c.length||u||setTimeout(n,0)},i.prototype.run=function(){this.fun.apply(null,this.array)},a.title="browser",a.browser=!0,a.env={},a.argv=[],a.version="",a.versions={},a.on=o,a.addListener=o,a.once=o,a.off=o,a.removeListener=o,a.removeAllListeners=o,a.emit=o,a.binding=function(t){throw new Error("process.binding is not supported")},a.cwd=function(){return"/"},a.chdir=function(t){throw new Error("process.chdir is not supported")},a.umask=function(){return 0}},function(t,e){t.exports=function(t){return t&&"object"==typeof t&&"function"==typeof t.copy&&"function"==typeof t.fill&&"function"==typeof t.readUInt8}},function(t,e){"function"==typeof Object.create?t.exports=function(t,e){t.super_=e,t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(t,e){t.super_=e;var r=function(){};r.prototype=e.prototype,t.prototype=new r,t.prototype.constructor=t}},function(t,e,r){function n(){i.call(this),this.blocks={},this.stacks=[],this.threads=[],this.sequencer=new o(this),this._primitives={},this._registerBlockPackages()}var i=r(1),o=r(7),s=r(9),a=r(2),c={scratch3:r(11),wedo2:r(12)};n.STACK_GLOW_ON="STACK_GLOW_ON",n.STACK_GLOW_OFF="STACK_GLOW_OFF",n.BLOCK_GLOW_ON="BLOCK_GLOW_ON",n.BLOCK_GLOW_OFF="BLOCK_GLOW_OFF",a.inherits(n,i),n.THREAD_STEP_INTERVAL=1e3/30,n.prototype.createBlock=function(t,e){this.blocks[t.id]=t;for(var r in t.fields){var n=t.fields[r].blocks;for(var i in n){var o=n[i];this.blocks[o.id]=o}}e||this.stacks.push(t.id)},n.prototype.changeBlock=function(t){"field"===t.element&&"undefined"!=typeof this.blocks[t.id]&&"undefined"!=typeof this.blocks[t.id].fields[t.name]&&(this.blocks[t.id].fields[t.name].value=t.value)},n.prototype.moveBlock=function(t){var e=this;void 0===t.newParent&&void 0!==t.oldParent?(e.stacks.push(t.id),void 0===t.oldField?e.blocks[t.oldParent].next=null:delete e.blocks[t.oldParent].fields[t.oldField]):void 0!==t.newParent&&(e._deleteStack(t.id),void 0===t.newField?e.blocks[t.newParent].next=t.id:e.blocks[t.newParent].fields[t.newField]={name:t.newField,value:t.id,blocks:{}})},n.prototype.deleteBlock=function(t){var e=this.blocks[t.id];null!==e.next&&this.deleteBlock({id:e.next});for(var r in e.fields)if("SUBSTACK"===r)this.deleteBlock({id:e.fields[r].value});else for(var n in e.fields[r].blocks)this.deleteBlock({id:n});this._deleteStack(t.id),delete this.blocks[t.id]},n.prototype._registerBlockPackages=function(){for(var t in c)if(c.hasOwnProperty(t)){var e=new c[t](this),r=e.getPrimitives();for(var n in r)r.hasOwnProperty(n)&&(this._primitives[n]=r[n].bind(e))}},n.prototype.getOpcodeFunction=function(t){return this._primitives[t]},n.prototype._pushThread=function(t){this.emit(n.STACK_GLOW_ON,t);var e=new s(t);this.threads.push(e)},n.prototype._removeThread=function(t){var e=this.threads.indexOf(t);e>-1&&(this.emit(n.STACK_GLOW_OFF,t.topBlock),this.threads.splice(e,1))},n.prototype.toggleStack=function(t){for(var e=0;e<this.threads.length;e++)if(this.threads[e].topBlock==t)return void this._removeThread(this.threads[e]);this._pushThread(t)},n.prototype.greenFlag=function(){for(var t=0;t<this.threads.length;t++)this._removeThread(this.threads[t]);for(var e=0;e<this.stacks.length;e++){var r=this.stacks[e];"event_whenflagclicked"===this.blocks[r].opcode&&this._pushThread(this.stacks[e])}},n.prototype.startDistanceSensors=function(){for(var t=0;t<this.stacks.length;t++){var e=this.stacks[t];if("wedo_whendistanceclose"===this.blocks[e].opcode){for(var r=!1,n=0;n<this.threads.length;n++)this.threads[n].topBlock===e&&(r=!0);r||this._pushThread(this.stacks[t])}}},n.prototype.stopAll=function(){for(var t=this.threads.slice();t.length>0;)this._removeThread(t.pop());window["native"]&&window["native"].motorStop()},n.prototype._step=function(){for(var t=this.sequencer.stepThreads(this.threads),e=0;e<t.length;e++)this._removeThread(t[e])},n.prototype.glowBlock=function(t,e){e?this.emit(n.BLOCK_GLOW_ON,t):this.emit(n.BLOCK_GLOW_OFF,t)},n.prototype.start=function(){window.setInterval&&window.setInterval(function(){this._step()}.bind(this),n.THREAD_STEP_INTERVAL)},n.prototype._deleteStack=function(t){var e=this.stacks.indexOf(t);e>-1&&this.stacks.splice(e,1)},n.prototype._getNextBlock=function(t){return"undefined"==typeof this.blocks[t]?null:this.blocks[t].next},n.prototype._getSubstack=function(t){return"undefined"==typeof this.blocks[t]?null:this.blocks[t].fields.SUBSTACK},n.prototype._getOpcode=function(t){return"undefined"==typeof this.blocks[t]?null:this.blocks[t].opcode},t.exports=n},function(t,e,r){function n(t){this.timer=new i,this.runtime=t}var i=r(8),o=r(9),s=r(10);n.WORK_TIME=10,n.prototype.stepThreads=function(t){this.timer.start();for(var e=[],r=0;t.length>0&&t.length>r&&this.timer.timeElapsed()<n.WORK_TIME;){for(var i=[],a=0;a<t.length;a++){var c=t[a];c.status===o.STATUS_RUNNING?this.stepThread(c):c.status===o.STATUS_YIELD?(s.resolve(c.yieldTimerId),r++):c.status===o.STATUS_DONE&&(c.status=o.STATUS_RUNNING),c.stack.length>0&&null===c.nextBlock&&c.status===o.STATUS_DONE&&(c.nextBlock=c.stack.pop(),null!==c.nextBlock&&c.status===o.STATUS_RUNNING),null===c.nextBlock&&c.status===o.STATUS_DONE?e.push(c):i.push(c)}t=i}return e},n.prototype.stepThread=function(t){var e=s.timerId,r=t.nextBlock;if(!r||!this.runtime.blocks[r])return void(t.status=o.STATUS_DONE);t.nextBlock=this.runtime._getNextBlock(r);var n=this.runtime._getOpcode(r);t.stack.push(r),t.stack.length>t.stackFrames.length&&t.stackFrames.push({});var i=t.stackFrames[t.stackFrames.length-1],a=function(){t.status=o.STATUS_YIELD},c=this,u=function(){t.status=o.STATUS_DONE,t.nextBlock=c.runtime._getNextBlock(r),t.stack.pop(),t.stackFrames.pop()},l=function(t){for(var e=0;e<c.runtime.stacks.length;e++){var r=c.runtime.stacks[e],n=c.runtime.blocks[r],i=t(n);if(i){for(var o=!1,s=0;s<c.runtime.threads.length;s++)if(c.runtime.threads[s].topBlock==r){o=!0;break}o||c.runtime._pushThread(r)}}},h=!1,f=function(){var e=c.runtime._getSubstack(r);e&&e.value?t.nextBlock=e.value:t.nextBlock=null,h=!0},p=[],d=this.runtime.blocks[r].fields;for(var g in d){var _=d[g];for(var m in _.blocks){var b=_.blocks[m],y=b.fields;for(var v in y){var w=y[v];p.push(w.value)}}}if(n){var S=this.runtime.getOpcodeFunction(n);if(S)try{S(p,{"yield":a,done:u,timeout:s.timeout,stackFrame:i,startSubstack:f,startHats:l})}catch(x){console.error("Exception calling block function for opcode: "+n+"\n"+x)}finally{s.timerId>e&&(t.yieldTimerId=s.timerId),t.status!==o.STATUS_RUNNING||h||u()}else console.warn("Could not get implementation for opcode: "+n)}else console.warn("Could not get opcode for block: "+r)},t.exports=n},function(t,e){function r(){this.startTime=0}r.prototype.time=function(){return Date.now()},r.prototype.start=function(){this.startTime=this.time()},r.prototype.timeElapsed=function(){return this.time()-this.startTime},t.exports=r},function(t,e){function r(t){this.topBlock=t,this.nextBlock=t,this.stack=[],this.stackFrames=[],this.status=0,this.yieldTimerId=-1}r.STATUS_RUNNING=0,r.STATUS_YIELD=1,r.STATUS_DONE=2,t.exports=r},function(t,e,r){function n(){}var i=r(8);n.timers={},n.timerId=0,n.globalTimer=new i,n.timeout=function(t,e){var r=++n.timerId;return n.timers[r]=[t,n.globalTimer.time()+e],r},n.resolve=function(t){var e=n.timers[t];if(!e)return!1;var r=e[0],i=e[1];return n.globalTimer.time()<i?!1:(r(),delete n.timers[t],!0)},n.reject=function(t){n.timers[t]&&delete n.timers[t]},n.rejectAll=function(){n.timers={},n.timerId=0},t.exports=n},function(t,e){function r(t){this.runtime=t}r.prototype.getPrimitives=function(){return{control_repeat:this.repeat,control_forever:this.forever,control_wait:this.wait,control_stop:this.stop,event_whenflagclicked:this.whenFlagClicked,event_whenbroadcastreceived:this.whenBroadcastReceived,event_broadcast:this.broadcast}},r.prototype.repeat=function(t,e){console.log("Running: control_repeat"),void 0===e.stackFrame.loopCounter&&(e.stackFrame.loopCounter=parseInt(t[0])),e.stackFrame.loopCounter--,e.stackFrame.loopCounter>=0&&e.startSubstack()},r.prototype.forever=function(t,e){console.log("Running: control_forever"),e.startSubstack()},r.prototype.wait=function(t,e){console.log("Running: control_wait"),e["yield"](),e.timeout(function(){e.done()},1e3*parseFloat(t[0]))},r.prototype.stop=function(){console.log("Running: control_stop"),this.runtime.stopAll()},r.prototype.whenFlagClicked=function(){console.log("Running: event_whenflagclicked")},r.prototype.whenBroadcastReceived=function(){console.log("Running: event_whenbroadcastreceived")},r.prototype.broadcast=function(t,e){console.log("Running: event_broadcast"),e.startHats(function(e){if("event_whenbroadcastreceived"===e.opcode){var r=e.fields.CHOICE.blocks;for(var n in r){var i=r[n];return i.fields.CHOICE.value===t[0]}}return!1})},t.exports=r},function(t,e,r){function n(t){this.runtime=t,this._motorSpeed=100,this._motorTimeout=null}var i=r(10);n.prototype.getPrimitives=function(){return{wedo_motorclockwise:this.motorClockwise,wedo_motorcounterclockwise:this.motorCounterClockwise,wedo_motorspeed:this.motorSpeed,wedo_setcolor:this.setColor,wedo_whendistanceclose:this.whenDistanceClose,wedo_whentilt:this.whenTilt}},n.prototype._clamp=function(t,e,r){return Math.max(e,Math.min(t,r))},n.prototype._motorOnFor=function(t,e,r){this._motorTimeout>0&&(i.resolve(this._motorTimeout),this._motorTimeout=null),window["native"]&&window["native"].motorRun(t,this._motorSpeed);var n=this,o=this._motorTimeout=r.timeout(function(){n._motorTimeout==o&&(n._motorTimeout=null),window["native"]&&window["native"].motorStop(),r.done()},1e3*e);r["yield"]()},n.prototype.motorClockwise=function(t,e){this._motorOnFor("right",parseFloat(t[0]),e)},n.prototype.motorCounterClockwise=function(t,e){this._motorOnFor("left",parseFloat(t[0]),e)},n.prototype.motorSpeed=function(t){var e=t[0];switch(e){case"slow":this._motorSpeed=20;break;case"medium":this._motorSpeed=50;break;case"fast":this._motorSpeed=100}},n.prototype._getColor=function(t){var e={yellow:7,orange:8,coral:9,magenta:1,purple:2,blue:3,green:6,white:10};return"mystery"==t?Math.floor(10*Math.random()+1):e[t]},n.prototype.setColor=function(t,e){if(window["native"]){var r=this._getColor(t[0]);window["native"].setLedColor(r)}e["yield"](),e.timeout(function(){e.done()},250)},n.prototype.whenDistanceClose=function(){console.log("Running: wedo_whendistanceclose")},n.prototype.whenTilt=function(){console.log("Running: wedo_whentilt")},t.exports=n},function(t,e,r){function n(t){var e={},r=t[0],n=r.attribs.name;e[n]={name:n,value:null,blocks:{}};var i=r.children[0],o=i.attribs.id,s=i.attribs.type;e[n].blocks[o]={id:o,opcode:s,next:null,fields:{}};var a=i.children[0],c=a.attribs.name,u=a.children[0].data;return e[n].blocks[o].fields[c]={name:c,value:u,blocks:null},e}var i=r(14),o=r(65),s=o(i.parseDOM,{length:1,resolvers:[String],max:200});t.exports=function(t){if("object"==typeof t&&"string"==typeof t.blockId&&"object"==typeof t.xml){var e={id:t.blockId,opcode:null,next:null,fields:{}};return"object"==typeof t.xml.attributes&&(e.opcode=t.xml.attributes.type.value),"string"!=typeof t.xml.innerHTML?e:""===t.xml.innerHTML?e:(e.fields=n(s(t.xml.innerHTML)),e)}}},function(t,e,r){function n(e,r){return delete t.exports[e],t.exports[e]=r,r}var i=r(15),o=r(22);t.exports={Parser:i,Tokenizer:r(16),ElementType:r(23),DomHandler:o,get FeedHandler(){return n("FeedHandler",r(26))},get Stream(){return n("Stream",r(27))},get WritableStream(){return n("WritableStream",r(28))},get ProxyHandler(){return n("ProxyHandler",r(51))},get DomUtils(){return n("DomUtils",r(52))},get CollectingHandler(){return n("CollectingHandler",r(64))},DefaultHandler:o,get RssHandler(){return n("RssHandler",this.FeedHandler)},parseDOM:function(t,e){var r=new o(e);return new i(r,e).end(t),r.dom},parseFeed:function(e,r){var n=new t.exports.FeedHandler(r);return new i(n,r).end(e),n.dom},createDomStream:function(t,e,r){var n=new o(t,e,r);return new i(n,e)},EVENTS:{attribute:2,cdatastart:0,cdataend:0,text:1,processinginstruction:2,comment:1,commentend:0,closetag:1,opentag:2,opentagname:1,error:1,end:0}}},function(t,e,r){function n(t,e){this._options=e||{},this._cbs=t||{},this._tagname="",this._attribname="",this._attribvalue="",this._attribs=null,this._stack=[],this.startIndex=0,this.endIndex=null,this._lowerCaseTagNames="lowerCaseTags"in this._options?!!this._options.lowerCaseTags:!this._options.xmlMode,this._lowerCaseAttributeNames="lowerCaseAttributeNames"in this._options?!!this._options.lowerCaseAttributeNames:!this._options.xmlMode,this._options.Tokenizer&&(i=this._options.Tokenizer),this._tokenizer=new i(this._options,this),this._cbs.onparserinit&&this._cbs.onparserinit(this)}var i=r(16),o={input:!0,option:!0,optgroup:!0,select:!0,button:!0,datalist:!0,textarea:!0},s={tr:{tr:!0,th:!0,td:!0},th:{th:!0},td:{thead:!0,th:!0,td:!0},body:{head:!0,link:!0,script:!0},li:{li:!0},p:{p:!0},h1:{p:!0},h2:{p:!0},h3:{p:!0},h4:{p:!0},h5:{p:!0},h6:{p:!0},select:o,input:o,output:o,button:o,datalist:o,textarea:o,option:{option:!0},optgroup:{optgroup:!0}},a={__proto__:null,area:!0,base:!0,basefont:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,isindex:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,path:!0,circle:!0,ellipse:!0,line:!0,rect:!0,use:!0,stop:!0,polyline:!0,polygon:!0},c=/\s|\//;r(2).inherits(n,r(1).EventEmitter),n.prototype._updatePosition=function(t){null===this.endIndex?this._tokenizer._sectionStart<=t?this.startIndex=0:this.startIndex=this._tokenizer._sectionStart-t:this.startIndex=this.endIndex+1,this.endIndex=this._tokenizer.getAbsoluteIndex()},n.prototype.ontext=function(t){this._updatePosition(1),this.endIndex--,this._cbs.ontext&&this._cbs.ontext(t)},n.prototype.onopentagname=function(t){if(this._lowerCaseTagNames&&(t=t.toLowerCase()),this._tagname=t,!this._options.xmlMode&&t in s)for(var e;(e=this._stack[this._stack.length-1])in s[t];this.onclosetag(e));!this._options.xmlMode&&t in a||this._stack.push(t),this._cbs.onopentagname&&this._cbs.onopentagname(t),this._cbs.onopentag&&(this._attribs={})},n.prototype.onopentagend=function(){this._updatePosition(1),this._attribs&&(this._cbs.onopentag&&this._cbs.onopentag(this._tagname,this._attribs),this._attribs=null),!this._options.xmlMode&&this._cbs.onclosetag&&this._tagname in a&&this._cbs.onclosetag(this._tagname),this._tagname=""},n.prototype.onclosetag=function(t){if(this._updatePosition(1),this._lowerCaseTagNames&&(t=t.toLowerCase()),!this._stack.length||t in a&&!this._options.xmlMode)this._options.xmlMode||"br"!==t&&"p"!==t||(this.onopentagname(t),this._closeCurrentTag());else{var e=this._stack.lastIndexOf(t);if(-1!==e)if(this._cbs.onclosetag)for(e=this._stack.length-e;e--;)this._cbs.onclosetag(this._stack.pop());else this._stack.length=e;else"p"!==t||this._options.xmlMode||(this.onopentagname(t),this._closeCurrentTag())}},n.prototype.onselfclosingtag=function(){this._options.xmlMode||this._options.recognizeSelfClosing?this._closeCurrentTag():this.onopentagend()},n.prototype._closeCurrentTag=function(){var t=this._tagname;this.onopentagend(),this._stack[this._stack.length-1]===t&&(this._cbs.onclosetag&&this._cbs.onclosetag(t),this._stack.pop())},n.prototype.onattribname=function(t){this._lowerCaseAttributeNames&&(t=t.toLowerCase()),this._attribname=t},n.prototype.onattribdata=function(t){this._attribvalue+=t},n.prototype.onattribend=function(){this._cbs.onattribute&&this._cbs.onattribute(this._attribname,this._attribvalue),this._attribs&&!Object.prototype.hasOwnProperty.call(this._attribs,this._attribname)&&(this._attribs[this._attribname]=this._attribvalue),this._attribname="",this._attribvalue=""},n.prototype._getInstructionName=function(t){var e=t.search(c),r=0>e?t:t.substr(0,e);return this._lowerCaseTagNames&&(r=r.toLowerCase()),r},n.prototype.ondeclaration=function(t){if(this._cbs.onprocessinginstruction){var e=this._getInstructionName(t);this._cbs.onprocessinginstruction("!"+e,"!"+t)}},n.prototype.onprocessinginstruction=function(t){if(this._cbs.onprocessinginstruction){var e=this._getInstructionName(t);this._cbs.onprocessinginstruction("?"+e,"?"+t)}},n.prototype.oncomment=function(t){this._updatePosition(4),this._cbs.oncomment&&this._cbs.oncomment(t),this._cbs.oncommentend&&this._cbs.oncommentend()},n.prototype.oncdata=function(t){this._updatePosition(1),this._options.xmlMode||this._options.recognizeCDATA?(this._cbs.oncdatastart&&this._cbs.oncdatastart(),this._cbs.ontext&&this._cbs.ontext(t),this._cbs.oncdataend&&this._cbs.oncdataend()):this.oncomment("[CDATA["+t+"]]")},n.prototype.onerror=function(t){this._cbs.onerror&&this._cbs.onerror(t)},n.prototype.onend=function(){if(this._cbs.onclosetag)for(var t=this._stack.length;t>0;this._cbs.onclosetag(this._stack[--t]));this._cbs.onend&&this._cbs.onend()},n.prototype.reset=function(){this._cbs.onreset&&this._cbs.onreset(),this._tokenizer.reset(),this._tagname="",this._attribname="",this._attribs=null,this._stack=[],this._cbs.onparserinit&&this._cbs.onparserinit(this)},n.prototype.parseComplete=function(t){this.reset(),this.end(t)},n.prototype.write=function(t){this._tokenizer.write(t)},n.prototype.end=function(t){this._tokenizer.end(t)},n.prototype.pause=function(){this._tokenizer.pause()},n.prototype.resume=function(){this._tokenizer.resume()},n.prototype.parseChunk=n.prototype.write,n.prototype.done=n.prototype.end,t.exports=n},function(t,e,r){function n(t){return" "===t||"\n"===t||" "===t||"\f"===t||"\r"===t}function i(t,e){return function(r){r===t&&(this._state=e)}}function o(t,e,r){var n=t.toLowerCase();return t===n?function(t){t===n?this._state=e:(this._state=r,this._index--)}:function(i){i===n||i===t?this._state=e:(this._state=r,this._index--)}}function s(t,e){var r=t.toLowerCase();return function(n){n===r||n===t?this._state=e:(this._state=g,this._index--)}}function a(t,e){this._state=p,this._buffer="",this._sectionStart=0,this._index=0,this._bufferOffset=0,this._baseState=p,this._special=gt,this._cbs=e,this._running=!0,this._ended=!1,this._xmlMode=!(!t||!t.xmlMode),this._decodeEntities=!(!t||!t.decodeEntities)}t.exports=a;var c=r(17),u=r(19),l=r(20),h=r(21),f=0,p=f++,d=f++,g=f++,_=f++,m=f++,b=f++,y=f++,v=f++,w=f++,S=f++,x=f++,E=f++,k=f++,T=f++,A=f++,L=f++,O=f++,C=f++,I=f++,B=f++,D=f++,N=f++,R=f++,q=f++,j=f++,P=f++,U=f++,M=f++,F=f++,z=f++,H=f++,V=f++,G=f++,Y=f++,W=f++,K=f++,J=f++,X=f++,Q=f++,Z=f++,$=f++,tt=f++,et=f++,rt=f++,nt=f++,it=f++,ot=f++,st=f++,at=f++,ct=f++,ut=f++,lt=f++,ht=f++,ft=f++,pt=f++,dt=0,gt=dt++,_t=dt++,mt=dt++;a.prototype._stateText=function(t){"<"===t?(this._index>this._sectionStart&&this._cbs.ontext(this._getSection()),this._state=d,this._sectionStart=this._index):this._decodeEntities&&this._special===gt&&"&"===t&&(this._index>this._sectionStart&&this._cbs.ontext(this._getSection()),this._baseState=p,this._state=ut,this._sectionStart=this._index)},a.prototype._stateBeforeTagName=function(t){"/"===t?this._state=m:">"===t||this._special!==gt||n(t)?this._state=p:"!"===t?(this._state=A,this._sectionStart=this._index+1):"?"===t?(this._state=O,this._sectionStart=this._index+1):"<"===t?(this._cbs.ontext(this._getSection()),this._sectionStart=this._index):(this._state=this._xmlMode||"s"!==t&&"S"!==t?g:H,this._sectionStart=this._index)},a.prototype._stateInTagName=function(t){("/"===t||">"===t||n(t))&&(this._emitToken("onopentagname"),this._state=v,this._index--)},a.prototype._stateBeforeCloseingTagName=function(t){n(t)||(">"===t?this._state=p:this._special!==gt?"s"===t||"S"===t?this._state=V:(this._state=p,this._index--):(this._state=b,this._sectionStart=this._index))},a.prototype._stateInCloseingTagName=function(t){(">"===t||n(t))&&(this._emitToken("onclosetag"),this._state=y,this._index--)},a.prototype._stateAfterCloseingTagName=function(t){">"===t&&(this._state=p,this._sectionStart=this._index+1)},a.prototype._stateBeforeAttributeName=function(t){">"===t?(this._cbs.onopentagend(),this._state=p,this._sectionStart=this._index+1):"/"===t?this._state=_:n(t)||(this._state=w,this._sectionStart=this._index)},a.prototype._stateInSelfClosingTag=function(t){">"===t?(this._cbs.onselfclosingtag(),this._state=p,this._sectionStart=this._index+1):n(t)||(this._state=v,this._index--)},a.prototype._stateInAttributeName=function(t){("="===t||"/"===t||">"===t||n(t))&&(this._cbs.onattribname(this._getSection()),this._sectionStart=-1,this._state=S,this._index--)},a.prototype._stateAfterAttributeName=function(t){"="===t?this._state=x:"/"===t||">"===t?(this._cbs.onattribend(),this._state=v,this._index--):n(t)||(this._cbs.onattribend(),this._state=w,this._sectionStart=this._index)},a.prototype._stateBeforeAttributeValue=function(t){'"'===t?(this._state=E,this._sectionStart=this._index+1):"'"===t?(this._state=k,this._sectionStart=this._index+1):n(t)||(this._state=T,this._sectionStart=this._index, -this._index--)},a.prototype._stateInAttributeValueDoubleQuotes=function(t){'"'===t?(this._emitToken("onattribdata"),this._cbs.onattribend(),this._state=v):this._decodeEntities&&"&"===t&&(this._emitToken("onattribdata"),this._baseState=this._state,this._state=ut,this._sectionStart=this._index)},a.prototype._stateInAttributeValueSingleQuotes=function(t){"'"===t?(this._emitToken("onattribdata"),this._cbs.onattribend(),this._state=v):this._decodeEntities&&"&"===t&&(this._emitToken("onattribdata"),this._baseState=this._state,this._state=ut,this._sectionStart=this._index)},a.prototype._stateInAttributeValueNoQuotes=function(t){n(t)||">"===t?(this._emitToken("onattribdata"),this._cbs.onattribend(),this._state=v,this._index--):this._decodeEntities&&"&"===t&&(this._emitToken("onattribdata"),this._baseState=this._state,this._state=ut,this._sectionStart=this._index)},a.prototype._stateBeforeDeclaration=function(t){this._state="["===t?N:"-"===t?C:L},a.prototype._stateInDeclaration=function(t){">"===t&&(this._cbs.ondeclaration(this._getSection()),this._state=p,this._sectionStart=this._index+1)},a.prototype._stateInProcessingInstruction=function(t){">"===t&&(this._cbs.onprocessinginstruction(this._getSection()),this._state=p,this._sectionStart=this._index+1)},a.prototype._stateBeforeComment=function(t){"-"===t?(this._state=I,this._sectionStart=this._index+1):this._state=L},a.prototype._stateInComment=function(t){"-"===t&&(this._state=B)},a.prototype._stateAfterComment1=function(t){"-"===t?this._state=D:this._state=I},a.prototype._stateAfterComment2=function(t){">"===t?(this._cbs.oncomment(this._buffer.substring(this._sectionStart,this._index-2)),this._state=p,this._sectionStart=this._index+1):"-"!==t&&(this._state=I)},a.prototype._stateBeforeCdata1=o("C",R,L),a.prototype._stateBeforeCdata2=o("D",q,L),a.prototype._stateBeforeCdata3=o("A",j,L),a.prototype._stateBeforeCdata4=o("T",P,L),a.prototype._stateBeforeCdata5=o("A",U,L),a.prototype._stateBeforeCdata6=function(t){"["===t?(this._state=M,this._sectionStart=this._index+1):(this._state=L,this._index--)},a.prototype._stateInCdata=function(t){"]"===t&&(this._state=F)},a.prototype._stateAfterCdata1=i("]",z),a.prototype._stateAfterCdata2=function(t){">"===t?(this._cbs.oncdata(this._buffer.substring(this._sectionStart,this._index-2)),this._state=p,this._sectionStart=this._index+1):"]"!==t&&(this._state=M)},a.prototype._stateBeforeSpecial=function(t){"c"===t||"C"===t?this._state=G:"t"===t||"T"===t?this._state=et:(this._state=g,this._index--)},a.prototype._stateBeforeSpecialEnd=function(t){this._special!==_t||"c"!==t&&"C"!==t?this._special!==mt||"t"!==t&&"T"!==t?this._state=p:this._state=ot:this._state=X},a.prototype._stateBeforeScript1=s("R",Y),a.prototype._stateBeforeScript2=s("I",W),a.prototype._stateBeforeScript3=s("P",K),a.prototype._stateBeforeScript4=s("T",J),a.prototype._stateBeforeScript5=function(t){("/"===t||">"===t||n(t))&&(this._special=_t),this._state=g,this._index--},a.prototype._stateAfterScript1=o("R",Q,p),a.prototype._stateAfterScript2=o("I",Z,p),a.prototype._stateAfterScript3=o("P",$,p),a.prototype._stateAfterScript4=o("T",tt,p),a.prototype._stateAfterScript5=function(t){">"===t||n(t)?(this._special=gt,this._state=b,this._sectionStart=this._index-6,this._index--):this._state=p},a.prototype._stateBeforeStyle1=s("Y",rt),a.prototype._stateBeforeStyle2=s("L",nt),a.prototype._stateBeforeStyle3=s("E",it),a.prototype._stateBeforeStyle4=function(t){("/"===t||">"===t||n(t))&&(this._special=mt),this._state=g,this._index--},a.prototype._stateAfterStyle1=o("Y",st,p),a.prototype._stateAfterStyle2=o("L",at,p),a.prototype._stateAfterStyle3=o("E",ct,p),a.prototype._stateAfterStyle4=function(t){">"===t||n(t)?(this._special=gt,this._state=b,this._sectionStart=this._index-5,this._index--):this._state=p},a.prototype._stateBeforeEntity=o("#",lt,ht),a.prototype._stateBeforeNumericEntity=o("X",pt,ft),a.prototype._parseNamedEntityStrict=function(){if(this._sectionStart+1<this._index){var t=this._buffer.substring(this._sectionStart+1,this._index),e=this._xmlMode?h:u;e.hasOwnProperty(t)&&(this._emitPartial(e[t]),this._sectionStart=this._index+1)}},a.prototype._parseLegacyEntity=function(){var t=this._sectionStart+1,e=this._index-t;for(e>6&&(e=6);e>=2;){var r=this._buffer.substr(t,e);if(l.hasOwnProperty(r))return this._emitPartial(l[r]),void(this._sectionStart+=e+1);e--}},a.prototype._stateInNamedEntity=function(t){";"===t?(this._parseNamedEntityStrict(),this._sectionStart+1<this._index&&!this._xmlMode&&this._parseLegacyEntity(),this._state=this._baseState):("a">t||t>"z")&&("A">t||t>"Z")&&("0">t||t>"9")&&(this._xmlMode||this._sectionStart+1===this._index||(this._baseState!==p?"="!==t&&this._parseNamedEntityStrict():this._parseLegacyEntity()),this._state=this._baseState,this._index--)},a.prototype._decodeNumericEntity=function(t,e){var r=this._sectionStart+t;if(r!==this._index){var n=this._buffer.substring(r,this._index),i=parseInt(n,e);this._emitPartial(c(i)),this._sectionStart=this._index}else this._sectionStart--;this._state=this._baseState},a.prototype._stateInNumericEntity=function(t){";"===t?(this._decodeNumericEntity(2,10),this._sectionStart++):("0">t||t>"9")&&(this._xmlMode?this._state=this._baseState:this._decodeNumericEntity(2,10),this._index--)},a.prototype._stateInHexEntity=function(t){";"===t?(this._decodeNumericEntity(3,16),this._sectionStart++):("a">t||t>"f")&&("A">t||t>"F")&&("0">t||t>"9")&&(this._xmlMode?this._state=this._baseState:this._decodeNumericEntity(3,16),this._index--)},a.prototype._cleanup=function(){this._sectionStart<0?(this._buffer="",this._index=0,this._bufferOffset+=this._index):this._running&&(this._state===p?(this._sectionStart!==this._index&&this._cbs.ontext(this._buffer.substr(this._sectionStart)),this._buffer="",this._index=0,this._bufferOffset+=this._index):this._sectionStart===this._index?(this._buffer="",this._index=0,this._bufferOffset+=this._index):(this._buffer=this._buffer.substr(this._sectionStart),this._index-=this._sectionStart,this._bufferOffset+=this._sectionStart),this._sectionStart=0)},a.prototype.write=function(t){this._ended&&this._cbs.onerror(Error(".write() after done!")),this._buffer+=t,this._parse()},a.prototype._parse=function(){for(;this._index<this._buffer.length&&this._running;){var t=this._buffer.charAt(this._index);this._state===p?this._stateText(t):this._state===d?this._stateBeforeTagName(t):this._state===g?this._stateInTagName(t):this._state===m?this._stateBeforeCloseingTagName(t):this._state===b?this._stateInCloseingTagName(t):this._state===y?this._stateAfterCloseingTagName(t):this._state===_?this._stateInSelfClosingTag(t):this._state===v?this._stateBeforeAttributeName(t):this._state===w?this._stateInAttributeName(t):this._state===S?this._stateAfterAttributeName(t):this._state===x?this._stateBeforeAttributeValue(t):this._state===E?this._stateInAttributeValueDoubleQuotes(t):this._state===k?this._stateInAttributeValueSingleQuotes(t):this._state===T?this._stateInAttributeValueNoQuotes(t):this._state===A?this._stateBeforeDeclaration(t):this._state===L?this._stateInDeclaration(t):this._state===O?this._stateInProcessingInstruction(t):this._state===C?this._stateBeforeComment(t):this._state===I?this._stateInComment(t):this._state===B?this._stateAfterComment1(t):this._state===D?this._stateAfterComment2(t):this._state===N?this._stateBeforeCdata1(t):this._state===R?this._stateBeforeCdata2(t):this._state===q?this._stateBeforeCdata3(t):this._state===j?this._stateBeforeCdata4(t):this._state===P?this._stateBeforeCdata5(t):this._state===U?this._stateBeforeCdata6(t):this._state===M?this._stateInCdata(t):this._state===F?this._stateAfterCdata1(t):this._state===z?this._stateAfterCdata2(t):this._state===H?this._stateBeforeSpecial(t):this._state===V?this._stateBeforeSpecialEnd(t):this._state===G?this._stateBeforeScript1(t):this._state===Y?this._stateBeforeScript2(t):this._state===W?this._stateBeforeScript3(t):this._state===K?this._stateBeforeScript4(t):this._state===J?this._stateBeforeScript5(t):this._state===X?this._stateAfterScript1(t):this._state===Q?this._stateAfterScript2(t):this._state===Z?this._stateAfterScript3(t):this._state===$?this._stateAfterScript4(t):this._state===tt?this._stateAfterScript5(t):this._state===et?this._stateBeforeStyle1(t):this._state===rt?this._stateBeforeStyle2(t):this._state===nt?this._stateBeforeStyle3(t):this._state===it?this._stateBeforeStyle4(t):this._state===ot?this._stateAfterStyle1(t):this._state===st?this._stateAfterStyle2(t):this._state===at?this._stateAfterStyle3(t):this._state===ct?this._stateAfterStyle4(t):this._state===ut?this._stateBeforeEntity(t):this._state===lt?this._stateBeforeNumericEntity(t):this._state===ht?this._stateInNamedEntity(t):this._state===ft?this._stateInNumericEntity(t):this._state===pt?this._stateInHexEntity(t):this._cbs.onerror(Error("unknown _state"),this._state),this._index++}this._cleanup()},a.prototype.pause=function(){this._running=!1},a.prototype.resume=function(){this._running=!0,this._index<this._buffer.length&&this._parse(),this._ended&&this._finish()},a.prototype.end=function(t){this._ended&&this._cbs.onerror(Error(".end() after done!")),t&&this.write(t),this._ended=!0,this._running&&this._finish()},a.prototype._finish=function(){this._sectionStart<this._index&&this._handleTrailingData(),this._cbs.onend()},a.prototype._handleTrailingData=function(){var t=this._buffer.substr(this._sectionStart);this._state===M||this._state===F||this._state===z?this._cbs.oncdata(t):this._state===I||this._state===B||this._state===D?this._cbs.oncomment(t):this._state!==ht||this._xmlMode?this._state!==ft||this._xmlMode?this._state!==pt||this._xmlMode?this._state!==g&&this._state!==v&&this._state!==x&&this._state!==S&&this._state!==w&&this._state!==k&&this._state!==E&&this._state!==T&&this._state!==b&&this._cbs.ontext(t):(this._decodeNumericEntity(3,16),this._sectionStart<this._index&&(this._state=this._baseState,this._handleTrailingData())):(this._decodeNumericEntity(2,10),this._sectionStart<this._index&&(this._state=this._baseState,this._handleTrailingData())):(this._parseLegacyEntity(),this._sectionStart<this._index&&(this._state=this._baseState,this._handleTrailingData()))},a.prototype.reset=function(){a.call(this,{xmlMode:this._xmlMode,decodeEntities:this._decodeEntities},this._cbs)},a.prototype.getAbsoluteIndex=function(){return this._bufferOffset+this._index},a.prototype._getSection=function(){return this._buffer.substring(this._sectionStart,this._index)},a.prototype._emitToken=function(t){this._cbs[t](this._getSection()),this._sectionStart=-1},a.prototype._emitPartial=function(t){this._baseState!==p?this._cbs.onattribdata(t):this._cbs.ontext(t)}},function(t,e,r){function n(t){if(t>=55296&&57343>=t||t>1114111)return"�";t in i&&(t=i[t]);var e="";return t>65535&&(t-=65536,e+=String.fromCharCode(t>>>10&1023|55296),t=56320|1023&t),e+=String.fromCharCode(t)}var i=r(18);t.exports=n},function(t,e){t.exports={0:65533,128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376}},function(t,e){t.exports={Aacute:"Á",aacute:"á",Abreve:"Ă",abreve:"ă",ac:"∾",acd:"∿",acE:"∾̳",Acirc:"Â",acirc:"â",acute:"´",Acy:"А",acy:"а",AElig:"Æ",aelig:"æ",af:"",Afr:"𝔄",afr:"𝔞",Agrave:"À",agrave:"à",alefsym:"ℵ",aleph:"ℵ",Alpha:"Α",alpha:"α",Amacr:"Ā",amacr:"ā",amalg:"⨿",amp:"&",AMP:"&",andand:"⩕",And:"⩓",and:"∧",andd:"⩜",andslope:"⩘",andv:"⩚",ang:"∠",ange:"⦤",angle:"∠",angmsdaa:"⦨",angmsdab:"⦩",angmsdac:"⦪",angmsdad:"⦫",angmsdae:"⦬",angmsdaf:"⦭",angmsdag:"⦮",angmsdah:"⦯",angmsd:"∡",angrt:"∟",angrtvb:"⊾",angrtvbd:"⦝",angsph:"∢",angst:"Å",angzarr:"⍼",Aogon:"Ą",aogon:"ą",Aopf:"𝔸",aopf:"𝕒",apacir:"⩯",ap:"≈",apE:"⩰",ape:"≊",apid:"≋",apos:"'",ApplyFunction:"",approx:"≈",approxeq:"≊",Aring:"Å",aring:"å",Ascr:"𝒜",ascr:"𝒶",Assign:"≔",ast:"*",asymp:"≈",asympeq:"≍",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",awconint:"∳",awint:"⨑",backcong:"≌",backepsilon:"϶",backprime:"‵",backsim:"∽",backsimeq:"⋍",Backslash:"∖",Barv:"⫧",barvee:"⊽",barwed:"⌅",Barwed:"⌆",barwedge:"⌅",bbrk:"⎵",bbrktbrk:"⎶",bcong:"≌",Bcy:"Б",bcy:"б",bdquo:"„",becaus:"∵",because:"∵",Because:"∵",bemptyv:"⦰",bepsi:"϶",bernou:"ℬ",Bernoullis:"ℬ",Beta:"Β",beta:"β",beth:"ℶ",between:"≬",Bfr:"𝔅",bfr:"𝔟",bigcap:"⋂",bigcirc:"◯",bigcup:"⋃",bigodot:"⨀",bigoplus:"⨁",bigotimes:"⨂",bigsqcup:"⨆",bigstar:"★",bigtriangledown:"▽",bigtriangleup:"△",biguplus:"⨄",bigvee:"⋁",bigwedge:"⋀",bkarow:"⤍",blacklozenge:"⧫",blacksquare:"▪",blacktriangle:"▴",blacktriangledown:"▾",blacktriangleleft:"◂",blacktriangleright:"▸",blank:"␣",blk12:"▒",blk14:"░",blk34:"▓",block:"█",bne:"=⃥",bnequiv:"≡⃥",bNot:"⫭",bnot:"⌐",Bopf:"𝔹",bopf:"𝕓",bot:"⊥",bottom:"⊥",bowtie:"⋈",boxbox:"⧉",boxdl:"┐",boxdL:"╕",boxDl:"╖",boxDL:"╗",boxdr:"┌",boxdR:"╒",boxDr:"╓",boxDR:"╔",boxh:"─",boxH:"═",boxhd:"┬",boxHd:"╤",boxhD:"╥",boxHD:"╦",boxhu:"┴",boxHu:"╧",boxhU:"╨",boxHU:"╩",boxminus:"⊟",boxplus:"⊞",boxtimes:"⊠",boxul:"┘",boxuL:"╛",boxUl:"╜",boxUL:"╝",boxur:"└",boxuR:"╘",boxUr:"╙",boxUR:"╚",boxv:"│",boxV:"║",boxvh:"┼",boxvH:"╪",boxVh:"╫",boxVH:"╬",boxvl:"┤",boxvL:"╡",boxVl:"╢",boxVL:"╣",boxvr:"├",boxvR:"╞",boxVr:"╟",boxVR:"╠",bprime:"‵",breve:"˘",Breve:"˘",brvbar:"¦",bscr:"𝒷",Bscr:"ℬ",bsemi:"⁏",bsim:"∽",bsime:"⋍",bsolb:"⧅",bsol:"\\",bsolhsub:"⟈",bull:"•",bullet:"•",bump:"≎",bumpE:"⪮",bumpe:"≏",Bumpeq:"≎",bumpeq:"≏",Cacute:"Ć",cacute:"ć",capand:"⩄",capbrcup:"⩉",capcap:"⩋",cap:"∩",Cap:"⋒",capcup:"⩇",capdot:"⩀",CapitalDifferentialD:"ⅅ",caps:"∩︀",caret:"⁁",caron:"ˇ",Cayleys:"ℭ",ccaps:"⩍",Ccaron:"Č",ccaron:"č",Ccedil:"Ç",ccedil:"ç",Ccirc:"Ĉ",ccirc:"ĉ",Cconint:"∰",ccups:"⩌",ccupssm:"⩐",Cdot:"Ċ",cdot:"ċ",cedil:"¸",Cedilla:"¸",cemptyv:"⦲",cent:"¢",centerdot:"·",CenterDot:"·",cfr:"𝔠",Cfr:"ℭ",CHcy:"Ч",chcy:"ч",check:"✓",checkmark:"✓",Chi:"Χ",chi:"χ",circ:"ˆ",circeq:"≗",circlearrowleft:"↺",circlearrowright:"↻",circledast:"⊛",circledcirc:"⊚",circleddash:"⊝",CircleDot:"⊙",circledR:"®",circledS:"Ⓢ",CircleMinus:"⊖",CirclePlus:"⊕",CircleTimes:"⊗",cir:"○",cirE:"⧃",cire:"≗",cirfnint:"⨐",cirmid:"⫯",cirscir:"⧂",ClockwiseContourIntegral:"∲",CloseCurlyDoubleQuote:"”",CloseCurlyQuote:"’",clubs:"♣",clubsuit:"♣",colon:":",Colon:"∷",Colone:"⩴",colone:"≔",coloneq:"≔",comma:",",commat:"@",comp:"∁",compfn:"∘",complement:"∁",complexes:"ℂ",cong:"≅",congdot:"⩭",Congruent:"≡",conint:"∮",Conint:"∯",ContourIntegral:"∮",copf:"𝕔",Copf:"ℂ",coprod:"∐",Coproduct:"∐",copy:"©",COPY:"©",copysr:"℗",CounterClockwiseContourIntegral:"∳",crarr:"↵",cross:"✗",Cross:"⨯",Cscr:"𝒞",cscr:"𝒸",csub:"⫏",csube:"⫑",csup:"⫐",csupe:"⫒",ctdot:"⋯",cudarrl:"⤸",cudarrr:"⤵",cuepr:"⋞",cuesc:"⋟",cularr:"↶",cularrp:"⤽",cupbrcap:"⩈",cupcap:"⩆",CupCap:"≍",cup:"∪",Cup:"⋓",cupcup:"⩊",cupdot:"⊍",cupor:"⩅",cups:"∪︀",curarr:"↷",curarrm:"⤼",curlyeqprec:"⋞",curlyeqsucc:"⋟",curlyvee:"⋎",curlywedge:"⋏",curren:"¤",curvearrowleft:"↶",curvearrowright:"↷",cuvee:"⋎",cuwed:"⋏",cwconint:"∲",cwint:"∱",cylcty:"⌭",dagger:"†",Dagger:"‡",daleth:"ℸ",darr:"↓",Darr:"↡",dArr:"⇓",dash:"‐",Dashv:"⫤",dashv:"⊣",dbkarow:"⤏",dblac:"˝",Dcaron:"Ď",dcaron:"ď",Dcy:"Д",dcy:"д",ddagger:"‡",ddarr:"⇊",DD:"ⅅ",dd:"ⅆ",DDotrahd:"⤑",ddotseq:"⩷",deg:"°",Del:"∇",Delta:"Δ",delta:"δ",demptyv:"⦱",dfisht:"⥿",Dfr:"𝔇",dfr:"𝔡",dHar:"⥥",dharl:"⇃",dharr:"⇂",DiacriticalAcute:"´",DiacriticalDot:"˙",DiacriticalDoubleAcute:"˝",DiacriticalGrave:"`",DiacriticalTilde:"˜",diam:"⋄",diamond:"⋄",Diamond:"⋄",diamondsuit:"♦",diams:"♦",die:"¨",DifferentialD:"ⅆ",digamma:"ϝ",disin:"⋲",div:"÷",divide:"÷",divideontimes:"⋇",divonx:"⋇",DJcy:"Ђ",djcy:"ђ",dlcorn:"⌞",dlcrop:"⌍",dollar:"$",Dopf:"𝔻",dopf:"𝕕",Dot:"¨",dot:"˙",DotDot:"⃜",doteq:"≐",doteqdot:"≑",DotEqual:"≐",dotminus:"∸",dotplus:"∔",dotsquare:"⊡",doublebarwedge:"⌆",DoubleContourIntegral:"∯",DoubleDot:"¨",DoubleDownArrow:"⇓",DoubleLeftArrow:"⇐",DoubleLeftRightArrow:"⇔",DoubleLeftTee:"⫤",DoubleLongLeftArrow:"⟸",DoubleLongLeftRightArrow:"⟺",DoubleLongRightArrow:"⟹",DoubleRightArrow:"⇒",DoubleRightTee:"⊨",DoubleUpArrow:"⇑",DoubleUpDownArrow:"⇕",DoubleVerticalBar:"∥",DownArrowBar:"⤓",downarrow:"↓",DownArrow:"↓",Downarrow:"⇓",DownArrowUpArrow:"⇵",DownBreve:"̑",downdownarrows:"⇊",downharpoonleft:"⇃",downharpoonright:"⇂",DownLeftRightVector:"⥐",DownLeftTeeVector:"⥞",DownLeftVectorBar:"⥖",DownLeftVector:"↽",DownRightTeeVector:"⥟",DownRightVectorBar:"⥗",DownRightVector:"⇁",DownTeeArrow:"↧",DownTee:"⊤",drbkarow:"⤐",drcorn:"⌟",drcrop:"⌌",Dscr:"𝒟",dscr:"𝒹",DScy:"Ѕ",dscy:"ѕ",dsol:"⧶",Dstrok:"Đ",dstrok:"đ",dtdot:"⋱",dtri:"▿",dtrif:"▾",duarr:"⇵",duhar:"⥯",dwangle:"⦦",DZcy:"Џ",dzcy:"џ",dzigrarr:"⟿",Eacute:"É",eacute:"é",easter:"⩮",Ecaron:"Ě",ecaron:"ě",Ecirc:"Ê",ecirc:"ê",ecir:"≖",ecolon:"≕",Ecy:"Э",ecy:"э",eDDot:"⩷",Edot:"Ė",edot:"ė",eDot:"≑",ee:"ⅇ",efDot:"≒",Efr:"𝔈",efr:"𝔢",eg:"⪚",Egrave:"È",egrave:"è",egs:"⪖",egsdot:"⪘",el:"⪙",Element:"∈",elinters:"⏧",ell:"ℓ",els:"⪕",elsdot:"⪗",Emacr:"Ē",emacr:"ē",empty:"∅",emptyset:"∅",EmptySmallSquare:"◻",emptyv:"∅",EmptyVerySmallSquare:"▫",emsp13:" ",emsp14:" ",emsp:" ",ENG:"Ŋ",eng:"ŋ",ensp:" ",Eogon:"Ę",eogon:"ę",Eopf:"𝔼",eopf:"𝕖",epar:"⋕",eparsl:"⧣",eplus:"⩱",epsi:"ε",Epsilon:"Ε",epsilon:"ε",epsiv:"ϵ",eqcirc:"≖",eqcolon:"≕",eqsim:"≂",eqslantgtr:"⪖",eqslantless:"⪕",Equal:"⩵",equals:"=",EqualTilde:"≂",equest:"≟",Equilibrium:"⇌",equiv:"≡",equivDD:"⩸",eqvparsl:"⧥",erarr:"⥱",erDot:"≓",escr:"ℯ",Escr:"ℰ",esdot:"≐",Esim:"⩳",esim:"≂",Eta:"Η",eta:"η",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",euro:"€",excl:"!",exist:"∃",Exists:"∃",expectation:"ℰ",exponentiale:"ⅇ",ExponentialE:"ⅇ",fallingdotseq:"≒",Fcy:"Ф",fcy:"ф",female:"♀",ffilig:"ffi",fflig:"ff",ffllig:"ffl",Ffr:"𝔉",ffr:"𝔣",filig:"fi",FilledSmallSquare:"◼",FilledVerySmallSquare:"▪",fjlig:"fj",flat:"♭",fllig:"fl",fltns:"▱",fnof:"ƒ",Fopf:"𝔽",fopf:"𝕗",forall:"∀",ForAll:"∀",fork:"⋔",forkv:"⫙",Fouriertrf:"ℱ",fpartint:"⨍",frac12:"½",frac13:"⅓",frac14:"¼",frac15:"⅕",frac16:"⅙",frac18:"⅛",frac23:"⅔",frac25:"⅖",frac34:"¾",frac35:"⅗",frac38:"⅜",frac45:"⅘",frac56:"⅚",frac58:"⅝",frac78:"⅞",frasl:"⁄",frown:"⌢",fscr:"𝒻",Fscr:"ℱ",gacute:"ǵ",Gamma:"Γ",gamma:"γ",Gammad:"Ϝ",gammad:"ϝ",gap:"⪆",Gbreve:"Ğ",gbreve:"ğ",Gcedil:"Ģ",Gcirc:"Ĝ",gcirc:"ĝ",Gcy:"Г",gcy:"г",Gdot:"Ġ",gdot:"ġ",ge:"≥",gE:"≧",gEl:"⪌",gel:"⋛",geq:"≥",geqq:"≧",geqslant:"⩾",gescc:"⪩",ges:"⩾",gesdot:"⪀",gesdoto:"⪂",gesdotol:"⪄",gesl:"⋛︀",gesles:"⪔",Gfr:"𝔊",gfr:"𝔤",gg:"≫",Gg:"⋙",ggg:"⋙",gimel:"ℷ",GJcy:"Ѓ",gjcy:"ѓ",gla:"⪥",gl:"≷",glE:"⪒",glj:"⪤",gnap:"⪊",gnapprox:"⪊",gne:"⪈",gnE:"≩",gneq:"⪈",gneqq:"≩",gnsim:"⋧",Gopf:"𝔾",gopf:"𝕘",grave:"`",GreaterEqual:"≥",GreaterEqualLess:"⋛",GreaterFullEqual:"≧",GreaterGreater:"⪢",GreaterLess:"≷",GreaterSlantEqual:"⩾",GreaterTilde:"≳",Gscr:"𝒢",gscr:"ℊ",gsim:"≳",gsime:"⪎",gsiml:"⪐",gtcc:"⪧",gtcir:"⩺",gt:">",GT:">",Gt:"≫",gtdot:"⋗",gtlPar:"⦕",gtquest:"⩼",gtrapprox:"⪆",gtrarr:"⥸",gtrdot:"⋗",gtreqless:"⋛",gtreqqless:"⪌",gtrless:"≷",gtrsim:"≳",gvertneqq:"≩︀",gvnE:"≩︀",Hacek:"ˇ",hairsp:" ",half:"½",hamilt:"ℋ",HARDcy:"Ъ",hardcy:"ъ",harrcir:"⥈",harr:"↔",hArr:"⇔",harrw:"↭",Hat:"^",hbar:"ℏ",Hcirc:"Ĥ",hcirc:"ĥ",hearts:"♥",heartsuit:"♥",hellip:"…",hercon:"⊹",hfr:"𝔥",Hfr:"ℌ",HilbertSpace:"ℋ",hksearow:"⤥",hkswarow:"⤦",hoarr:"⇿",homtht:"∻",hookleftarrow:"↩",hookrightarrow:"↪",hopf:"𝕙",Hopf:"ℍ",horbar:"―",HorizontalLine:"─",hscr:"𝒽",Hscr:"ℋ",hslash:"ℏ",Hstrok:"Ħ",hstrok:"ħ",HumpDownHump:"≎",HumpEqual:"≏",hybull:"⁃",hyphen:"‐",Iacute:"Í",iacute:"í",ic:"",Icirc:"Î",icirc:"î",Icy:"И",icy:"и",Idot:"İ",IEcy:"Е",iecy:"е",iexcl:"¡",iff:"⇔",ifr:"𝔦",Ifr:"ℑ",Igrave:"Ì",igrave:"ì",ii:"ⅈ",iiiint:"⨌",iiint:"∭",iinfin:"⧜",iiota:"℩",IJlig:"IJ",ijlig:"ij",Imacr:"Ī",imacr:"ī",image:"ℑ",ImaginaryI:"ⅈ",imagline:"ℐ",imagpart:"ℑ",imath:"ı",Im:"ℑ",imof:"⊷",imped:"Ƶ",Implies:"⇒",incare:"℅","in":"∈",infin:"∞",infintie:"⧝",inodot:"ı",intcal:"⊺","int":"∫",Int:"∬",integers:"ℤ",Integral:"∫",intercal:"⊺",Intersection:"⋂",intlarhk:"⨗",intprod:"⨼",InvisibleComma:"",InvisibleTimes:"",IOcy:"Ё",iocy:"ё",Iogon:"Į",iogon:"į",Iopf:"𝕀",iopf:"𝕚",Iota:"Ι",iota:"ι",iprod:"⨼",iquest:"¿",iscr:"𝒾",Iscr:"ℐ",isin:"∈",isindot:"⋵",isinE:"⋹",isins:"⋴",isinsv:"⋳",isinv:"∈",it:"",Itilde:"Ĩ",itilde:"ĩ",Iukcy:"І",iukcy:"і",Iuml:"Ï",iuml:"ï",Jcirc:"Ĵ",jcirc:"ĵ",Jcy:"Й",jcy:"й",Jfr:"𝔍",jfr:"𝔧",jmath:"ȷ",Jopf:"𝕁",jopf:"𝕛",Jscr:"𝒥",jscr:"𝒿",Jsercy:"Ј",jsercy:"ј",Jukcy:"Є",jukcy:"є",Kappa:"Κ",kappa:"κ",kappav:"ϰ",Kcedil:"Ķ",kcedil:"ķ",Kcy:"К",kcy:"к",Kfr:"𝔎",kfr:"𝔨",kgreen:"ĸ",KHcy:"Х",khcy:"х",KJcy:"Ќ",kjcy:"ќ",Kopf:"𝕂",kopf:"𝕜",Kscr:"𝒦",kscr:"𝓀",lAarr:"⇚",Lacute:"Ĺ",lacute:"ĺ",laemptyv:"⦴",lagran:"ℒ",Lambda:"Λ",lambda:"λ",lang:"⟨",Lang:"⟪",langd:"⦑",langle:"⟨",lap:"⪅",Laplacetrf:"ℒ",laquo:"«",larrb:"⇤",larrbfs:"⤟",larr:"←",Larr:"↞",lArr:"⇐",larrfs:"⤝",larrhk:"↩",larrlp:"↫",larrpl:"⤹",larrsim:"⥳",larrtl:"↢",latail:"⤙",lAtail:"⤛",lat:"⪫",late:"⪭",lates:"⪭︀",lbarr:"⤌",lBarr:"⤎",lbbrk:"❲",lbrace:"{",lbrack:"[",lbrke:"⦋",lbrksld:"⦏",lbrkslu:"⦍",Lcaron:"Ľ",lcaron:"ľ",Lcedil:"Ļ",lcedil:"ļ",lceil:"⌈",lcub:"{",Lcy:"Л",lcy:"л",ldca:"⤶",ldquo:"“",ldquor:"„",ldrdhar:"⥧",ldrushar:"⥋",ldsh:"↲",le:"≤",lE:"≦",LeftAngleBracket:"⟨",LeftArrowBar:"⇤",leftarrow:"←",LeftArrow:"←",Leftarrow:"⇐",LeftArrowRightArrow:"⇆",leftarrowtail:"↢",LeftCeiling:"⌈",LeftDoubleBracket:"⟦",LeftDownTeeVector:"⥡",LeftDownVectorBar:"⥙",LeftDownVector:"⇃",LeftFloor:"⌊",leftharpoondown:"↽",leftharpoonup:"↼",leftleftarrows:"⇇",leftrightarrow:"↔",LeftRightArrow:"↔",Leftrightarrow:"⇔",leftrightarrows:"⇆",leftrightharpoons:"⇋",leftrightsquigarrow:"↭",LeftRightVector:"⥎",LeftTeeArrow:"↤",LeftTee:"⊣",LeftTeeVector:"⥚",leftthreetimes:"⋋",LeftTriangleBar:"⧏",LeftTriangle:"⊲",LeftTriangleEqual:"⊴",LeftUpDownVector:"⥑",LeftUpTeeVector:"⥠",LeftUpVectorBar:"⥘",LeftUpVector:"↿",LeftVectorBar:"⥒",LeftVector:"↼",lEg:"⪋",leg:"⋚",leq:"≤",leqq:"≦",leqslant:"⩽",lescc:"⪨",les:"⩽",lesdot:"⩿",lesdoto:"⪁",lesdotor:"⪃",lesg:"⋚︀",lesges:"⪓",lessapprox:"⪅",lessdot:"⋖",lesseqgtr:"⋚",lesseqqgtr:"⪋",LessEqualGreater:"⋚",LessFullEqual:"≦",LessGreater:"≶",lessgtr:"≶",LessLess:"⪡",lesssim:"≲",LessSlantEqual:"⩽",LessTilde:"≲",lfisht:"⥼",lfloor:"⌊",Lfr:"𝔏",lfr:"𝔩",lg:"≶",lgE:"⪑",lHar:"⥢",lhard:"↽",lharu:"↼",lharul:"⥪",lhblk:"▄",LJcy:"Љ",ljcy:"љ",llarr:"⇇",ll:"≪",Ll:"⋘",llcorner:"⌞",Lleftarrow:"⇚",llhard:"⥫",lltri:"◺",Lmidot:"Ŀ",lmidot:"ŀ",lmoustache:"⎰",lmoust:"⎰",lnap:"⪉",lnapprox:"⪉",lne:"⪇",lnE:"≨",lneq:"⪇",lneqq:"≨",lnsim:"⋦",loang:"⟬",loarr:"⇽",lobrk:"⟦",longleftarrow:"⟵",LongLeftArrow:"⟵",Longleftarrow:"⟸",longleftrightarrow:"⟷",LongLeftRightArrow:"⟷",Longleftrightarrow:"⟺",longmapsto:"⟼",longrightarrow:"⟶",LongRightArrow:"⟶",Longrightarrow:"⟹",looparrowleft:"↫",looparrowright:"↬",lopar:"⦅",Lopf:"𝕃",lopf:"𝕝",loplus:"⨭",lotimes:"⨴",lowast:"∗",lowbar:"_",LowerLeftArrow:"↙",LowerRightArrow:"↘",loz:"◊",lozenge:"◊",lozf:"⧫",lpar:"(",lparlt:"⦓",lrarr:"⇆",lrcorner:"⌟",lrhar:"⇋",lrhard:"⥭",lrm:"",lrtri:"⊿",lsaquo:"‹",lscr:"𝓁",Lscr:"ℒ",lsh:"↰",Lsh:"↰",lsim:"≲",lsime:"⪍",lsimg:"⪏",lsqb:"[",lsquo:"‘",lsquor:"‚",Lstrok:"Ł",lstrok:"ł",ltcc:"⪦",ltcir:"⩹",lt:"<",LT:"<",Lt:"≪",ltdot:"⋖",lthree:"⋋",ltimes:"⋉",ltlarr:"⥶",ltquest:"⩻",ltri:"◃",ltrie:"⊴",ltrif:"◂",ltrPar:"⦖",lurdshar:"⥊",luruhar:"⥦",lvertneqq:"≨︀",lvnE:"≨︀",macr:"¯",male:"♂",malt:"✠",maltese:"✠",Map:"⤅",map:"↦",mapsto:"↦",mapstodown:"↧",mapstoleft:"↤",mapstoup:"↥",marker:"▮",mcomma:"⨩",Mcy:"М",mcy:"м",mdash:"—",mDDot:"∺",measuredangle:"∡",MediumSpace:" ",Mellintrf:"ℳ",Mfr:"𝔐",mfr:"𝔪",mho:"℧",micro:"µ",midast:"*",midcir:"⫰",mid:"∣",middot:"·",minusb:"⊟",minus:"−",minusd:"∸",minusdu:"⨪",MinusPlus:"∓",mlcp:"⫛",mldr:"…",mnplus:"∓",models:"⊧",Mopf:"𝕄",mopf:"𝕞",mp:"∓",mscr:"𝓂",Mscr:"ℳ",mstpos:"∾",Mu:"Μ",mu:"μ",multimap:"⊸",mumap:"⊸",nabla:"∇",Nacute:"Ń",nacute:"ń",nang:"∠⃒",nap:"≉",napE:"⩰̸",napid:"≋̸",napos:"ʼn",napprox:"≉",natural:"♮",naturals:"ℕ",natur:"♮",nbsp:" ",nbump:"≎̸",nbumpe:"≏̸",ncap:"⩃",Ncaron:"Ň",ncaron:"ň",Ncedil:"Ņ",ncedil:"ņ",ncong:"≇",ncongdot:"⩭̸",ncup:"⩂",Ncy:"Н",ncy:"н",ndash:"–",nearhk:"⤤",nearr:"↗",neArr:"⇗",nearrow:"↗",ne:"≠",nedot:"≐̸",NegativeMediumSpace:"",NegativeThickSpace:"",NegativeThinSpace:"",NegativeVeryThinSpace:"",nequiv:"≢",nesear:"⤨",nesim:"≂̸",NestedGreaterGreater:"≫",NestedLessLess:"≪",NewLine:"\n",nexist:"∄",nexists:"∄",Nfr:"𝔑",nfr:"𝔫",ngE:"≧̸",nge:"≱",ngeq:"≱",ngeqq:"≧̸",ngeqslant:"⩾̸",nges:"⩾̸",nGg:"⋙̸",ngsim:"≵",nGt:"≫⃒",ngt:"≯",ngtr:"≯",nGtv:"≫̸",nharr:"↮",nhArr:"⇎",nhpar:"⫲",ni:"∋",nis:"⋼",nisd:"⋺",niv:"∋",NJcy:"Њ",njcy:"њ",nlarr:"↚",nlArr:"⇍",nldr:"‥",nlE:"≦̸",nle:"≰",nleftarrow:"↚",nLeftarrow:"⇍",nleftrightarrow:"↮",nLeftrightarrow:"⇎",nleq:"≰",nleqq:"≦̸",nleqslant:"⩽̸",nles:"⩽̸",nless:"≮",nLl:"⋘̸",nlsim:"≴",nLt:"≪⃒",nlt:"≮",nltri:"⋪",nltrie:"⋬",nLtv:"≪̸",nmid:"∤",NoBreak:"",NonBreakingSpace:" ",nopf:"𝕟",Nopf:"ℕ",Not:"⫬",not:"¬",NotCongruent:"≢",NotCupCap:"≭",NotDoubleVerticalBar:"∦",NotElement:"∉",NotEqual:"≠",NotEqualTilde:"≂̸",NotExists:"∄",NotGreater:"≯",NotGreaterEqual:"≱",NotGreaterFullEqual:"≧̸",NotGreaterGreater:"≫̸",NotGreaterLess:"≹",NotGreaterSlantEqual:"⩾̸",NotGreaterTilde:"≵",NotHumpDownHump:"≎̸",NotHumpEqual:"≏̸",notin:"∉",notindot:"⋵̸",notinE:"⋹̸",notinva:"∉",notinvb:"⋷",notinvc:"⋶",NotLeftTriangleBar:"⧏̸",NotLeftTriangle:"⋪",NotLeftTriangleEqual:"⋬",NotLess:"≮",NotLessEqual:"≰",NotLessGreater:"≸",NotLessLess:"≪̸",NotLessSlantEqual:"⩽̸",NotLessTilde:"≴",NotNestedGreaterGreater:"⪢̸",NotNestedLessLess:"⪡̸",notni:"∌",notniva:"∌",notnivb:"⋾",notnivc:"⋽",NotPrecedes:"⊀",NotPrecedesEqual:"⪯̸",NotPrecedesSlantEqual:"⋠",NotReverseElement:"∌",NotRightTriangleBar:"⧐̸",NotRightTriangle:"⋫",NotRightTriangleEqual:"⋭",NotSquareSubset:"⊏̸",NotSquareSubsetEqual:"⋢",NotSquareSuperset:"⊐̸",NotSquareSupersetEqual:"⋣",NotSubset:"⊂⃒",NotSubsetEqual:"⊈",NotSucceeds:"⊁",NotSucceedsEqual:"⪰̸",NotSucceedsSlantEqual:"⋡",NotSucceedsTilde:"≿̸",NotSuperset:"⊃⃒",NotSupersetEqual:"⊉",NotTilde:"≁",NotTildeEqual:"≄",NotTildeFullEqual:"≇",NotTildeTilde:"≉",NotVerticalBar:"∤",nparallel:"∦",npar:"∦",nparsl:"⫽⃥",npart:"∂̸",npolint:"⨔",npr:"⊀",nprcue:"⋠",nprec:"⊀",npreceq:"⪯̸",npre:"⪯̸",nrarrc:"⤳̸",nrarr:"↛",nrArr:"⇏",nrarrw:"↝̸",nrightarrow:"↛",nRightarrow:"⇏",nrtri:"⋫",nrtrie:"⋭",nsc:"⊁",nsccue:"⋡",nsce:"⪰̸",Nscr:"𝒩",nscr:"𝓃",nshortmid:"∤",nshortparallel:"∦",nsim:"≁",nsime:"≄",nsimeq:"≄",nsmid:"∤",nspar:"∦",nsqsube:"⋢",nsqsupe:"⋣",nsub:"⊄",nsubE:"⫅̸",nsube:"⊈",nsubset:"⊂⃒",nsubseteq:"⊈",nsubseteqq:"⫅̸",nsucc:"⊁",nsucceq:"⪰̸",nsup:"⊅",nsupE:"⫆̸",nsupe:"⊉",nsupset:"⊃⃒",nsupseteq:"⊉",nsupseteqq:"⫆̸",ntgl:"≹",Ntilde:"Ñ",ntilde:"ñ",ntlg:"≸",ntriangleleft:"⋪",ntrianglelefteq:"⋬",ntriangleright:"⋫",ntrianglerighteq:"⋭",Nu:"Ν",nu:"ν",num:"#",numero:"№",numsp:" ",nvap:"≍⃒",nvdash:"⊬",nvDash:"⊭",nVdash:"⊮",nVDash:"⊯",nvge:"≥⃒",nvgt:">⃒",nvHarr:"⤄",nvinfin:"⧞",nvlArr:"⤂",nvle:"≤⃒",nvlt:"<⃒",nvltrie:"⊴⃒",nvrArr:"⤃",nvrtrie:"⊵⃒",nvsim:"∼⃒",nwarhk:"⤣",nwarr:"↖",nwArr:"⇖",nwarrow:"↖",nwnear:"⤧",Oacute:"Ó",oacute:"ó",oast:"⊛",Ocirc:"Ô",ocirc:"ô",ocir:"⊚",Ocy:"О",ocy:"о",odash:"⊝",Odblac:"Ő",odblac:"ő",odiv:"⨸",odot:"⊙",odsold:"⦼",OElig:"Œ",oelig:"œ",ofcir:"⦿",Ofr:"𝔒",ofr:"𝔬",ogon:"˛",Ograve:"Ò",ograve:"ò",ogt:"⧁",ohbar:"⦵",ohm:"Ω",oint:"∮",olarr:"↺",olcir:"⦾",olcross:"⦻",oline:"‾",olt:"⧀",Omacr:"Ō",omacr:"ō",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",omid:"⦶",ominus:"⊖",Oopf:"𝕆",oopf:"𝕠",opar:"⦷",OpenCurlyDoubleQuote:"“",OpenCurlyQuote:"‘",operp:"⦹",oplus:"⊕",orarr:"↻",Or:"⩔",or:"∨",ord:"⩝",order:"ℴ",orderof:"ℴ",ordf:"ª",ordm:"º",origof:"⊶",oror:"⩖",orslope:"⩗",orv:"⩛",oS:"Ⓢ",Oscr:"𝒪",oscr:"ℴ",Oslash:"Ø",oslash:"ø",osol:"⊘",Otilde:"Õ",otilde:"õ",otimesas:"⨶",Otimes:"⨷",otimes:"⊗",Ouml:"Ö",ouml:"ö",ovbar:"⌽",OverBar:"‾",OverBrace:"⏞",OverBracket:"⎴",OverParenthesis:"⏜",para:"¶",parallel:"∥",par:"∥",parsim:"⫳",parsl:"⫽",part:"∂",PartialD:"∂",Pcy:"П",pcy:"п",percnt:"%",period:".",permil:"‰",perp:"⊥",pertenk:"‱",Pfr:"𝔓",pfr:"𝔭",Phi:"Φ",phi:"φ",phiv:"ϕ",phmmat:"ℳ",phone:"☎",Pi:"Π",pi:"π",pitchfork:"⋔",piv:"ϖ",planck:"ℏ",planckh:"ℎ",plankv:"ℏ",plusacir:"⨣",plusb:"⊞",pluscir:"⨢",plus:"+",plusdo:"∔",plusdu:"⨥",pluse:"⩲",PlusMinus:"±",plusmn:"±",plussim:"⨦",plustwo:"⨧",pm:"±",Poincareplane:"ℌ",pointint:"⨕",popf:"𝕡",Popf:"ℙ",pound:"£",prap:"⪷",Pr:"⪻",pr:"≺",prcue:"≼",precapprox:"⪷",prec:"≺",preccurlyeq:"≼",Precedes:"≺",PrecedesEqual:"⪯",PrecedesSlantEqual:"≼",PrecedesTilde:"≾",preceq:"⪯",precnapprox:"⪹",precneqq:"⪵",precnsim:"⋨",pre:"⪯",prE:"⪳",precsim:"≾",prime:"′",Prime:"″",primes:"ℙ",prnap:"⪹",prnE:"⪵",prnsim:"⋨",prod:"∏",Product:"∏",profalar:"⌮",profline:"⌒",profsurf:"⌓",prop:"∝",Proportional:"∝",Proportion:"∷",propto:"∝",prsim:"≾",prurel:"⊰",Pscr:"𝒫",pscr:"𝓅",Psi:"Ψ",psi:"ψ",puncsp:" ",Qfr:"𝔔",qfr:"𝔮",qint:"⨌",qopf:"𝕢",Qopf:"ℚ",qprime:"⁗",Qscr:"𝒬",qscr:"𝓆",quaternions:"ℍ",quatint:"⨖",quest:"?",questeq:"≟",quot:'"',QUOT:'"',rAarr:"⇛",race:"∽̱",Racute:"Ŕ",racute:"ŕ",radic:"√",raemptyv:"⦳",rang:"⟩",Rang:"⟫",rangd:"⦒",range:"⦥",rangle:"⟩",raquo:"»",rarrap:"⥵",rarrb:"⇥",rarrbfs:"⤠",rarrc:"⤳",rarr:"→",Rarr:"↠",rArr:"⇒",rarrfs:"⤞",rarrhk:"↪",rarrlp:"↬",rarrpl:"⥅",rarrsim:"⥴",Rarrtl:"⤖",rarrtl:"↣",rarrw:"↝",ratail:"⤚",rAtail:"⤜",ratio:"∶",rationals:"ℚ",rbarr:"⤍",rBarr:"⤏",RBarr:"⤐",rbbrk:"❳",rbrace:"}",rbrack:"]",rbrke:"⦌",rbrksld:"⦎",rbrkslu:"⦐",Rcaron:"Ř",rcaron:"ř",Rcedil:"Ŗ",rcedil:"ŗ",rceil:"⌉",rcub:"}",Rcy:"Р",rcy:"р",rdca:"⤷",rdldhar:"⥩",rdquo:"”",rdquor:"”",rdsh:"↳",real:"ℜ",realine:"ℛ",realpart:"ℜ",reals:"ℝ",Re:"ℜ",rect:"▭",reg:"®",REG:"®",ReverseElement:"∋",ReverseEquilibrium:"⇋",ReverseUpEquilibrium:"⥯",rfisht:"⥽",rfloor:"⌋",rfr:"𝔯",Rfr:"ℜ",rHar:"⥤",rhard:"⇁",rharu:"⇀",rharul:"⥬",Rho:"Ρ",rho:"ρ",rhov:"ϱ",RightAngleBracket:"⟩",RightArrowBar:"⇥",rightarrow:"→",RightArrow:"→",Rightarrow:"⇒",RightArrowLeftArrow:"⇄",rightarrowtail:"↣",RightCeiling:"⌉",RightDoubleBracket:"⟧",RightDownTeeVector:"⥝",RightDownVectorBar:"⥕",RightDownVector:"⇂",RightFloor:"⌋",rightharpoondown:"⇁",rightharpoonup:"⇀",rightleftarrows:"⇄",rightleftharpoons:"⇌",rightrightarrows:"⇉",rightsquigarrow:"↝",RightTeeArrow:"↦",RightTee:"⊢",RightTeeVector:"⥛",rightthreetimes:"⋌",RightTriangleBar:"⧐",RightTriangle:"⊳",RightTriangleEqual:"⊵",RightUpDownVector:"⥏",RightUpTeeVector:"⥜",RightUpVectorBar:"⥔",RightUpVector:"↾",RightVectorBar:"⥓",RightVector:"⇀",ring:"˚",risingdotseq:"≓",rlarr:"⇄",rlhar:"⇌",rlm:"",rmoustache:"⎱",rmoust:"⎱",rnmid:"⫮",roang:"⟭",roarr:"⇾",robrk:"⟧",ropar:"⦆",ropf:"𝕣",Ropf:"ℝ",roplus:"⨮",rotimes:"⨵",RoundImplies:"⥰",rpar:")",rpargt:"⦔",rppolint:"⨒",rrarr:"⇉",Rrightarrow:"⇛",rsaquo:"›",rscr:"𝓇",Rscr:"ℛ",rsh:"↱",Rsh:"↱",rsqb:"]",rsquo:"’",rsquor:"’",rthree:"⋌",rtimes:"⋊",rtri:"▹",rtrie:"⊵",rtrif:"▸",rtriltri:"⧎",RuleDelayed:"⧴",ruluhar:"⥨",rx:"℞",Sacute:"Ś",sacute:"ś",sbquo:"‚",scap:"⪸",Scaron:"Š",scaron:"š",Sc:"⪼",sc:"≻",sccue:"≽",sce:"⪰",scE:"⪴",Scedil:"Ş",scedil:"ş",Scirc:"Ŝ",scirc:"ŝ",scnap:"⪺",scnE:"⪶",scnsim:"⋩",scpolint:"⨓",scsim:"≿",Scy:"С",scy:"с",sdotb:"⊡",sdot:"⋅",sdote:"⩦",searhk:"⤥",searr:"↘",seArr:"⇘",searrow:"↘",sect:"§",semi:";",seswar:"⤩",setminus:"∖",setmn:"∖",sext:"✶",Sfr:"𝔖",sfr:"𝔰",sfrown:"⌢",sharp:"♯",SHCHcy:"Щ",shchcy:"щ",SHcy:"Ш",shcy:"ш",ShortDownArrow:"↓",ShortLeftArrow:"←",shortmid:"∣",shortparallel:"∥",ShortRightArrow:"→",ShortUpArrow:"↑",shy:"",Sigma:"Σ",sigma:"σ",sigmaf:"ς",sigmav:"ς",sim:"∼",simdot:"⩪",sime:"≃",simeq:"≃",simg:"⪞",simgE:"⪠",siml:"⪝",simlE:"⪟",simne:"≆",simplus:"⨤",simrarr:"⥲",slarr:"←",SmallCircle:"∘",smallsetminus:"∖",smashp:"⨳",smeparsl:"⧤",smid:"∣",smile:"⌣",smt:"⪪",smte:"⪬",smtes:"⪬︀",SOFTcy:"Ь",softcy:"ь",solbar:"⌿",solb:"⧄",sol:"/",Sopf:"𝕊",sopf:"𝕤",spades:"♠",spadesuit:"♠",spar:"∥",sqcap:"⊓",sqcaps:"⊓︀",sqcup:"⊔",sqcups:"⊔︀",Sqrt:"√",sqsub:"⊏",sqsube:"⊑",sqsubset:"⊏",sqsubseteq:"⊑",sqsup:"⊐",sqsupe:"⊒",sqsupset:"⊐",sqsupseteq:"⊒",square:"□",Square:"□",SquareIntersection:"⊓",SquareSubset:"⊏",SquareSubsetEqual:"⊑",SquareSuperset:"⊐",SquareSupersetEqual:"⊒",SquareUnion:"⊔",squarf:"▪",squ:"□",squf:"▪",srarr:"→",Sscr:"𝒮",sscr:"𝓈",ssetmn:"∖",ssmile:"⌣",sstarf:"⋆",Star:"⋆",star:"☆",starf:"★",straightepsilon:"ϵ",straightphi:"ϕ",strns:"¯",sub:"⊂",Sub:"⋐",subdot:"⪽",subE:"⫅",sube:"⊆",subedot:"⫃",submult:"⫁",subnE:"⫋",subne:"⊊",subplus:"⪿",subrarr:"⥹",subset:"⊂",Subset:"⋐",subseteq:"⊆",subseteqq:"⫅",SubsetEqual:"⊆",subsetneq:"⊊",subsetneqq:"⫋",subsim:"⫇",subsub:"⫕", -subsup:"⫓",succapprox:"⪸",succ:"≻",succcurlyeq:"≽",Succeeds:"≻",SucceedsEqual:"⪰",SucceedsSlantEqual:"≽",SucceedsTilde:"≿",succeq:"⪰",succnapprox:"⪺",succneqq:"⪶",succnsim:"⋩",succsim:"≿",SuchThat:"∋",sum:"∑",Sum:"∑",sung:"♪",sup1:"¹",sup2:"²",sup3:"³",sup:"⊃",Sup:"⋑",supdot:"⪾",supdsub:"⫘",supE:"⫆",supe:"⊇",supedot:"⫄",Superset:"⊃",SupersetEqual:"⊇",suphsol:"⟉",suphsub:"⫗",suplarr:"⥻",supmult:"⫂",supnE:"⫌",supne:"⊋",supplus:"⫀",supset:"⊃",Supset:"⋑",supseteq:"⊇",supseteqq:"⫆",supsetneq:"⊋",supsetneqq:"⫌",supsim:"⫈",supsub:"⫔",supsup:"⫖",swarhk:"⤦",swarr:"↙",swArr:"⇙",swarrow:"↙",swnwar:"⤪",szlig:"ß",Tab:" ",target:"⌖",Tau:"Τ",tau:"τ",tbrk:"⎴",Tcaron:"Ť",tcaron:"ť",Tcedil:"Ţ",tcedil:"ţ",Tcy:"Т",tcy:"т",tdot:"⃛",telrec:"⌕",Tfr:"𝔗",tfr:"𝔱",there4:"∴",therefore:"∴",Therefore:"∴",Theta:"Θ",theta:"θ",thetasym:"ϑ",thetav:"ϑ",thickapprox:"≈",thicksim:"∼",ThickSpace:" ",ThinSpace:" ",thinsp:" ",thkap:"≈",thksim:"∼",THORN:"Þ",thorn:"þ",tilde:"˜",Tilde:"∼",TildeEqual:"≃",TildeFullEqual:"≅",TildeTilde:"≈",timesbar:"⨱",timesb:"⊠",times:"×",timesd:"⨰",tint:"∭",toea:"⤨",topbot:"⌶",topcir:"⫱",top:"⊤",Topf:"𝕋",topf:"𝕥",topfork:"⫚",tosa:"⤩",tprime:"‴",trade:"™",TRADE:"™",triangle:"▵",triangledown:"▿",triangleleft:"◃",trianglelefteq:"⊴",triangleq:"≜",triangleright:"▹",trianglerighteq:"⊵",tridot:"◬",trie:"≜",triminus:"⨺",TripleDot:"⃛",triplus:"⨹",trisb:"⧍",tritime:"⨻",trpezium:"⏢",Tscr:"𝒯",tscr:"𝓉",TScy:"Ц",tscy:"ц",TSHcy:"Ћ",tshcy:"ћ",Tstrok:"Ŧ",tstrok:"ŧ",twixt:"≬",twoheadleftarrow:"↞",twoheadrightarrow:"↠",Uacute:"Ú",uacute:"ú",uarr:"↑",Uarr:"↟",uArr:"⇑",Uarrocir:"⥉",Ubrcy:"Ў",ubrcy:"ў",Ubreve:"Ŭ",ubreve:"ŭ",Ucirc:"Û",ucirc:"û",Ucy:"У",ucy:"у",udarr:"⇅",Udblac:"Ű",udblac:"ű",udhar:"⥮",ufisht:"⥾",Ufr:"𝔘",ufr:"𝔲",Ugrave:"Ù",ugrave:"ù",uHar:"⥣",uharl:"↿",uharr:"↾",uhblk:"▀",ulcorn:"⌜",ulcorner:"⌜",ulcrop:"⌏",ultri:"◸",Umacr:"Ū",umacr:"ū",uml:"¨",UnderBar:"_",UnderBrace:"⏟",UnderBracket:"⎵",UnderParenthesis:"⏝",Union:"⋃",UnionPlus:"⊎",Uogon:"Ų",uogon:"ų",Uopf:"𝕌",uopf:"𝕦",UpArrowBar:"⤒",uparrow:"↑",UpArrow:"↑",Uparrow:"⇑",UpArrowDownArrow:"⇅",updownarrow:"↕",UpDownArrow:"↕",Updownarrow:"⇕",UpEquilibrium:"⥮",upharpoonleft:"↿",upharpoonright:"↾",uplus:"⊎",UpperLeftArrow:"↖",UpperRightArrow:"↗",upsi:"υ",Upsi:"ϒ",upsih:"ϒ",Upsilon:"Υ",upsilon:"υ",UpTeeArrow:"↥",UpTee:"⊥",upuparrows:"⇈",urcorn:"⌝",urcorner:"⌝",urcrop:"⌎",Uring:"Ů",uring:"ů",urtri:"◹",Uscr:"𝒰",uscr:"𝓊",utdot:"⋰",Utilde:"Ũ",utilde:"ũ",utri:"▵",utrif:"▴",uuarr:"⇈",Uuml:"Ü",uuml:"ü",uwangle:"⦧",vangrt:"⦜",varepsilon:"ϵ",varkappa:"ϰ",varnothing:"∅",varphi:"ϕ",varpi:"ϖ",varpropto:"∝",varr:"↕",vArr:"⇕",varrho:"ϱ",varsigma:"ς",varsubsetneq:"⊊︀",varsubsetneqq:"⫋︀",varsupsetneq:"⊋︀",varsupsetneqq:"⫌︀",vartheta:"ϑ",vartriangleleft:"⊲",vartriangleright:"⊳",vBar:"⫨",Vbar:"⫫",vBarv:"⫩",Vcy:"В",vcy:"в",vdash:"⊢",vDash:"⊨",Vdash:"⊩",VDash:"⊫",Vdashl:"⫦",veebar:"⊻",vee:"∨",Vee:"⋁",veeeq:"≚",vellip:"⋮",verbar:"|",Verbar:"‖",vert:"|",Vert:"‖",VerticalBar:"∣",VerticalLine:"|",VerticalSeparator:"❘",VerticalTilde:"≀",VeryThinSpace:" ",Vfr:"𝔙",vfr:"𝔳",vltri:"⊲",vnsub:"⊂⃒",vnsup:"⊃⃒",Vopf:"𝕍",vopf:"𝕧",vprop:"∝",vrtri:"⊳",Vscr:"𝒱",vscr:"𝓋",vsubnE:"⫋︀",vsubne:"⊊︀",vsupnE:"⫌︀",vsupne:"⊋︀",Vvdash:"⊪",vzigzag:"⦚",Wcirc:"Ŵ",wcirc:"ŵ",wedbar:"⩟",wedge:"∧",Wedge:"⋀",wedgeq:"≙",weierp:"℘",Wfr:"𝔚",wfr:"𝔴",Wopf:"𝕎",wopf:"𝕨",wp:"℘",wr:"≀",wreath:"≀",Wscr:"𝒲",wscr:"𝓌",xcap:"⋂",xcirc:"◯",xcup:"⋃",xdtri:"▽",Xfr:"𝔛",xfr:"𝔵",xharr:"⟷",xhArr:"⟺",Xi:"Ξ",xi:"ξ",xlarr:"⟵",xlArr:"⟸",xmap:"⟼",xnis:"⋻",xodot:"⨀",Xopf:"𝕏",xopf:"𝕩",xoplus:"⨁",xotime:"⨂",xrarr:"⟶",xrArr:"⟹",Xscr:"𝒳",xscr:"𝓍",xsqcup:"⨆",xuplus:"⨄",xutri:"△",xvee:"⋁",xwedge:"⋀",Yacute:"Ý",yacute:"ý",YAcy:"Я",yacy:"я",Ycirc:"Ŷ",ycirc:"ŷ",Ycy:"Ы",ycy:"ы",yen:"¥",Yfr:"𝔜",yfr:"𝔶",YIcy:"Ї",yicy:"ї",Yopf:"𝕐",yopf:"𝕪",Yscr:"𝒴",yscr:"𝓎",YUcy:"Ю",yucy:"ю",yuml:"ÿ",Yuml:"Ÿ",Zacute:"Ź",zacute:"ź",Zcaron:"Ž",zcaron:"ž",Zcy:"З",zcy:"з",Zdot:"Ż",zdot:"ż",zeetrf:"ℨ",ZeroWidthSpace:"",Zeta:"Ζ",zeta:"ζ",zfr:"𝔷",Zfr:"ℨ",ZHcy:"Ж",zhcy:"ж",zigrarr:"⇝",zopf:"𝕫",Zopf:"ℤ",Zscr:"𝒵",zscr:"𝓏",zwj:"",zwnj:""}},function(t,e){t.exports={Aacute:"Á",aacute:"á",Acirc:"Â",acirc:"â",acute:"´",AElig:"Æ",aelig:"æ",Agrave:"À",agrave:"à",amp:"&",AMP:"&",Aring:"Å",aring:"å",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",brvbar:"¦",Ccedil:"Ç",ccedil:"ç",cedil:"¸",cent:"¢",copy:"©",COPY:"©",curren:"¤",deg:"°",divide:"÷",Eacute:"É",eacute:"é",Ecirc:"Ê",ecirc:"ê",Egrave:"È",egrave:"è",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",frac12:"½",frac14:"¼",frac34:"¾",gt:">",GT:">",Iacute:"Í",iacute:"í",Icirc:"Î",icirc:"î",iexcl:"¡",Igrave:"Ì",igrave:"ì",iquest:"¿",Iuml:"Ï",iuml:"ï",laquo:"«",lt:"<",LT:"<",macr:"¯",micro:"µ",middot:"·",nbsp:" ",not:"¬",Ntilde:"Ñ",ntilde:"ñ",Oacute:"Ó",oacute:"ó",Ocirc:"Ô",ocirc:"ô",Ograve:"Ò",ograve:"ò",ordf:"ª",ordm:"º",Oslash:"Ø",oslash:"ø",Otilde:"Õ",otilde:"õ",Ouml:"Ö",ouml:"ö",para:"¶",plusmn:"±",pound:"£",quot:'"',QUOT:'"',raquo:"»",reg:"®",REG:"®",sect:"§",shy:"",sup1:"¹",sup2:"²",sup3:"³",szlig:"ß",THORN:"Þ",thorn:"þ",times:"×",Uacute:"Ú",uacute:"ú",Ucirc:"Û",ucirc:"û",Ugrave:"Ù",ugrave:"ù",uml:"¨",Uuml:"Ü",uuml:"ü",Yacute:"Ý",yacute:"ý",yen:"¥",yuml:"ÿ"}},function(t,e){t.exports={amp:"&",apos:"'",gt:">",lt:"<",quot:'"'}},function(t,e,r){function n(t,e,r){"object"==typeof t?(r=e,e=t,t=null):"function"==typeof e&&(r=e,e=c),this._callback=t,this._options=e||c,this._elementCB=r,this.dom=[],this._done=!1,this._tagStack=[],this._parser=this._parser||null}var i=r(23),o=/\s+/g,s=r(24),a=r(25),c={normalizeWhitespace:!1,withStartIndices:!1};n.prototype.onparserinit=function(t){this._parser=t},n.prototype.onreset=function(){n.call(this,this._callback,this._options,this._elementCB)},n.prototype.onend=function(){this._done||(this._done=!0,this._parser=null,this._handleCallback(null))},n.prototype._handleCallback=n.prototype.onerror=function(t){if("function"==typeof this._callback)this._callback(t,this.dom);else if(t)throw t},n.prototype.onclosetag=function(){var t=this._tagStack.pop();this._elementCB&&this._elementCB(t)},n.prototype._addDomElement=function(t){var e=this._tagStack[this._tagStack.length-1],r=e?e.children:this.dom,n=r[r.length-1];t.next=null,this._options.withStartIndices&&(t.startIndex=this._parser.startIndex),this._options.withDomLvl1&&(t.__proto__="tag"===t.type?a:s),n?(t.prev=n,n.next=t):t.prev=null,r.push(t),t.parent=e||null},n.prototype.onopentag=function(t,e){var r={type:"script"===t?i.Script:"style"===t?i.Style:i.Tag,name:t,attribs:e,children:[]};this._addDomElement(r),this._tagStack.push(r)},n.prototype.ontext=function(t){var e,r=this._options.normalizeWhitespace||this._options.ignoreWhitespace;!this._tagStack.length&&this.dom.length&&(e=this.dom[this.dom.length-1]).type===i.Text?r?e.data=(e.data+t).replace(o," "):e.data+=t:this._tagStack.length&&(e=this._tagStack[this._tagStack.length-1])&&(e=e.children[e.children.length-1])&&e.type===i.Text?r?e.data=(e.data+t).replace(o," "):e.data+=t:(r&&(t=t.replace(o," ")),this._addDomElement({data:t,type:i.Text}))},n.prototype.oncomment=function(t){var e=this._tagStack[this._tagStack.length-1];if(e&&e.type===i.Comment)return void(e.data+=t);var r={data:t,type:i.Comment};this._addDomElement(r),this._tagStack.push(r)},n.prototype.oncdatastart=function(){var t={children:[{data:"",type:i.Text}],type:i.CDATA};this._addDomElement(t),this._tagStack.push(t)},n.prototype.oncommentend=n.prototype.oncdataend=function(){this._tagStack.pop()},n.prototype.onprocessinginstruction=function(t,e){this._addDomElement({name:t,data:e,type:i.Directive})},t.exports=n},function(t,e){t.exports={Text:"text",Directive:"directive",Comment:"comment",Script:"script",Style:"style",Tag:"tag",CDATA:"cdata",Doctype:"doctype",isTag:function(t){return"tag"===t.type||"script"===t.type||"style"===t.type}}},function(t,e){var r=t.exports={get firstChild(){var t=this.children;return t&&t[0]||null},get lastChild(){var t=this.children;return t&&t[t.length-1]||null},get nodeType(){return i[this.type]||i.element}},n={tagName:"name",childNodes:"children",parentNode:"parent",previousSibling:"prev",nextSibling:"next",nodeValue:"data"},i={element:1,text:3,cdata:4,comment:8};Object.keys(n).forEach(function(t){var e=n[t];Object.defineProperty(r,t,{get:function(){return this[e]||null},set:function(t){return this[e]=t,t}})})},function(t,e,r){var n=r(24),i=t.exports=Object.create(n),o={tagName:"name"};Object.keys(o).forEach(function(t){var e=o[t];Object.defineProperty(i,t,{get:function(){return this[e]||null},set:function(t){return this[e]=t,t}})})},function(t,e,r){function n(t,e){this.init(t,e)}function i(t,e){return l.getElementsByTagName(t,e,!0)}function o(t,e){return l.getElementsByTagName(t,e,!0,1)[0]}function s(t,e,r){return l.getText(l.getElementsByTagName(t,e,r,1)).trim()}function a(t,e,r,n,i){var o=s(r,n,i);o&&(t[e]=o)}var c=r(14),u=c.DomHandler,l=c.DomUtils;r(2).inherits(n,u),n.prototype.init=u;var h=function(t){return"rss"===t||"feed"===t||"rdf:RDF"===t};n.prototype.onend=function(){var t,e,r={},n=o(h,this.dom);n&&("feed"===n.name?(e=n.children,r.type="atom",a(r,"id","id",e),a(r,"title","title",e),(t=o("link",e))&&(t=t.attribs)&&(t=t.href)&&(r.link=t),a(r,"description","subtitle",e),(t=s("updated",e))&&(r.updated=new Date(t)),a(r,"author","email",e,!0),r.items=i("entry",e).map(function(t){var e,r={};return t=t.children,a(r,"id","id",t),a(r,"title","title",t),(e=o("link",t))&&(e=e.attribs)&&(e=e.href)&&(r.link=e),(e=s("summary",t)||s("content",t))&&(r.description=e),(e=s("updated",t))&&(r.pubDate=new Date(e)),r})):(e=o("channel",n.children).children,r.type=n.name.substr(0,3),r.id="",a(r,"title","title",e),a(r,"link","link",e),a(r,"description","description",e),(t=s("lastBuildDate",e))&&(r.updated=new Date(t)),a(r,"author","managingEditor",e,!0),r.items=i("item",n.children).map(function(t){var e,r={};return t=t.children,a(r,"id","guid",t),a(r,"title","title",t),a(r,"link","link",t),a(r,"description","description",t),(e=s("pubDate",t))&&(r.pubDate=new Date(e)),r}))),this.dom=r,u.prototype._handleCallback.call(this,n?null:Error("couldn't find root of feed"))},t.exports=n},function(t,e,r){function n(t){o.call(this,new i(this),t)}function i(t){this.scope=t}t.exports=n;var o=r(28);r(2).inherits(n,o),n.prototype.readable=!0;var s=r(14).EVENTS;Object.keys(s).forEach(function(t){if(0===s[t])i.prototype["on"+t]=function(){this.scope.emit(t)};else if(1===s[t])i.prototype["on"+t]=function(e){this.scope.emit(t,e)};else{if(2!==s[t])throw Error("wrong number of arguments!");i.prototype["on"+t]=function(e,r){this.scope.emit(t,e,r)}}})},function(t,e,r){function n(t,e){var r=this._parser=new i(t,e);o.call(this,{decodeStrings:!1}),this.once("finish",function(){r.end()})}t.exports=n;var i=r(15),o=r(29).Writable||r(50).Writable;r(2).inherits(n,o),o.prototype._write=function(t,e,r){this._parser.write(t),r()}},function(t,e,r){function n(){i.call(this)}t.exports=n;var i=r(1).EventEmitter,o=r(30);o(n,i),n.Readable=r(31),n.Writable=r(46),n.Duplex=r(47),n.Transform=r(48),n.PassThrough=r(49),n.Stream=n,n.prototype.pipe=function(t,e){function r(e){t.writable&&!1===t.write(e)&&u.pause&&u.pause()}function n(){u.readable&&u.resume&&u.resume()}function o(){l||(l=!0,t.end())}function s(){l||(l=!0,"function"==typeof t.destroy&&t.destroy())}function a(t){if(c(),0===i.listenerCount(this,"error"))throw t}function c(){u.removeListener("data",r),t.removeListener("drain",n),u.removeListener("end",o),u.removeListener("close",s),u.removeListener("error",a),t.removeListener("error",a),u.removeListener("end",c),u.removeListener("close",c),t.removeListener("close",c)}var u=this;u.on("data",r),t.on("drain",n),t._isStdio||e&&e.end===!1||(u.on("end",o),u.on("close",s));var l=!1;return u.on("error",a),t.on("error",a),u.on("end",c),u.on("close",c),t.on("close",c),t.emit("pipe",u),t}},function(t,e){"function"==typeof Object.create?t.exports=function(t,e){t.super_=e,t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(t,e){t.super_=e;var r=function(){};r.prototype=e.prototype,t.prototype=new r,t.prototype.constructor=t}},function(t,e,r){(function(n){e=t.exports=r(32),e.Stream=r(29),e.Readable=e,e.Writable=r(42),e.Duplex=r(41),e.Transform=r(44),e.PassThrough=r(45),n.browser||"disable"!==n.env.READABLE_STREAM||(t.exports=r(29))}).call(e,r(3))},function(t,e,r){(function(e){function n(t,e){var n=r(41);t=t||{};var i=t.highWaterMark,o=t.objectMode?16:16384;this.highWaterMark=i||0===i?i:o,this.highWaterMark=~~this.highWaterMark,this.buffer=[],this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.objectMode=!!t.objectMode,e instanceof n&&(this.objectMode=this.objectMode||!!t.readableObjectMode),this.defaultEncoding=t.defaultEncoding||"utf8",this.ranOut=!1,this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,t.encoding&&(L||(L=r(43).StringDecoder),this.decoder=new L(t.encoding),this.encoding=t.encoding)}function i(t){r(41);return this instanceof i?(this._readableState=new n(t,this),this.readable=!0,void T.call(this)):new i(t)}function o(t,e,r,n,i){var o=u(e,r);if(o)t.emit("error",o);else if(A.isNullOrUndefined(r))e.reading=!1,e.ended||l(t,e);else if(e.objectMode||r&&r.length>0)if(e.ended&&!i){var a=new Error("stream.push() after EOF");t.emit("error",a)}else if(e.endEmitted&&i){var a=new Error("stream.unshift() after end event");t.emit("error",a)}else!e.decoder||i||n||(r=e.decoder.write(r)),i||(e.reading=!1),e.flowing&&0===e.length&&!e.sync?(t.emit("data",r),t.read(0)):(e.length+=e.objectMode?1:r.length,i?e.buffer.unshift(r):e.buffer.push(r),e.needReadable&&h(t)),p(t,e);else i||(e.reading=!1);return s(e)}function s(t){return!t.ended&&(t.needReadable||t.length<t.highWaterMark||0===t.length)}function a(t){if(t>=C)t=C;else{t--;for(var e=1;32>e;e<<=1)t|=t>>e;t++}return t}function c(t,e){return 0===e.length&&e.ended?0:e.objectMode?0===t?0:1:isNaN(t)||A.isNull(t)?e.flowing&&e.buffer.length?e.buffer[0].length:e.length:0>=t?0:(t>e.highWaterMark&&(e.highWaterMark=a(t)),t>e.length?e.ended?e.length:(e.needReadable=!0,0):t)}function u(t,e){var r=null;return A.isBuffer(e)||A.isString(e)||A.isNullOrUndefined(e)||t.objectMode||(r=new TypeError("Invalid non-string/buffer chunk")),r}function l(t,e){if(e.decoder&&!e.ended){var r=e.decoder.end();r&&r.length&&(e.buffer.push(r),e.length+=e.objectMode?1:r.length)}e.ended=!0,h(t)}function h(t){var r=t._readableState;r.needReadable=!1,r.emittedReadable||(O("emitReadable",r.flowing),r.emittedReadable=!0,r.sync?e.nextTick(function(){f(t)}):f(t))}function f(t){O("emit readable"),t.emit("readable"),b(t)}function p(t,r){r.readingMore||(r.readingMore=!0,e.nextTick(function(){d(t,r)}))}function d(t,e){for(var r=e.length;!e.reading&&!e.flowing&&!e.ended&&e.length<e.highWaterMark&&(O("maybeReadMore read 0"),t.read(0),r!==e.length);)r=e.length;e.readingMore=!1}function g(t){return function(){var e=t._readableState;O("pipeOnDrain",e.awaitDrain),e.awaitDrain&&e.awaitDrain--,0===e.awaitDrain&&k.listenerCount(t,"data")&&(e.flowing=!0,b(t))}}function _(t,r){r.resumeScheduled||(r.resumeScheduled=!0,e.nextTick(function(){m(t,r)}))}function m(t,e){e.resumeScheduled=!1,t.emit("resume"),b(t),e.flowing&&!e.reading&&t.read(0)}function b(t){var e=t._readableState;if(O("flow",e.flowing),e.flowing)do var r=t.read();while(null!==r&&e.flowing)}function y(t,e){var r,n=e.buffer,i=e.length,o=!!e.decoder,s=!!e.objectMode;if(0===n.length)return null;if(0===i)r=null;else if(s)r=n.shift();else if(!t||t>=i)r=o?n.join(""):E.concat(n,i),n.length=0;else if(t<n[0].length){var a=n[0];r=a.slice(0,t),n[0]=a.slice(t)}else if(t===n[0].length)r=n.shift();else{r=o?"":new E(t);for(var c=0,u=0,l=n.length;l>u&&t>c;u++){var a=n[0],h=Math.min(t-c,a.length);o?r+=a.slice(0,h):a.copy(r,c,0,h),h<a.length?n[0]=a.slice(h):n.shift(),c+=h}}return r}function v(t){var r=t._readableState;if(r.length>0)throw new Error("endReadable called on non-empty stream");r.endEmitted||(r.ended=!0,e.nextTick(function(){r.endEmitted||0!==r.length||(r.endEmitted=!0,t.readable=!1,t.emit("end"))}))}function w(t,e){for(var r=0,n=t.length;n>r;r++)e(t[r],r)}function S(t,e){for(var r=0,n=t.length;n>r;r++)if(t[r]===e)return r;return-1}t.exports=i;var x=r(33),E=r(34).Buffer;i.ReadableState=n;var k=r(1).EventEmitter;k.listenerCount||(k.listenerCount=function(t,e){return t.listeners(e).length});var T=r(29),A=r(38);A.inherits=r(39);var L,O=r(40);O=O&&O.debuglog?O.debuglog("stream"):function(){},A.inherits(i,T),i.prototype.push=function(t,e){var r=this._readableState;return A.isString(t)&&!r.objectMode&&(e=e||r.defaultEncoding,e!==r.encoding&&(t=new E(t,e),e="")),o(this,r,t,e,!1)},i.prototype.unshift=function(t){var e=this._readableState;return o(this,e,t,"",!0)},i.prototype.setEncoding=function(t){return L||(L=r(43).StringDecoder),this._readableState.decoder=new L(t),this._readableState.encoding=t,this};var C=8388608;i.prototype.read=function(t){O("read",t);var e=this._readableState,r=t;if((!A.isNumber(t)||t>0)&&(e.emittedReadable=!1),0===t&&e.needReadable&&(e.length>=e.highWaterMark||e.ended))return O("read: emitReadable",e.length,e.ended),0===e.length&&e.ended?v(this):h(this),null;if(t=c(t,e),0===t&&e.ended)return 0===e.length&&v(this),null;var n=e.needReadable;O("need readable",n),(0===e.length||e.length-t<e.highWaterMark)&&(n=!0,O("length less than watermark",n)),(e.ended||e.reading)&&(n=!1,O("reading or ended",n)),n&&(O("do read"),e.reading=!0,e.sync=!0,0===e.length&&(e.needReadable=!0),this._read(e.highWaterMark),e.sync=!1),n&&!e.reading&&(t=c(r,e));var i;return i=t>0?y(t,e):null,A.isNull(i)&&(e.needReadable=!0,t=0),e.length-=t,0!==e.length||e.ended||(e.needReadable=!0),r!==t&&e.ended&&0===e.length&&v(this),A.isNull(i)||this.emit("data",i),i},i.prototype._read=function(t){this.emit("error",new Error("not implemented"))},i.prototype.pipe=function(t,r){function n(t){O("onunpipe"),t===h&&o()}function i(){O("onend"),t.end()}function o(){O("cleanup"),t.removeListener("close",c),t.removeListener("finish",u),t.removeListener("drain",_),t.removeListener("error",a),t.removeListener("unpipe",n),h.removeListener("end",i),h.removeListener("end",o),h.removeListener("data",s),!f.awaitDrain||t._writableState&&!t._writableState.needDrain||_()}function s(e){O("ondata");var r=t.write(e);!1===r&&(O("false write response, pause",h._readableState.awaitDrain),h._readableState.awaitDrain++,h.pause())}function a(e){O("onerror",e),l(),t.removeListener("error",a),0===k.listenerCount(t,"error")&&t.emit("error",e)}function c(){t.removeListener("finish",u),l()}function u(){O("onfinish"),t.removeListener("close",c),l()}function l(){O("unpipe"),h.unpipe(t)}var h=this,f=this._readableState;switch(f.pipesCount){case 0:f.pipes=t;break;case 1:f.pipes=[f.pipes,t];break;default:f.pipes.push(t)}f.pipesCount+=1,O("pipe count=%d opts=%j",f.pipesCount,r);var p=(!r||r.end!==!1)&&t!==e.stdout&&t!==e.stderr,d=p?i:o;f.endEmitted?e.nextTick(d):h.once("end",d),t.on("unpipe",n);var _=g(h);return t.on("drain",_),h.on("data",s),t._events&&t._events.error?x(t._events.error)?t._events.error.unshift(a):t._events.error=[a,t._events.error]:t.on("error",a),t.once("close",c),t.once("finish",u),t.emit("pipe",h),f.flowing||(O("pipe resume"),h.resume()),t},i.prototype.unpipe=function(t){var e=this._readableState;if(0===e.pipesCount)return this;if(1===e.pipesCount)return t&&t!==e.pipes?this:(t||(t=e.pipes),e.pipes=null,e.pipesCount=0,e.flowing=!1,t&&t.emit("unpipe",this),this);if(!t){var r=e.pipes,n=e.pipesCount;e.pipes=null,e.pipesCount=0,e.flowing=!1;for(var i=0;n>i;i++)r[i].emit("unpipe",this);return this}var i=S(e.pipes,t);return-1===i?this:(e.pipes.splice(i,1),e.pipesCount-=1,1===e.pipesCount&&(e.pipes=e.pipes[0]),t.emit("unpipe",this),this)},i.prototype.on=function(t,r){var n=T.prototype.on.call(this,t,r);if("data"===t&&!1!==this._readableState.flowing&&this.resume(),"readable"===t&&this.readable){var i=this._readableState;if(!i.readableListening)if(i.readableListening=!0,i.emittedReadable=!1,i.needReadable=!0,i.reading)i.length&&h(this,i);else{var o=this;e.nextTick(function(){O("readable nexttick read 0"),o.read(0)})}}return n},i.prototype.addListener=i.prototype.on,i.prototype.resume=function(){var t=this._readableState;return t.flowing||(O("resume"),t.flowing=!0,t.reading||(O("resume read 0"),this.read(0)),_(this,t)),this},i.prototype.pause=function(){return O("call pause flowing=%j",this._readableState.flowing),!1!==this._readableState.flowing&&(O("pause"),this._readableState.flowing=!1,this.emit("pause")),this},i.prototype.wrap=function(t){var e=this._readableState,r=!1,n=this;t.on("end",function(){if(O("wrapped end"),e.decoder&&!e.ended){var t=e.decoder.end();t&&t.length&&n.push(t)}n.push(null)}),t.on("data",function(i){if(O("wrapped data"),e.decoder&&(i=e.decoder.write(i)),i&&(e.objectMode||i.length)){var o=n.push(i);o||(r=!0,t.pause())}});for(var i in t)A.isFunction(t[i])&&A.isUndefined(this[i])&&(this[i]=function(e){return function(){return t[e].apply(t,arguments)}}(i));var o=["error","close","destroy","pause","resume"];return w(o,function(e){t.on(e,n.emit.bind(n,e))}),n._read=function(e){O("wrapped _read",e),r&&(r=!1,t.resume())},n},i._fromList=y}).call(e,r(3))},function(t,e){t.exports=Array.isArray||function(t){return"[object Array]"==Object.prototype.toString.call(t)}},function(t,e,r){(function(t,n){/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> - * @license MIT - */ -"use strict";function i(){function t(){}try{var e=new Uint8Array(1);return e.foo=function(){return 42},e.constructor=t,42===e.foo()&&e.constructor===t&&"function"==typeof e.subarray&&0===e.subarray(1,1).byteLength}catch(r){return!1}}function o(){return t.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function t(e){return this instanceof t?(t.TYPED_ARRAY_SUPPORT||(this.length=0,this.parent=void 0),"number"==typeof e?s(this,e):"string"==typeof e?a(this,e,arguments.length>1?arguments[1]:"utf8"):c(this,e)):arguments.length>1?new t(e,arguments[1]):new t(e)}function s(e,r){if(e=g(e,0>r?0:0|_(r)),!t.TYPED_ARRAY_SUPPORT)for(var n=0;r>n;n++)e[n]=0;return e}function a(t,e,r){"string"==typeof r&&""!==r||(r="utf8");var n=0|b(e,r);return t=g(t,n),t.write(e,r),t}function c(e,r){if(t.isBuffer(r))return u(e,r);if(X(r))return l(e,r);if(null==r)throw new TypeError("must start with number, buffer, array or string");if("undefined"!=typeof ArrayBuffer){if(r.buffer instanceof ArrayBuffer)return h(e,r);if(r instanceof ArrayBuffer)return f(e,r)}return r.length?p(e,r):d(e,r)}function u(t,e){var r=0|_(e.length);return t=g(t,r),e.copy(t,0,0,r),t}function l(t,e){var r=0|_(e.length);t=g(t,r);for(var n=0;r>n;n+=1)t[n]=255&e[n];return t}function h(t,e){var r=0|_(e.length);t=g(t,r);for(var n=0;r>n;n+=1)t[n]=255&e[n];return t}function f(e,r){return t.TYPED_ARRAY_SUPPORT?(r.byteLength,e=t._augment(new Uint8Array(r))):e=h(e,new Uint8Array(r)),e}function p(t,e){var r=0|_(e.length);t=g(t,r);for(var n=0;r>n;n+=1)t[n]=255&e[n];return t}function d(t,e){var r,n=0;"Buffer"===e.type&&X(e.data)&&(r=e.data,n=0|_(r.length)),t=g(t,n);for(var i=0;n>i;i+=1)t[i]=255&r[i];return t}function g(e,r){t.TYPED_ARRAY_SUPPORT?(e=t._augment(new Uint8Array(r)),e.__proto__=t.prototype):(e.length=r,e._isBuffer=!0);var n=0!==r&&r<=t.poolSize>>>1;return n&&(e.parent=Q),e}function _(t){if(t>=o())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+o().toString(16)+" bytes");return 0|t}function m(e,r){if(!(this instanceof m))return new m(e,r);var n=new t(e,r);return delete n.parent,n}function b(t,e){"string"!=typeof t&&(t=""+t);var r=t.length;if(0===r)return 0;for(var n=!1;;)switch(e){case"ascii":case"binary":case"raw":case"raws":return r;case"utf8":case"utf-8":return H(t).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return Y(t).length;default:if(n)return H(t).length;e=(""+e).toLowerCase(),n=!0}}function y(t,e,r){var n=!1;if(e=0|e,r=void 0===r||r===1/0?this.length:0|r,t||(t="utf8"),0>e&&(e=0),r>this.length&&(r=this.length),e>=r)return"";for(;;)switch(t){case"hex":return I(this,e,r);case"utf8":case"utf-8":return A(this,e,r);case"ascii":return O(this,e,r);case"binary":return C(this,e,r);case"base64":return T(this,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return B(this,e,r);default:if(n)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),n=!0}}function v(t,e,r,n){r=Number(r)||0;var i=t.length-r;n?(n=Number(n),n>i&&(n=i)):n=i;var o=e.length;if(o%2!==0)throw new Error("Invalid hex string");n>o/2&&(n=o/2);for(var s=0;n>s;s++){var a=parseInt(e.substr(2*s,2),16);if(isNaN(a))throw new Error("Invalid hex string");t[r+s]=a}return s}function w(t,e,r,n){return W(H(e,t.length-r),t,r,n)}function S(t,e,r,n){return W(V(e),t,r,n)}function x(t,e,r,n){return S(t,e,r,n)}function E(t,e,r,n){return W(Y(e),t,r,n)}function k(t,e,r,n){return W(G(e,t.length-r),t,r,n)}function T(t,e,r){return 0===e&&r===t.length?K.fromByteArray(t):K.fromByteArray(t.slice(e,r))}function A(t,e,r){r=Math.min(t.length,r);for(var n=[],i=e;r>i;){var o=t[i],s=null,a=o>239?4:o>223?3:o>191?2:1;if(r>=i+a){var c,u,l,h;switch(a){case 1:128>o&&(s=o);break;case 2:c=t[i+1],128===(192&c)&&(h=(31&o)<<6|63&c,h>127&&(s=h));break;case 3:c=t[i+1],u=t[i+2],128===(192&c)&&128===(192&u)&&(h=(15&o)<<12|(63&c)<<6|63&u,h>2047&&(55296>h||h>57343)&&(s=h));break;case 4:c=t[i+1],u=t[i+2],l=t[i+3],128===(192&c)&&128===(192&u)&&128===(192&l)&&(h=(15&o)<<18|(63&c)<<12|(63&u)<<6|63&l,h>65535&&1114112>h&&(s=h))}}null===s?(s=65533,a=1):s>65535&&(s-=65536,n.push(s>>>10&1023|55296),s=56320|1023&s),n.push(s),i+=a}return L(n)}function L(t){var e=t.length;if(Z>=e)return String.fromCharCode.apply(String,t);for(var r="",n=0;e>n;)r+=String.fromCharCode.apply(String,t.slice(n,n+=Z));return r}function O(t,e,r){var n="";r=Math.min(t.length,r);for(var i=e;r>i;i++)n+=String.fromCharCode(127&t[i]);return n}function C(t,e,r){var n="";r=Math.min(t.length,r);for(var i=e;r>i;i++)n+=String.fromCharCode(t[i]);return n}function I(t,e,r){var n=t.length;(!e||0>e)&&(e=0),(!r||0>r||r>n)&&(r=n);for(var i="",o=e;r>o;o++)i+=z(t[o]);return i}function B(t,e,r){for(var n=t.slice(e,r),i="",o=0;o<n.length;o+=2)i+=String.fromCharCode(n[o]+256*n[o+1]);return i}function D(t,e,r){if(t%1!==0||0>t)throw new RangeError("offset is not uint");if(t+e>r)throw new RangeError("Trying to access beyond buffer length")}function N(e,r,n,i,o,s){if(!t.isBuffer(e))throw new TypeError("buffer must be a Buffer instance");if(r>o||s>r)throw new RangeError("value is out of bounds");if(n+i>e.length)throw new RangeError("index out of range")}function R(t,e,r,n){0>e&&(e=65535+e+1);for(var i=0,o=Math.min(t.length-r,2);o>i;i++)t[r+i]=(e&255<<8*(n?i:1-i))>>>8*(n?i:1-i)}function q(t,e,r,n){0>e&&(e=4294967295+e+1);for(var i=0,o=Math.min(t.length-r,4);o>i;i++)t[r+i]=e>>>8*(n?i:3-i)&255}function j(t,e,r,n,i,o){if(e>i||o>e)throw new RangeError("value is out of bounds");if(r+n>t.length)throw new RangeError("index out of range");if(0>r)throw new RangeError("index out of range")}function P(t,e,r,n,i){return i||j(t,e,r,4,3.4028234663852886e38,-3.4028234663852886e38),J.write(t,e,r,n,23,4),r+4}function U(t,e,r,n,i){return i||j(t,e,r,8,1.7976931348623157e308,-1.7976931348623157e308),J.write(t,e,r,n,52,8),r+8}function M(t){if(t=F(t).replace(tt,""),t.length<2)return"";for(;t.length%4!==0;)t+="=";return t}function F(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}function z(t){return 16>t?"0"+t.toString(16):t.toString(16)}function H(t,e){e=e||1/0;for(var r,n=t.length,i=null,o=[],s=0;n>s;s++){if(r=t.charCodeAt(s),r>55295&&57344>r){if(!i){if(r>56319){(e-=3)>-1&&o.push(239,191,189);continue}if(s+1===n){(e-=3)>-1&&o.push(239,191,189);continue}i=r;continue}if(56320>r){(e-=3)>-1&&o.push(239,191,189),i=r;continue}r=(i-55296<<10|r-56320)+65536}else i&&(e-=3)>-1&&o.push(239,191,189);if(i=null,128>r){if((e-=1)<0)break;o.push(r)}else if(2048>r){if((e-=2)<0)break;o.push(r>>6|192,63&r|128)}else if(65536>r){if((e-=3)<0)break;o.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(1114112>r))throw new Error("Invalid code point");if((e-=4)<0)break;o.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return o}function V(t){for(var e=[],r=0;r<t.length;r++)e.push(255&t.charCodeAt(r));return e}function G(t,e){for(var r,n,i,o=[],s=0;s<t.length&&!((e-=2)<0);s++)r=t.charCodeAt(s),n=r>>8,i=r%256,o.push(i),o.push(n);return o}function Y(t){return K.toByteArray(M(t))}function W(t,e,r,n){for(var i=0;n>i&&!(i+r>=e.length||i>=t.length);i++)e[i+r]=t[i];return i}var K=r(35),J=r(36),X=r(37);e.Buffer=t,e.SlowBuffer=m,e.INSPECT_MAX_BYTES=50,t.poolSize=8192;var Q={};t.TYPED_ARRAY_SUPPORT=void 0!==n.TYPED_ARRAY_SUPPORT?n.TYPED_ARRAY_SUPPORT:i(),t.TYPED_ARRAY_SUPPORT?(t.prototype.__proto__=Uint8Array.prototype,t.__proto__=Uint8Array):(t.prototype.length=void 0,t.prototype.parent=void 0),t.isBuffer=function(t){return!(null==t||!t._isBuffer)},t.compare=function(e,r){if(!t.isBuffer(e)||!t.isBuffer(r))throw new TypeError("Arguments must be Buffers");if(e===r)return 0;for(var n=e.length,i=r.length,o=0,s=Math.min(n,i);s>o&&e[o]===r[o];)++o;return o!==s&&(n=e[o],i=r[o]),i>n?-1:n>i?1:0},t.isEncoding=function(t){switch(String(t).toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"raw":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return!0;default:return!1}},t.concat=function(e,r){if(!X(e))throw new TypeError("list argument must be an Array of Buffers.");if(0===e.length)return new t(0);var n;if(void 0===r)for(r=0,n=0;n<e.length;n++)r+=e[n].length;var i=new t(r),o=0;for(n=0;n<e.length;n++){var s=e[n];s.copy(i,o),o+=s.length}return i},t.byteLength=b,t.prototype.toString=function(){var t=0|this.length;return 0===t?"":0===arguments.length?A(this,0,t):y.apply(this,arguments)},t.prototype.equals=function(e){if(!t.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e?!0:0===t.compare(this,e)},t.prototype.inspect=function(){var t="",r=e.INSPECT_MAX_BYTES;return this.length>0&&(t=this.toString("hex",0,r).match(/.{2}/g).join(" "),this.length>r&&(t+=" ... ")),"<Buffer "+t+">"},t.prototype.compare=function(e){if(!t.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e?0:t.compare(this,e)},t.prototype.indexOf=function(e,r){function n(t,e,r){for(var n=-1,i=0;r+i<t.length;i++)if(t[r+i]===e[-1===n?0:i-n]){if(-1===n&&(n=i),i-n+1===e.length)return r+n}else n=-1;return-1}if(r>2147483647?r=2147483647:-2147483648>r&&(r=-2147483648),r>>=0,0===this.length)return-1;if(r>=this.length)return-1;if(0>r&&(r=Math.max(this.length+r,0)),"string"==typeof e)return 0===e.length?-1:String.prototype.indexOf.call(this,e,r);if(t.isBuffer(e))return n(this,e,r);if("number"==typeof e)return t.TYPED_ARRAY_SUPPORT&&"function"===Uint8Array.prototype.indexOf?Uint8Array.prototype.indexOf.call(this,e,r):n(this,[e],r);throw new TypeError("val must be string, number or Buffer")},t.prototype.get=function(t){return console.log(".get() is deprecated. Access using array indexes instead."),this.readUInt8(t)},t.prototype.set=function(t,e){return console.log(".set() is deprecated. Access using array indexes instead."),this.writeUInt8(t,e)},t.prototype.write=function(t,e,r,n){if(void 0===e)n="utf8",r=this.length,e=0;else if(void 0===r&&"string"==typeof e)n=e,r=this.length,e=0;else if(isFinite(e))e=0|e,isFinite(r)?(r=0|r,void 0===n&&(n="utf8")):(n=r,r=void 0);else{var i=n;n=e,e=0|r,r=i}var o=this.length-e;if((void 0===r||r>o)&&(r=o),t.length>0&&(0>r||0>e)||e>this.length)throw new RangeError("attempt to write outside buffer bounds");n||(n="utf8");for(var s=!1;;)switch(n){case"hex":return v(this,t,e,r);case"utf8":case"utf-8":return w(this,t,e,r);case"ascii":return S(this,t,e,r);case"binary":return x(this,t,e,r);case"base64":return E(this,t,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return k(this,t,e,r);default:if(s)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),s=!0}},t.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var Z=4096;t.prototype.slice=function(e,r){var n=this.length;e=~~e,r=void 0===r?n:~~r,0>e?(e+=n,0>e&&(e=0)):e>n&&(e=n),0>r?(r+=n,0>r&&(r=0)):r>n&&(r=n),e>r&&(r=e);var i;if(t.TYPED_ARRAY_SUPPORT)i=t._augment(this.subarray(e,r));else{var o=r-e;i=new t(o,void 0);for(var s=0;o>s;s++)i[s]=this[s+e]}return i.length&&(i.parent=this.parent||this),i},t.prototype.readUIntLE=function(t,e,r){t=0|t,e=0|e,r||D(t,e,this.length);for(var n=this[t],i=1,o=0;++o<e&&(i*=256);)n+=this[t+o]*i;return n},t.prototype.readUIntBE=function(t,e,r){t=0|t,e=0|e,r||D(t,e,this.length);for(var n=this[t+--e],i=1;e>0&&(i*=256);)n+=this[t+--e]*i;return n},t.prototype.readUInt8=function(t,e){return e||D(t,1,this.length),this[t]},t.prototype.readUInt16LE=function(t,e){return e||D(t,2,this.length),this[t]|this[t+1]<<8},t.prototype.readUInt16BE=function(t,e){return e||D(t,2,this.length),this[t]<<8|this[t+1]},t.prototype.readUInt32LE=function(t,e){return e||D(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},t.prototype.readUInt32BE=function(t,e){return e||D(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},t.prototype.readIntLE=function(t,e,r){t=0|t,e=0|e,r||D(t,e,this.length);for(var n=this[t],i=1,o=0;++o<e&&(i*=256);)n+=this[t+o]*i;return i*=128,n>=i&&(n-=Math.pow(2,8*e)),n},t.prototype.readIntBE=function(t,e,r){t=0|t,e=0|e,r||D(t,e,this.length);for(var n=e,i=1,o=this[t+--n];n>0&&(i*=256);)o+=this[t+--n]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*e)),o},t.prototype.readInt8=function(t,e){return e||D(t,1,this.length),128&this[t]?-1*(255-this[t]+1):this[t]},t.prototype.readInt16LE=function(t,e){e||D(t,2,this.length);var r=this[t]|this[t+1]<<8;return 32768&r?4294901760|r:r},t.prototype.readInt16BE=function(t,e){e||D(t,2,this.length);var r=this[t+1]|this[t]<<8;return 32768&r?4294901760|r:r},t.prototype.readInt32LE=function(t,e){return e||D(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},t.prototype.readInt32BE=function(t,e){return e||D(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},t.prototype.readFloatLE=function(t,e){return e||D(t,4,this.length),J.read(this,t,!0,23,4)},t.prototype.readFloatBE=function(t,e){return e||D(t,4,this.length),J.read(this,t,!1,23,4)},t.prototype.readDoubleLE=function(t,e){return e||D(t,8,this.length),J.read(this,t,!0,52,8)},t.prototype.readDoubleBE=function(t,e){return e||D(t,8,this.length),J.read(this,t,!1,52,8)},t.prototype.writeUIntLE=function(t,e,r,n){t=+t,e=0|e,r=0|r,n||N(this,t,e,r,Math.pow(2,8*r),0);var i=1,o=0;for(this[e]=255&t;++o<r&&(i*=256);)this[e+o]=t/i&255;return e+r},t.prototype.writeUIntBE=function(t,e,r,n){t=+t,e=0|e,r=0|r,n||N(this,t,e,r,Math.pow(2,8*r),0);var i=r-1,o=1;for(this[e+i]=255&t;--i>=0&&(o*=256);)this[e+i]=t/o&255;return e+r},t.prototype.writeUInt8=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,1,255,0),t.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[r]=255&e,r+1},t.prototype.writeUInt16LE=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,2,65535,0),t.TYPED_ARRAY_SUPPORT?(this[r]=255&e,this[r+1]=e>>>8):R(this,e,r,!0),r+2},t.prototype.writeUInt16BE=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,2,65535,0),t.TYPED_ARRAY_SUPPORT?(this[r]=e>>>8,this[r+1]=255&e):R(this,e,r,!1),r+2},t.prototype.writeUInt32LE=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,4,4294967295,0),t.TYPED_ARRAY_SUPPORT?(this[r+3]=e>>>24,this[r+2]=e>>>16,this[r+1]=e>>>8,this[r]=255&e):q(this,e,r,!0),r+4},t.prototype.writeUInt32BE=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,4,4294967295,0),t.TYPED_ARRAY_SUPPORT?(this[r]=e>>>24,this[r+1]=e>>>16,this[r+2]=e>>>8,this[r+3]=255&e):q(this,e,r,!1),r+4},t.prototype.writeIntLE=function(t,e,r,n){if(t=+t,e=0|e,!n){var i=Math.pow(2,8*r-1);N(this,t,e,r,i-1,-i)}var o=0,s=1,a=0>t?1:0;for(this[e]=255&t;++o<r&&(s*=256);)this[e+o]=(t/s>>0)-a&255;return e+r},t.prototype.writeIntBE=function(t,e,r,n){if(t=+t,e=0|e,!n){var i=Math.pow(2,8*r-1);N(this,t,e,r,i-1,-i)}var o=r-1,s=1,a=0>t?1:0;for(this[e+o]=255&t;--o>=0&&(s*=256);)this[e+o]=(t/s>>0)-a&255;return e+r},t.prototype.writeInt8=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,1,127,-128),t.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),0>e&&(e=255+e+1),this[r]=255&e,r+1},t.prototype.writeInt16LE=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,2,32767,-32768),t.TYPED_ARRAY_SUPPORT?(this[r]=255&e,this[r+1]=e>>>8):R(this,e,r,!0),r+2},t.prototype.writeInt16BE=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,2,32767,-32768),t.TYPED_ARRAY_SUPPORT?(this[r]=e>>>8,this[r+1]=255&e):R(this,e,r,!1),r+2},t.prototype.writeInt32LE=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,4,2147483647,-2147483648),t.TYPED_ARRAY_SUPPORT?(this[r]=255&e,this[r+1]=e>>>8,this[r+2]=e>>>16,this[r+3]=e>>>24):q(this,e,r,!0),r+4},t.prototype.writeInt32BE=function(e,r,n){return e=+e,r=0|r,n||N(this,e,r,4,2147483647,-2147483648),0>e&&(e=4294967295+e+1),t.TYPED_ARRAY_SUPPORT?(this[r]=e>>>24,this[r+1]=e>>>16,this[r+2]=e>>>8,this[r+3]=255&e):q(this,e,r,!1),r+4},t.prototype.writeFloatLE=function(t,e,r){return P(this,t,e,!0,r)},t.prototype.writeFloatBE=function(t,e,r){return P(this,t,e,!1,r)},t.prototype.writeDoubleLE=function(t,e,r){return U(this,t,e,!0,r)},t.prototype.writeDoubleBE=function(t,e,r){return U(this,t,e,!1,r)},t.prototype.copy=function(e,r,n,i){if(n||(n=0),i||0===i||(i=this.length),r>=e.length&&(r=e.length),r||(r=0),i>0&&n>i&&(i=n),i===n)return 0;if(0===e.length||0===this.length)return 0;if(0>r)throw new RangeError("targetStart out of bounds");if(0>n||n>=this.length)throw new RangeError("sourceStart out of bounds");if(0>i)throw new RangeError("sourceEnd out of bounds");i>this.length&&(i=this.length),e.length-r<i-n&&(i=e.length-r+n);var o,s=i-n;if(this===e&&r>n&&i>r)for(o=s-1;o>=0;o--)e[o+r]=this[o+n];else if(1e3>s||!t.TYPED_ARRAY_SUPPORT)for(o=0;s>o;o++)e[o+r]=this[o+n];else e._set(this.subarray(n,n+s),r);return s},t.prototype.fill=function(t,e,r){if(t||(t=0),e||(e=0),r||(r=this.length),e>r)throw new RangeError("end < start");if(r!==e&&0!==this.length){if(0>e||e>=this.length)throw new RangeError("start out of bounds");if(0>r||r>this.length)throw new RangeError("end out of bounds");var n;if("number"==typeof t)for(n=e;r>n;n++)this[n]=t;else{var i=H(t.toString()),o=i.length;for(n=e;r>n;n++)this[n]=i[n%o]}return this}},t.prototype.toArrayBuffer=function(){if("undefined"!=typeof Uint8Array){if(t.TYPED_ARRAY_SUPPORT)return new t(this).buffer;for(var e=new Uint8Array(this.length),r=0,n=e.length;n>r;r+=1)e[r]=this[r];return e.buffer}throw new TypeError("Buffer.toArrayBuffer not supported in this browser")};var $=t.prototype;t._augment=function(e){return e.constructor=t,e._isBuffer=!0,e._set=e.set,e.get=$.get,e.set=$.set,e.write=$.write,e.toString=$.toString,e.toLocaleString=$.toString,e.toJSON=$.toJSON,e.equals=$.equals,e.compare=$.compare,e.indexOf=$.indexOf,e.copy=$.copy,e.slice=$.slice,e.readUIntLE=$.readUIntLE,e.readUIntBE=$.readUIntBE,e.readUInt8=$.readUInt8,e.readUInt16LE=$.readUInt16LE,e.readUInt16BE=$.readUInt16BE,e.readUInt32LE=$.readUInt32LE,e.readUInt32BE=$.readUInt32BE,e.readIntLE=$.readIntLE,e.readIntBE=$.readIntBE,e.readInt8=$.readInt8,e.readInt16LE=$.readInt16LE,e.readInt16BE=$.readInt16BE,e.readInt32LE=$.readInt32LE,e.readInt32BE=$.readInt32BE,e.readFloatLE=$.readFloatLE,e.readFloatBE=$.readFloatBE,e.readDoubleLE=$.readDoubleLE,e.readDoubleBE=$.readDoubleBE,e.writeUInt8=$.writeUInt8,e.writeUIntLE=$.writeUIntLE,e.writeUIntBE=$.writeUIntBE,e.writeUInt16LE=$.writeUInt16LE,e.writeUInt16BE=$.writeUInt16BE,e.writeUInt32LE=$.writeUInt32LE,e.writeUInt32BE=$.writeUInt32BE,e.writeIntLE=$.writeIntLE,e.writeIntBE=$.writeIntBE,e.writeInt8=$.writeInt8,e.writeInt16LE=$.writeInt16LE,e.writeInt16BE=$.writeInt16BE,e.writeInt32LE=$.writeInt32LE,e.writeInt32BE=$.writeInt32BE,e.writeFloatLE=$.writeFloatLE,e.writeFloatBE=$.writeFloatBE,e.writeDoubleLE=$.writeDoubleLE,e.writeDoubleBE=$.writeDoubleBE,e.fill=$.fill,e.inspect=$.inspect,e.toArrayBuffer=$.toArrayBuffer,e};var tt=/[^+\/0-9A-Za-z-_]/g}).call(e,r(34).Buffer,function(){return this}())},function(t,e,r){var n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";!function(t){"use strict";function e(t){var e=t.charCodeAt(0);return e===s||e===h?62:e===a||e===f?63:c>e?-1:c+10>e?e-c+26+26:l+26>e?e-l:u+26>e?e-u+26:void 0}function r(t){function r(t){u[h++]=t}var n,i,s,a,c,u;if(t.length%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var l=t.length;c="="===t.charAt(l-2)?2:"="===t.charAt(l-1)?1:0,u=new o(3*t.length/4-c),s=c>0?t.length-4:t.length;var h=0;for(n=0,i=0;s>n;n+=4,i+=3)a=e(t.charAt(n))<<18|e(t.charAt(n+1))<<12|e(t.charAt(n+2))<<6|e(t.charAt(n+3)),r((16711680&a)>>16),r((65280&a)>>8),r(255&a);return 2===c?(a=e(t.charAt(n))<<2|e(t.charAt(n+1))>>4,r(255&a)):1===c&&(a=e(t.charAt(n))<<10|e(t.charAt(n+1))<<4|e(t.charAt(n+2))>>2,r(a>>8&255),r(255&a)),u}function i(t){function e(t){return n.charAt(t)}function r(t){return e(t>>18&63)+e(t>>12&63)+e(t>>6&63)+e(63&t)}var i,o,s,a=t.length%3,c="";for(i=0,s=t.length-a;s>i;i+=3)o=(t[i]<<16)+(t[i+1]<<8)+t[i+2],c+=r(o);switch(a){case 1:o=t[t.length-1],c+=e(o>>2),c+=e(o<<4&63),c+="==";break;case 2:o=(t[t.length-2]<<8)+t[t.length-1],c+=e(o>>10),c+=e(o>>4&63),c+=e(o<<2&63),c+="="}return c}var o="undefined"!=typeof Uint8Array?Uint8Array:Array,s="+".charCodeAt(0),a="/".charCodeAt(0),c="0".charCodeAt(0),u="a".charCodeAt(0),l="A".charCodeAt(0),h="-".charCodeAt(0),f="_".charCodeAt(0);t.toByteArray=r,t.fromByteArray=i}(e)},function(t,e){e.read=function(t,e,r,n,i){var o,s,a=8*i-n-1,c=(1<<a)-1,u=c>>1,l=-7,h=r?i-1:0,f=r?-1:1,p=t[e+h];for(h+=f,o=p&(1<<-l)-1,p>>=-l,l+=a;l>0;o=256*o+t[e+h],h+=f,l-=8);for(s=o&(1<<-l)-1,o>>=-l,l+=n;l>0;s=256*s+t[e+h],h+=f,l-=8);if(0===o)o=1-u;else{if(o===c)return s?NaN:(p?-1:1)*(1/0);s+=Math.pow(2,n),o-=u}return(p?-1:1)*s*Math.pow(2,o-n)},e.write=function(t,e,r,n,i,o){var s,a,c,u=8*o-i-1,l=(1<<u)-1,h=l>>1,f=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,p=n?0:o-1,d=n?1:-1,g=0>e||0===e&&0>1/e?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(a=isNaN(e)?1:0,s=l):(s=Math.floor(Math.log(e)/Math.LN2),e*(c=Math.pow(2,-s))<1&&(s--,c*=2),e+=s+h>=1?f/c:f*Math.pow(2,1-h),e*c>=2&&(s++,c/=2),s+h>=l?(a=0,s=l):s+h>=1?(a=(e*c-1)*Math.pow(2,i),s+=h):(a=e*Math.pow(2,h-1)*Math.pow(2,i),s=0));i>=8;t[r+p]=255&a,p+=d,a/=256,i-=8);for(s=s<<i|a,u+=i;u>0;t[r+p]=255&s,p+=d,s/=256,u-=8);t[r+p-d]|=128*g}},function(t,e){var r={}.toString;t.exports=Array.isArray||function(t){return"[object Array]"==r.call(t)}},function(t,e,r){(function(t){function r(t){return Array.isArray?Array.isArray(t):"[object Array]"===_(t)}function n(t){return"boolean"==typeof t}function i(t){return null===t}function o(t){return null==t}function s(t){return"number"==typeof t}function a(t){return"string"==typeof t}function c(t){return"symbol"==typeof t}function u(t){return void 0===t}function l(t){return"[object RegExp]"===_(t)}function h(t){return"object"==typeof t&&null!==t}function f(t){return"[object Date]"===_(t)}function p(t){return"[object Error]"===_(t)||t instanceof Error}function d(t){return"function"==typeof t}function g(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"==typeof t||"undefined"==typeof t}function _(t){return Object.prototype.toString.call(t)}e.isArray=r,e.isBoolean=n,e.isNull=i,e.isNullOrUndefined=o,e.isNumber=s,e.isString=a,e.isSymbol=c,e.isUndefined=u,e.isRegExp=l,e.isObject=h,e.isDate=f,e.isError=p,e.isFunction=d,e.isPrimitive=g,e.isBuffer=t.isBuffer}).call(e,r(34).Buffer)},function(t,e){"function"==typeof Object.create?t.exports=function(t,e){t.super_=e,t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(t,e){t.super_=e;var r=function(){};r.prototype=e.prototype,t.prototype=new r,t.prototype.constructor=t}},function(t,e){},function(t,e,r){(function(e){function n(t){return this instanceof n?(c.call(this,t),u.call(this,t),t&&t.readable===!1&&(this.readable=!1),t&&t.writable===!1&&(this.writable=!1),this.allowHalfOpen=!0,t&&t.allowHalfOpen===!1&&(this.allowHalfOpen=!1),void this.once("end",i)):new n(t)}function i(){this.allowHalfOpen||this._writableState.ended||e.nextTick(this.end.bind(this))}function o(t,e){for(var r=0,n=t.length;n>r;r++)e(t[r],r)}t.exports=n;var s=Object.keys||function(t){var e=[];for(var r in t)e.push(r);return e},a=r(38);a.inherits=r(39);var c=r(32),u=r(42);a.inherits(n,c),o(s(u.prototype),function(t){n.prototype[t]||(n.prototype[t]=u.prototype[t])})}).call(e,r(3))},function(t,e,r){(function(e){function n(t,e,r){this.chunk=t,this.encoding=e,this.callback=r}function i(t,e){var n=r(41);t=t||{};var i=t.highWaterMark,o=t.objectMode?16:16384;this.highWaterMark=i||0===i?i:o,this.objectMode=!!t.objectMode,e instanceof n&&(this.objectMode=this.objectMode||!!t.writableObjectMode),this.highWaterMark=~~this.highWaterMark,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1;var s=t.decodeStrings===!1;this.decodeStrings=!s,this.defaultEncoding=t.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(t){p(e,t)},this.writecb=null,this.writelen=0,this.buffer=[],this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1}function o(t){var e=r(41);return this instanceof o||this instanceof e?(this._writableState=new i(t,this),this.writable=!0,void x.call(this)):new o(t)}function s(t,r,n){var i=new Error("write after end");t.emit("error",i),e.nextTick(function(){n(i)})}function a(t,r,n,i){var o=!0;if(!(S.isBuffer(n)||S.isString(n)||S.isNullOrUndefined(n)||r.objectMode)){var s=new TypeError("Invalid non-string/buffer chunk");t.emit("error",s),e.nextTick(function(){i(s)}),o=!1}return o}function c(t,e,r){return!t.objectMode&&t.decodeStrings!==!1&&S.isString(e)&&(e=new w(e,r)),e}function u(t,e,r,i,o){r=c(e,r,i),S.isBuffer(r)&&(i="buffer");var s=e.objectMode?1:r.length;e.length+=s;var a=e.length<e.highWaterMark;return a||(e.needDrain=!0),e.writing||e.corked?e.buffer.push(new n(r,i,o)):l(t,e,!1,s,r,i,o),a}function l(t,e,r,n,i,o,s){e.writelen=n,e.writecb=s,e.writing=!0,e.sync=!0,r?t._writev(i,e.onwrite):t._write(i,o,e.onwrite),e.sync=!1}function h(t,r,n,i,o){n?e.nextTick(function(){r.pendingcb--,o(i)}):(r.pendingcb--,o(i)),t._writableState.errorEmitted=!0,t.emit("error",i)}function f(t){t.writing=!1,t.writecb=null,t.length-=t.writelen,t.writelen=0}function p(t,r){var n=t._writableState,i=n.sync,o=n.writecb;if(f(n),r)h(t,n,i,r,o);else{var s=m(t,n);s||n.corked||n.bufferProcessing||!n.buffer.length||_(t,n),i?e.nextTick(function(){d(t,n,s,o)}):d(t,n,s,o)}}function d(t,e,r,n){r||g(t,e),e.pendingcb--,n(),y(t,e)}function g(t,e){0===e.length&&e.needDrain&&(e.needDrain=!1,t.emit("drain"))}function _(t,e){if(e.bufferProcessing=!0,t._writev&&e.buffer.length>1){for(var r=[],n=0;n<e.buffer.length;n++)r.push(e.buffer[n].callback);e.pendingcb++,l(t,e,!0,e.length,e.buffer,"",function(t){for(var n=0;n<r.length;n++)e.pendingcb--,r[n](t)}),e.buffer=[]}else{for(var n=0;n<e.buffer.length;n++){var i=e.buffer[n],o=i.chunk,s=i.encoding,a=i.callback,c=e.objectMode?1:o.length;if(l(t,e,!1,c,o,s,a),e.writing){n++;break}}n<e.buffer.length?e.buffer=e.buffer.slice(n):e.buffer.length=0}e.bufferProcessing=!1}function m(t,e){return e.ending&&0===e.length&&!e.finished&&!e.writing}function b(t,e){e.prefinished||(e.prefinished=!0,t.emit("prefinish"))}function y(t,e){var r=m(t,e);return r&&(0===e.pendingcb?(b(t,e),e.finished=!0,t.emit("finish")):b(t,e)),r}function v(t,r,n){r.ending=!0,y(t,r),n&&(r.finished?e.nextTick(n):t.once("finish",n)),r.ended=!0}t.exports=o;var w=r(34).Buffer;o.WritableState=i;var S=r(38);S.inherits=r(39);var x=r(29);S.inherits(o,x),o.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe. Not readable."))},o.prototype.write=function(t,e,r){var n=this._writableState,i=!1;return S.isFunction(e)&&(r=e,e=null),S.isBuffer(t)?e="buffer":e||(e=n.defaultEncoding),S.isFunction(r)||(r=function(){}),n.ended?s(this,n,r):a(this,n,t,r)&&(n.pendingcb++,i=u(this,n,t,e,r)),i},o.prototype.cork=function(){var t=this._writableState;t.corked++},o.prototype.uncork=function(){var t=this._writableState;t.corked&&(t.corked--,t.writing||t.corked||t.finished||t.bufferProcessing||!t.buffer.length||_(this,t))},o.prototype._write=function(t,e,r){r(new Error("not implemented"))},o.prototype._writev=null,o.prototype.end=function(t,e,r){var n=this._writableState;S.isFunction(t)?(r=t,t=null,e=null):S.isFunction(e)&&(r=e,e=null),S.isNullOrUndefined(t)||this.write(t,e),n.corked&&(n.corked=1,this.uncork()),n.ending||n.finished||v(this,n,r)}}).call(e,r(3))},function(t,e,r){function n(t){if(t&&!c(t))throw new Error("Unknown encoding: "+t)}function i(t){return t.toString(this.encoding)}function o(t){this.charReceived=t.length%2,this.charLength=this.charReceived?2:0}function s(t){this.charReceived=t.length%3,this.charLength=this.charReceived?3:0}var a=r(34).Buffer,c=a.isEncoding||function(t){switch(t&&t.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}},u=e.StringDecoder=function(t){switch(this.encoding=(t||"utf8").toLowerCase().replace(/[-_]/,""),n(t),this.encoding){case"utf8":this.surrogateSize=3;break;case"ucs2":case"utf16le":this.surrogateSize=2,this.detectIncompleteChar=o;break;case"base64":this.surrogateSize=3,this.detectIncompleteChar=s;break;default:return void(this.write=i)}this.charBuffer=new a(6),this.charReceived=0,this.charLength=0};u.prototype.write=function(t){for(var e="";this.charLength;){var r=t.length>=this.charLength-this.charReceived?this.charLength-this.charReceived:t.length;if(t.copy(this.charBuffer,this.charReceived,0,r),this.charReceived+=r,this.charReceived<this.charLength)return"";t=t.slice(r,t.length),e=this.charBuffer.slice(0,this.charLength).toString(this.encoding);var n=e.charCodeAt(e.length-1);if(!(n>=55296&&56319>=n)){if(this.charReceived=this.charLength=0,0===t.length)return e;break}this.charLength+=this.surrogateSize,e=""}this.detectIncompleteChar(t);var i=t.length;this.charLength&&(t.copy(this.charBuffer,0,t.length-this.charReceived,i),i-=this.charReceived),e+=t.toString(this.encoding,0,i);var i=e.length-1,n=e.charCodeAt(i);if(n>=55296&&56319>=n){var o=this.surrogateSize;return this.charLength+=o,this.charReceived+=o,this.charBuffer.copy(this.charBuffer,o,0,o),t.copy(this.charBuffer,0,0,o),e.substring(0,i)}return e},u.prototype.detectIncompleteChar=function(t){for(var e=t.length>=3?3:t.length;e>0;e--){var r=t[t.length-e];if(1==e&&r>>5==6){this.charLength=2;break}if(2>=e&&r>>4==14){this.charLength=3;break}if(3>=e&&r>>3==30){this.charLength=4;break}}this.charReceived=e},u.prototype.end=function(t){var e="";if(t&&t.length&&(e=this.write(t)),this.charReceived){var r=this.charReceived,n=this.charBuffer,i=this.encoding;e+=n.slice(0,r).toString(i)}return e}},function(t,e,r){function n(t,e){this.afterTransform=function(t,r){return i(e,t,r)},this.needTransform=!1,this.transforming=!1,this.writecb=null,this.writechunk=null}function i(t,e,r){var n=t._transformState;n.transforming=!1;var i=n.writecb;if(!i)return t.emit("error",new Error("no writecb in Transform class"));n.writechunk=null,n.writecb=null,c.isNullOrUndefined(r)||t.push(r),i&&i(e);var o=t._readableState;o.reading=!1,(o.needReadable||o.length<o.highWaterMark)&&t._read(o.highWaterMark)}function o(t){if(!(this instanceof o))return new o(t);a.call(this,t),this._transformState=new n(t,this);var e=this;this._readableState.needReadable=!0,this._readableState.sync=!1,this.once("prefinish",function(){c.isFunction(this._flush)?this._flush(function(t){s(e,t)}):s(e)})}function s(t,e){if(e)return t.emit("error",e);var r=t._writableState,n=t._transformState;if(r.length)throw new Error("calling transform done when ws.length != 0");if(n.transforming)throw new Error("calling transform done when still transforming");return t.push(null)}t.exports=o;var a=r(41),c=r(38);c.inherits=r(39),c.inherits(o,a),o.prototype.push=function(t,e){return this._transformState.needTransform=!1,a.prototype.push.call(this,t,e)},o.prototype._transform=function(t,e,r){throw new Error("not implemented")},o.prototype._write=function(t,e,r){var n=this._transformState;if(n.writecb=r,n.writechunk=t,n.writeencoding=e,!n.transforming){var i=this._readableState;(n.needTransform||i.needReadable||i.length<i.highWaterMark)&&this._read(i.highWaterMark)}},o.prototype._read=function(t){var e=this._transformState;c.isNull(e.writechunk)||!e.writecb||e.transforming?e.needTransform=!0:(e.transforming=!0,this._transform(e.writechunk,e.writeencoding,e.afterTransform))}},function(t,e,r){function n(t){return this instanceof n?void i.call(this,t):new n(t)}t.exports=n;var i=r(44),o=r(38);o.inherits=r(39),o.inherits(n,i),n.prototype._transform=function(t,e,r){r(null,t)}},function(t,e,r){t.exports=r(42)},function(t,e,r){t.exports=r(41)},function(t,e,r){t.exports=r(44)},function(t,e,r){t.exports=r(45)},function(t,e){},function(t,e,r){function n(t){this._cbs=t||{}}t.exports=n;var i=r(14).EVENTS;Object.keys(i).forEach(function(t){if(0===i[t])t="on"+t,n.prototype[t]=function(){this._cbs[t]&&this._cbs[t]()};else if(1===i[t])t="on"+t,n.prototype[t]=function(e){this._cbs[t]&&this._cbs[t](e)};else{if(2!==i[t])throw Error("wrong number of arguments");t="on"+t,n.prototype[t]=function(e,r){this._cbs[t]&&this._cbs[t](e,r)}}})},function(t,e,r){var n=t.exports;[r(53),r(59),r(60),r(61),r(62),r(63)].forEach(function(t){Object.keys(t).forEach(function(e){n[e]=t[e].bind(n); -})})},function(t,e,r){function n(t,e){return t.children?t.children.map(function(t){return s(t,e)}).join(""):""}function i(t){return Array.isArray(t)?t.map(i).join(""):a(t)||t.type===o.CDATA?i(t.children):t.type===o.Text?t.data:""}var o=r(23),s=r(54),a=o.isTag;t.exports={getInnerHTML:n,getOuterHTML:s,getText:i}},function(t,e,r){function n(t,e){if(t){var r,n="";for(var i in t)r=t[i],n&&(n+=" "),n+=!r&&h[i]?i:i+'="'+(e.decodeEntities?l.encodeXML(r):r)+'"';return n}}function i(t,e){"svg"===t.name&&(e={decodeEntities:e.decodeEntities,xmlMode:!0});var r="<"+t.name,i=n(t.attribs,e);return i&&(r+=" "+i),!e.xmlMode||t.children&&0!==t.children.length?(r+=">",t.children&&(r+=d(t.children,e)),p[t.name]&&!e.xmlMode||(r+="</"+t.name+">")):r+="/>",r}function o(t){return"<"+t.data+">"}function s(t,e){var r=t.data||"";return!e.decodeEntities||t.parent&&t.parent.name in f||(r=l.encodeXML(r)),r}function a(t){return"<![CDATA["+t.children[0].data+"]]>"}function c(t){return"<!--"+t.data+"-->"}var u=r(55),l=r(56),h={__proto__:null,allowfullscreen:!0,async:!0,autofocus:!0,autoplay:!0,checked:!0,controls:!0,"default":!0,defer:!0,disabled:!0,hidden:!0,ismap:!0,loop:!0,multiple:!0,muted:!0,open:!0,readonly:!0,required:!0,reversed:!0,scoped:!0,seamless:!0,selected:!0,typemustmatch:!0},f={__proto__:null,style:!0,script:!0,xmp:!0,iframe:!0,noembed:!0,noframes:!0,plaintext:!0,noscript:!0},p={__proto__:null,area:!0,base:!0,basefont:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,isindex:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},d=t.exports=function(t,e){Array.isArray(t)||t.cheerio||(t=[t]),e=e||{};for(var r="",n=0;n<t.length;n++){var l=t[n];r+="root"===l.type?d(l.children,e):u.isTag(l)?i(l,e):l.type===u.Directive?o(l):l.type===u.Comment?c(l):l.type===u.CDATA?a(l):s(l,e)}return r}},function(t,e){t.exports={Text:"text",Directive:"directive",Comment:"comment",Script:"script",Style:"style",Tag:"tag",CDATA:"cdata",isTag:function(t){return"tag"===t.type||"script"===t.type||"style"===t.type}}},function(t,e,r){var n=r(57),i=r(58);e.decode=function(t,e){return(!e||0>=e?i.XML:i.HTML)(t)},e.decodeStrict=function(t,e){return(!e||0>=e?i.XML:i.HTMLStrict)(t)},e.encode=function(t,e){return(!e||0>=e?n.XML:n.HTML)(t)},e.encodeXML=n.XML,e.encodeHTML4=e.encodeHTML5=e.encodeHTML=n.HTML,e.decodeXML=e.decodeXMLStrict=i.XML,e.decodeHTML4=e.decodeHTML5=e.decodeHTML=i.HTML,e.decodeHTML4Strict=e.decodeHTML5Strict=e.decodeHTMLStrict=i.HTMLStrict,e.escape=n.escape},function(t,e,r){function n(t){return Object.keys(t).sort().reduce(function(e,r){return e[t[r]]="&"+r+";",e},{})}function i(t){var e=[],r=[];return Object.keys(t).forEach(function(t){1===t.length?e.push("\\"+t):r.push(t)}),r.unshift("["+e.join("")+"]"),new RegExp(r.join("|"),"g")}function o(t){return"&#x"+t.charCodeAt(0).toString(16).toUpperCase()+";"}function s(t){var e=t.charCodeAt(0),r=t.charCodeAt(1),n=1024*(e-55296)+r-56320+65536;return"&#x"+n.toString(16).toUpperCase()+";"}function a(t,e){function r(e){return t[e]}return function(t){return t.replace(e,r).replace(d,s).replace(p,o)}}function c(t){return t.replace(g,o).replace(d,s).replace(p,o)}var u=n(r(21)),l=i(u);e.XML=a(u,l);var h=n(r(19)),f=i(h);e.HTML=a(h,f);var p=/[^\0-\x7F]/g,d=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,g=i(u);e.escape=c},function(t,e,r){function n(t){var e=Object.keys(t).join("|"),r=o(t);e+="|#[xX][\\da-fA-F]+|#\\d+";var n=new RegExp("&(?:"+e+");","g");return function(t){return String(t).replace(n,r)}}function i(t,e){return e>t?1:-1}function o(t){return function(e){return"#"===e.charAt(1)?u("X"===e.charAt(2)||"x"===e.charAt(2)?parseInt(e.substr(3),16):parseInt(e.substr(2),10)):t[e.slice(1,-1)]}}var s=r(19),a=r(20),c=r(21),u=r(17),l=n(c),h=n(s),f=function(){function t(t){return";"!==t.substr(-1)&&(t+=";"),l(t)}for(var e=Object.keys(a).sort(i),r=Object.keys(s).sort(i),n=0,c=0;n<r.length;n++)e[c]===r[n]?(r[n]+=";?",c++):r[n]+=";";var u=new RegExp("&(?:"+r.join("|")+"|#[xX][\\da-fA-F]+;?|#\\d+;?)","g"),l=o(s);return function(e){return String(e).replace(u,t)}}();t.exports={XML:l,HTML:f,HTMLStrict:h}},function(t,e){var r=e.getChildren=function(t){return t.children},n=e.getParent=function(t){return t.parent};e.getSiblings=function(t){var e=n(t);return e?r(e):[t]},e.getAttributeValue=function(t,e){return t.attribs&&t.attribs[e]},e.hasAttrib=function(t,e){return!!t.attribs&&hasOwnProperty.call(t.attribs,e)},e.getName=function(t){return t.name}},function(t,e){e.removeElement=function(t){if(t.prev&&(t.prev.next=t.next),t.next&&(t.next.prev=t.prev),t.parent){var e=t.parent.children;e.splice(e.lastIndexOf(t),1)}},e.replaceElement=function(t,e){var r=e.prev=t.prev;r&&(r.next=e);var n=e.next=t.next;n&&(n.prev=e);var i=e.parent=t.parent;if(i){var o=i.children;o[o.lastIndexOf(t)]=e}},e.appendChild=function(t,e){if(e.parent=t,1!==t.children.push(e)){var r=t.children[t.children.length-2];r.next=e,e.prev=r,e.next=null}},e.append=function(t,e){var r=t.parent,n=t.next;if(e.next=n,e.prev=t,t.next=e,e.parent=r,n){if(n.prev=e,r){var i=r.children;i.splice(i.lastIndexOf(n),0,e)}}else r&&r.children.push(e)},e.prepend=function(t,e){var r=t.parent;if(r){var n=r.children;n.splice(n.lastIndexOf(t),0,e)}t.prev&&(t.prev.next=e),e.parent=r,e.prev=t.prev,e.next=t,t.prev=e}},function(t,e,r){function n(t,e,r,n){return Array.isArray(e)||(e=[e]),"number"==typeof n&&isFinite(n)||(n=1/0),i(t,e,r!==!1,n)}function i(t,e,r,n){for(var o,s=[],a=0,c=e.length;c>a&&!(t(e[a])&&(s.push(e[a]),--n<=0))&&(o=e[a].children,!(r&&o&&o.length>0&&(o=i(t,o,r,n),s=s.concat(o),n-=o.length,0>=n)));a++);return s}function o(t,e){for(var r=0,n=e.length;n>r;r++)if(t(e[r]))return e[r];return null}function s(t,e){for(var r=null,n=0,i=e.length;i>n&&!r;n++)u(e[n])&&(t(e[n])?r=e[n]:e[n].children.length>0&&(r=s(t,e[n].children)));return r}function a(t,e){for(var r=0,n=e.length;n>r;r++)if(u(e[r])&&(t(e[r])||e[r].children.length>0&&a(t,e[r].children)))return!0;return!1}function c(t,e){for(var r=[],n=0,i=e.length;i>n;n++)u(e[n])&&(t(e[n])&&r.push(e[n]),e[n].children.length>0&&(r=r.concat(c(t,e[n].children))));return r}var u=r(23).isTag;t.exports={filter:n,find:i,findOneChild:o,findOne:s,existsOne:a,findAll:c}},function(t,e,r){function n(t,e){return"function"==typeof e?function(r){return r.attribs&&e(r.attribs[t])}:function(r){return r.attribs&&r.attribs[t]===e}}function i(t,e){return function(r){return t(r)||e(r)}}var o=r(23),s=e.isTag=o.isTag;e.testElement=function(t,e){for(var r in t)if(t.hasOwnProperty(r)){if("tag_name"===r){if(!s(e)||!t.tag_name(e.name))return!1}else if("tag_type"===r){if(!t.tag_type(e.type))return!1}else if("tag_contains"===r){if(s(e)||!t.tag_contains(e.data))return!1}else if(!e.attribs||!t[r](e.attribs[r]))return!1}else;return!0};var a={tag_name:function(t){return"function"==typeof t?function(e){return s(e)&&t(e.name)}:"*"===t?s:function(e){return s(e)&&e.name===t}},tag_type:function(t){return"function"==typeof t?function(e){return t(e.type)}:function(e){return e.type===t}},tag_contains:function(t){return"function"==typeof t?function(e){return!s(e)&&t(e.data)}:function(e){return!s(e)&&e.data===t}}};e.getElements=function(t,e,r,o){var s=Object.keys(t).map(function(e){var r=t[e];return e in a?a[e](r):n(e,r)});return 0===s.length?[]:this.filter(s.reduce(i),e,r,o)},e.getElementById=function(t,e,r){return Array.isArray(e)||(e=[e]),this.findOne(n("id",t),e,r!==!1)},e.getElementsByTagName=function(t,e,r,n){return this.filter(a.tag_name(t),e,r,n)},e.getElementsByTagType=function(t,e,r,n){return this.filter(a.tag_type(t),e,r,n)}},function(t,e){e.removeSubsets=function(t){for(var e,r,n,i=t.length;--i>-1;){for(e=r=t[i],t[i]=null,n=!0;r;){if(t.indexOf(r)>-1){n=!1,t.splice(i,1);break}r=r.parent}n&&(t[i]=e)}return t};var r={DISCONNECTED:1,PRECEDING:2,FOLLOWING:4,CONTAINS:8,CONTAINED_BY:16},n=e.compareDocumentPosition=function(t,e){var n,i,o,s,a,c,u=[],l=[];if(t===e)return 0;for(n=t;n;)u.unshift(n),n=n.parent;for(n=e;n;)l.unshift(n),n=n.parent;for(c=0;u[c]===l[c];)c++;return 0===c?r.DISCONNECTED:(i=u[c-1],o=i.children,s=u[c],a=l[c],o.indexOf(s)>o.indexOf(a)?i===e?r.FOLLOWING|r.CONTAINED_BY:r.FOLLOWING:i===t?r.PRECEDING|r.CONTAINS:r.PRECEDING)};e.uniqueSort=function(t){var e,i,o=t.length;for(t=t.slice();--o>-1;)e=t[o],i=t.indexOf(e),i>-1&&o>i&&t.splice(o,1);return t.sort(function(t,e){var i=n(t,e);return i&r.PRECEDING?-1:i&r.FOLLOWING?1:0}),t}},function(t,e,r){function n(t){this._cbs=t||{},this.events=[]}t.exports=n;var i=r(14).EVENTS;Object.keys(i).forEach(function(t){if(0===i[t])t="on"+t,n.prototype[t]=function(){this.events.push([t]),this._cbs[t]&&this._cbs[t]()};else if(1===i[t])t="on"+t,n.prototype[t]=function(e){this.events.push([t,e]),this._cbs[t]&&this._cbs[t](e)};else{if(2!==i[t])throw Error("wrong number of arguments");t="on"+t,n.prototype[t]=function(e,r){this.events.push([t,e,r]),this._cbs[t]&&this._cbs[t](e,r)}}}),n.prototype.onreset=function(){this.events=[],this._cbs.onreset&&this._cbs.onreset()},n.prototype.restart=function(){this._cbs.onreset&&this._cbs.onreset();for(var t=0,e=this.events.length;e>t;t++)if(this._cbs[this.events[t][0]]){var r=this.events[t].length;1===r?this._cbs[this.events[t][0]]():2===r?this._cbs[this.events[t][0]](this.events[t][1]):this._cbs[this.events[t][0]](this.events[t][1],this.events[t][2])}}},function(t,e,r){"use strict";var n=r(66),i=r(67),o=r(73);t.exports=function(t){var e,s=n(arguments[1]);return s.normalizer||(e=s.length=i(s.length,t.length,s.async),0!==e&&(s.primitive?e===!1?s.normalizer=r(110):e>1&&(s.normalizer=r(111)(e)):e===!1?s.normalizer=r(112)():1===e?s.normalizer=r(114)():s.normalizer=r(115)(e))),s.async&&r(116),s.dispose&&r(119),s.maxAge&&r(120),s.max&&r(123),s.refCounter&&r(125),o(t,s)}},function(t,e){"use strict";var r=Array.prototype.forEach,n=Object.create,i=function(t,e){var r;for(r in t)e[r]=t[r]};t.exports=function(t){var e=n(null);return r.call(arguments,function(t){null!=t&&i(Object(t),e)}),e}},function(t,e,r){"use strict";var n=r(68);t.exports=function(t,e,r){var i;return isNaN(t)?(i=e,i>=0?r&&i?i-1:i:1):t===!1?!1:n(t)}},function(t,e,r){"use strict";var n=r(69),i=Math.max;t.exports=function(t){return i(0,n(t))}},function(t,e,r){"use strict";var n=r(70),i=Math.abs,o=Math.floor;t.exports=function(t){return isNaN(t)?0:(t=Number(t),0!==t&&isFinite(t)?n(t)*o(i(t)):t)}},function(t,e,r){"use strict";t.exports=r(71)()?Math.sign:r(72)},function(t,e){"use strict";t.exports=function(){var t=Math.sign;return"function"!=typeof t?!1:1===t(10)&&-1===t(-20)}},function(t,e){"use strict";t.exports=function(t){return t=Number(t),isNaN(t)||0===t?t:t>0?1:-1}},function(t,e,r){"use strict";var n=r(74),i=r(75),o=r(78),s=r(79),a=r(67),c=Object.prototype.hasOwnProperty;t.exports=function u(t){var e,r,l;return n(t),e=Object(arguments[1]),c.call(t,"__memoized__")&&!e.force?t:(r=a(e.length,t.length,e.async&&o.async),l=s(t,r,e),i(o,function(t,r){e[r]&&t(e[r],l,e)}),u.__profiler__&&u.__profiler__(l),l.updateEnv(),l.memoized)}},function(t,e){"use strict";t.exports=function(t){if("function"!=typeof t)throw new TypeError(t+" is not a function");return t}},function(t,e,r){"use strict";t.exports=r(76)("forEach")},function(t,e,r){"use strict";var n=r(74),i=r(77),o=Function.prototype.bind,s=Function.prototype.call,a=Object.keys,c=Object.prototype.propertyIsEnumerable;t.exports=function(t,e){return function(r,u){var l,h=arguments[2],f=arguments[3];return r=Object(i(r)),n(u),l=a(r),f&&l.sort("function"==typeof f?o.call(f,r):void 0),"function"!=typeof t&&(t=l[t]),s.call(t,l,function(t,n){return c.call(r,t)?s.call(u,h,r[t],t,r,n):e})}}},function(t,e){"use strict";t.exports=function(t){if(null==t)throw new TypeError("Cannot use null or undefined");return t}},function(t,e){"use strict"},function(t,e,r){"use strict";var n=r(80),i=r(87),o=r(89),s=r(94).methods,a=r(95),c=r(109),u=Function.prototype.apply,l=Function.prototype.call,h=Object.create,f=Object.prototype.hasOwnProperty,p=Object.defineProperties,d=s.on,g=s.emit;t.exports=function(t,e,r){var s,_,m,b,y,v,w,S,x,E,k,T,A,L=h(null);return _=e!==!1?e:isNaN(t.length)?1:t.length,r.normalizer&&(S=c(r.normalizer),m=S.get,b=S.set,y=S["delete"],v=S.clear),null!=r.resolvers&&(A=a(r.resolvers)),T=m?i(function(e){var r,i,o=arguments;if(A&&(o=A(o)),r=m(o),null!==r&&f.call(L,r))return x&&s.emit("get",r,o,this),L[r];if(i=1===o.length?l.call(t,this,o[0]):u.call(t,this,o),null===r){if(r=m(o),null!==r)throw n("Circular invocation","CIRCULAR_INVOCATION");r=b(o)}else if(f.call(L,r))throw n("Circular invocation","CIRCULAR_INVOCATION");return L[r]=i,E&&s.emit("set",r),i},_):0===e?function(){var e;if(f.call(L,"data"))return x&&s.emit("get","data",arguments,this),L.data;if(e=arguments.length?u.call(t,this,arguments):l.call(t,this),f.call(L,"data"))throw n("Circular invocation","CIRCULAR_INVOCATION");return L.data=e,E&&s.emit("set","data"),e}:function(e){var r,i,o=arguments;if(A&&(o=A(arguments)),i=String(o[0]),f.call(L,i))return x&&s.emit("get",i,o,this),L[i];if(r=1===o.length?l.call(t,this,o[0]):u.call(t,this,o),f.call(L,i))throw n("Circular invocation","CIRCULAR_INVOCATION");return L[i]=r,E&&s.emit("set",i),r},s={original:t,memoized:T,get:function(t){return A&&(t=A(t)),m?m(t):String(t[0])},has:function(t){return f.call(L,t)},"delete":function(t){var e;f.call(L,t)&&(y&&y(t),e=L[t],delete L[t],k&&s.emit("delete",t,e))},clear:function(){var t=L;v&&v(),L=h(null),s.emit("clear",t)},on:function(t,e){return"get"===t?x=!0:"set"===t?E=!0:"delete"===t&&(k=!0),d.call(this,t,e)},emit:g,updateEnv:function(){t=s.original}},w=m?i(function(t){var e,r=arguments;A&&(r=A(r)),e=m(r),null!==e&&s["delete"](e)},_):0===e?function(){return s["delete"]("data")}:function(t){return A&&(t=A(arguments)[0]),s["delete"](t)},p(T,{__memoized__:o(!0),"delete":o(w),clear:o(s.clear)}),s}},function(t,e,r){"use strict";var n=r(81),i=Error.captureStackTrace;e=t.exports=function(t){var r=new Error,o=arguments[1],s=arguments[2];return null==s&&o&&"object"==typeof o&&(s=o,o=null),null!=s&&n(r,s),r.message=String(t),null!=o&&(r.code=String(o)),i&&i(r,e),r}},function(t,e,r){"use strict";t.exports=r(82)()?Object.assign:r(83)},function(t,e){"use strict";t.exports=function(){var t,e=Object.assign;return"function"!=typeof e?!1:(t={foo:"raz"},e(t,{bar:"dwa"},{trzy:"trzy"}),t.foo+t.bar+t.trzy==="razdwatrzy")}},function(t,e,r){"use strict";var n=r(84),i=r(77),o=Math.max;t.exports=function(t,e){var r,s,a,c=o(arguments.length,2);for(t=Object(i(t)),a=function(n){try{t[n]=e[n]}catch(i){r||(r=i)}},s=1;c>s;++s)e=arguments[s],n(e).forEach(a);if(void 0!==r)throw r;return t}},function(t,e,r){"use strict";t.exports=r(85)()?Object.keys:r(86)},function(t,e){"use strict";t.exports=function(){try{return Object.keys("primitive"),!0}catch(t){return!1}}},function(t,e){"use strict";var r=Object.keys;t.exports=function(t){return r(null==t?t:Object(t))}},function(t,e,r){"use strict";var n,i,o,s,a=r(68),c=function(t,e){};try{Object.defineProperty(c,"length",{configurable:!0,writable:!1,enumerable:!1,value:1})}catch(u){}1===c.length?(n={configurable:!0,writable:!1,enumerable:!1},i=Object.defineProperty,t.exports=function(t,e){return e=a(e),t.length===e?t:(n.value=e,i(t,"length",n))}):(s=r(88),o=function(){var t=[];return function(e){var r,n=0;if(t[e])return t[e];for(r=[];e--;)r.push("a"+(++n).toString(36));return new Function("fn","return function ("+r.join(", ")+") { return fn.apply(this, arguments); };")}}(),t.exports=function(t,e){var r;if(e=a(e),t.length===e)return t;r=o(e)(t);try{s(r,t)}catch(n){}return r})},function(t,e,r){"use strict";var n=r(77),i=Object.defineProperty,o=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames;t.exports=function(t,e){var r;if(t=Object(n(t)),s(Object(n(e))).forEach(function(n){try{i(t,n,o(e,n))}catch(s){r=s}}),void 0!==r)throw r;return t}},function(t,e,r){"use strict";var n,i=r(81),o=r(66),s=r(90),a=r(91);n=t.exports=function(t,e){var r,n,s,c,u;return arguments.length<2||"string"!=typeof t?(c=e,e=t,t=null):c=arguments[2],null==t?(r=s=!0,n=!1):(r=a.call(t,"c"),n=a.call(t,"e"),s=a.call(t,"w")),u={value:e,configurable:r,enumerable:n,writable:s},c?i(o(c),u):u},n.gs=function(t,e,r){var n,c,u,l;return"string"!=typeof t?(u=r,r=e,e=t,t=null):u=arguments[3],null==e?e=void 0:s(e)?null==r?r=void 0:s(r)||(u=r,r=void 0):(u=e,e=r=void 0),null==t?(n=!0,c=!1):(n=a.call(t,"c"),c=a.call(t,"e")),l={get:e,set:r,configurable:n,enumerable:c},u?i(o(u),l):l}},function(t,e){"use strict";t.exports=function(t){return"function"==typeof t}},function(t,e,r){"use strict";t.exports=r(92)()?String.prototype.contains:r(93)},function(t,e){"use strict";var r="razdwatrzy";t.exports=function(){return"function"!=typeof r.contains?!1:r.contains("dwa")===!0&&r.contains("foo")===!1}},function(t,e){"use strict";var r=String.prototype.indexOf;t.exports=function(t){return r.call(this,t,arguments[1])>-1}},function(t,e,r){"use strict";var n,i,o,s,a,c,u,l=r(89),h=r(74),f=Function.prototype.apply,p=Function.prototype.call,d=Object.create,g=Object.defineProperty,_=Object.defineProperties,m=Object.prototype.hasOwnProperty,b={configurable:!0,enumerable:!1,writable:!0};n=function(t,e){var r;return h(e),m.call(this,"__ee__")?r=this.__ee__:(r=b.value=d(null),g(this,"__ee__",b),b.value=null),r[t]?"object"==typeof r[t]?r[t].push(e):r[t]=[r[t],e]:r[t]=e,this},i=function(t,e){var r,i;return h(e),i=this,n.call(this,t,r=function(){o.call(i,t,r),f.call(e,this,arguments)}),r.__eeOnceListener__=e,this},o=function(t,e){var r,n,i,o;if(h(e),!m.call(this,"__ee__"))return this;if(r=this.__ee__,!r[t])return this;if(n=r[t],"object"==typeof n)for(o=0;i=n[o];++o)i!==e&&i.__eeOnceListener__!==e||(2===n.length?r[t]=n[o?0:1]:n.splice(o,1));else n!==e&&n.__eeOnceListener__!==e||delete r[t];return this},s=function(t){var e,r,n,i,o;if(m.call(this,"__ee__")&&(i=this.__ee__[t]))if("object"==typeof i){for(r=arguments.length,o=new Array(r-1),e=1;r>e;++e)o[e-1]=arguments[e];for(i=i.slice(),e=0;n=i[e];++e)f.call(n,this,o)}else switch(arguments.length){case 1:p.call(i,this);break;case 2:p.call(i,this,arguments[1]);break;case 3:p.call(i,this,arguments[1],arguments[2]);break;default:for(r=arguments.length,o=new Array(r-1),e=1;r>e;++e)o[e-1]=arguments[e];f.call(i,this,o)}},a={on:n,once:i,off:o,emit:s},c={on:l(n),once:l(i),off:l(o),emit:l(s)},u=_({},c),t.exports=e=function(t){return null==t?d(u):_(Object(t),c)},e.methods=a},function(t,e,r){"use strict";var n,i=r(96),o=r(74),s=Array.prototype.slice;n=function(t){return this.map(function(e,r){return e?e(t[r]):t[r]}).concat(s.call(t,this.length))},t.exports=function(t){return t=i(t),t.forEach(function(t){null!=t&&o(t)}),n.bind(t)}},function(t,e,r){"use strict";var n=r(97),i=Array.isArray;t.exports=function(t){return i(t)?t:n(t)}},function(t,e,r){"use strict";t.exports=r(98)()?Array.from:r(99)},function(t,e){"use strict";t.exports=function(){var t,e,r=Array.from;return"function"!=typeof r?!1:(t=["raz","dwa"],e=r(t),Boolean(e&&e!==t&&"dwa"===e[1]))}},function(t,e,r){"use strict";var n=r(100).iterator,i=r(105),o=r(106),s=r(68),a=r(74),c=r(77),u=r(108),l=Array.isArray,h=Function.prototype.call,f={configurable:!0,enumerable:!0,writable:!0,value:null},p=Object.defineProperty;t.exports=function(t){var e,r,d,g,_,m,b,y,v,w,S=arguments[1],x=arguments[2];if(t=Object(c(t)),null!=S&&a(S),this&&this!==Array&&o(this))e=this;else{if(!S){if(i(t))return _=t.length,1!==_?Array.apply(null,t):(g=new Array(1),g[0]=t[0],g);if(l(t)){for(g=new Array(_=t.length),r=0;_>r;++r)g[r]=t[r];return g}}g=[]}if(!l(t))if(void 0!==(v=t[n])){for(b=a(v).call(t),e&&(g=new e),y=b.next(),r=0;!y.done;)w=S?h.call(S,x,y.value,r):y.value,e?(f.value=w,p(g,r,f)):g[r]=w,y=b.next(),++r;_=r}else if(u(t)){for(_=t.length,e&&(g=new e),r=0,d=0;_>r;++r)w=t[r],_>r+1&&(m=w.charCodeAt(0),m>=55296&&56319>=m&&(w+=t[++r])),w=S?h.call(S,x,w,d):w,e?(f.value=w,p(g,d,f)):g[d]=w,++d;_=d}if(void 0===_)for(_=s(t.length),e&&(g=new e(_)),r=0;_>r;++r)w=S?h.call(S,x,t[r],r):t[r],e?(f.value=w,p(g,r,f)):g[r]=w;return e&&(f.value=null,g.length=_),g}},function(t,e,r){"use strict";t.exports=r(101)()?Symbol:r(102)},function(t,e){"use strict";t.exports=function(){var t;if("function"!=typeof Symbol)return!1;t=Symbol("test symbol");try{String(t)}catch(e){return!1}return"symbol"==typeof Symbol.iterator?!0:"object"!=typeof Symbol.isConcatSpreadable?!1:"object"!=typeof Symbol.iterator?!1:"object"!=typeof Symbol.toPrimitive?!1:"object"!=typeof Symbol.toStringTag?!1:"object"==typeof Symbol.unscopables}},function(t,e,r){"use strict";var n,i,o,s=r(89),a=r(103),c=Object.create,u=Object.defineProperties,l=Object.defineProperty,h=Object.prototype,f=c(null);"function"==typeof Symbol&&(n=Symbol);var p=function(){var t=c(null);return function(e){for(var r,n,i=0;t[e+(i||"")];)++i;return e+=i||"",t[e]=!0,r="@@"+e,l(h,r,s.gs(null,function(t){n||(n=!0,l(this,r,s(t)),n=!1)})),r}}();o=function(t){if(this instanceof o)throw new TypeError("TypeError: Symbol is not a constructor");return i(t)},t.exports=i=function d(t){var e;if(this instanceof d)throw new TypeError("TypeError: Symbol is not a constructor");return e=c(o.prototype),t=void 0===t?"":String(t),u(e,{__description__:s("",t),__name__:s("",p(t))})},u(i,{"for":s(function(t){return f[t]?f[t]:f[t]=i(String(t))}),keyFor:s(function(t){var e;a(t);for(e in f)if(f[e]===t)return e}),hasInstance:s("",n&&n.hasInstance||i("hasInstance")),isConcatSpreadable:s("",n&&n.isConcatSpreadable||i("isConcatSpreadable")),iterator:s("",n&&n.iterator||i("iterator")),match:s("",n&&n.match||i("match")),replace:s("",n&&n.replace||i("replace")),search:s("",n&&n.search||i("search")),species:s("",n&&n.species||i("species")),split:s("",n&&n.split||i("split")),toPrimitive:s("",n&&n.toPrimitive||i("toPrimitive")),toStringTag:s("",n&&n.toStringTag||i("toStringTag")),unscopables:s("",n&&n.unscopables||i("unscopables"))}),u(o.prototype,{constructor:s(i),toString:s("",function(){return this.__name__})}),u(i.prototype,{toString:s(function(){return"Symbol ("+a(this).__description__+")"}),valueOf:s(function(){return a(this)})}),l(i.prototype,i.toPrimitive,s("",function(){return a(this)})),l(i.prototype,i.toStringTag,s("c","Symbol")),l(o.prototype,i.toStringTag,s("c",i.prototype[i.toStringTag])),l(o.prototype,i.toPrimitive,s("c",i.prototype[i.toPrimitive]))},function(t,e,r){"use strict";var n=r(104);t.exports=function(t){if(!n(t))throw new TypeError(t+" is not a symbol");return t}},function(t,e){"use strict";t.exports=function(t){return t&&("symbol"==typeof t||"Symbol"===t["@@toStringTag"])||!1}},function(t,e){"use strict";var r=Object.prototype.toString,n=r.call(function(){return arguments}());t.exports=function(t){return r.call(t)===n}},function(t,e,r){"use strict";var n=Object.prototype.toString,i=n.call(r(107));t.exports=function(t){return"function"==typeof t&&n.call(t)===i}},function(t,e){"use strict";t.exports=function(){}},function(t,e){"use strict";var r=Object.prototype.toString,n=r.call("");t.exports=function(t){return"string"==typeof t||t&&"object"==typeof t&&(t instanceof String||r.call(t)===n)||!1}},function(t,e,r){"use strict";var n=r(74);t.exports=function(t){var e;return"function"==typeof t?{set:t,get:t}:(e={get:n(t.get)},void 0!==t.set?(e.set=n(t.set),e["delete"]=n(t["delete"]),e.clear=n(t.clear),e):(e.set=e.get,e))}},function(t,e){"use strict";t.exports=function(t){var e,r,n=t.length;if(!n)return"";for(e=String(t[r=0]);--n;)e+=""+t[++r];return e}},function(t,e){"use strict";t.exports=function(t){return t?function(e){for(var r=String(e[0]),n=0,i=t;--i;)r+=""+e[++n];return r}:function(){return""}}},function(t,e,r){"use strict";var n=r(113),i=Object.create;t.exports=function(){var t=0,e=[],r=i(null);return{get:function(t){var r,i=0,o=e,s=t.length;if(0===s)return o[s]||null;if(o=o[s]){for(;s-1>i;){if(r=n.call(o[0],t[i]),-1===r)return null;o=o[1][r],++i}return r=n.call(o[0],t[i]),-1===r?null:o[1][r]||null}return null},set:function(i){var o,s=0,a=e,c=i.length;if(0===c)a[c]=++t;else{for(a[c]||(a[c]=[[],[]]),a=a[c];c-1>s;)o=n.call(a[0],i[s]),-1===o&&(o=a[0].push(i[s])-1,a[1].push([[],[]])),a=a[1][o],++s;o=n.call(a[0],i[s]),-1===o&&(o=a[0].push(i[s])-1),a[1][o]=++t}return r[t]=i,t},"delete":function(t){var i,o=0,s=e,a=r[t],c=a.length,u=[];if(0===c)delete s[c];else if(s=s[c]){for(;c-1>o;){if(i=n.call(s[0],a[o]),-1===i)return;u.push(s,i),s=s[1][i],++o}if(i=n.call(s[0],a[o]),-1===i)return;for(t=s[1][i],s[0].splice(i,1),s[1].splice(i,1);!s[0].length&&u.length;)i=u.pop(),s=u.pop(),s[0].splice(i,1),s[1].splice(i,1)}delete r[t]},clear:function(){e=[],r=i(null)}}}},function(t,e,r){"use strict";var n=r(68),i=r(77),o=Array.prototype.indexOf,s=Object.prototype.hasOwnProperty,a=Math.abs,c=Math.floor;t.exports=function(t){var e,r,u,l;if(t===t)return o.apply(this,arguments);for(r=n(i(this).length),u=arguments[1],u=isNaN(u)?0:u>=0?c(u):n(this.length)-c(a(u)),e=u;r>e;++e)if(s.call(this,e)&&(l=this[e],l!==l))return e;return-1}},function(t,e,r){"use strict";var n=r(113);t.exports=function(){var t=0,e=[],r=[];return{get:function(t){var i=n.call(e,t[0]);return-1===i?null:r[i]},set:function(n){return e.push(n[0]),r.push(++t),t},"delete":function(t){var i=n.call(r,t);-1!==i&&(e.splice(i,1),r.splice(i,1))},clear:function(){e=[],r=[]}}}},function(t,e,r){"use strict";var n=r(113),i=Object.create;t.exports=function(t){var e=0,r=[[],[]],o=i(null);return{get:function(e){for(var i,o=0,s=r;t-1>o;){if(i=n.call(s[0],e[o]),-1===i)return null;s=s[1][i],++o}return i=n.call(s[0],e[o]),-1===i?null:s[1][i]||null},set:function(i){for(var s,a=0,c=r;t-1>a;)s=n.call(c[0],i[a]),-1===s&&(s=c[0].push(i[a])-1,c[1].push([[],[]])),c=c[1][s],++a;return s=n.call(c[0],i[a]),-1===s&&(s=c[0].push(i[a])-1),c[1][s]=++e,o[e]=i,e},"delete":function(e){for(var i,s=0,a=r,c=[],u=o[e];t-1>s;){if(i=n.call(a[0],u[s]),-1===i)return;c.push(a,i),a=a[1][i],++s}if(i=n.call(a[0],u[s]),-1!==i){for(e=a[1][i],a[0].splice(i,1),a[1].splice(i,1);!a[0].length&&c.length;)i=c.pop(),a=c.pop(),a[0].splice(i,1),a[1].splice(i,1);delete o[e]}},clear:function(){r=[[],[]],o=i(null)}}}},function(t,e,r){"use strict";var n=r(97),i=r(88),o=r(87),s=r(117),a=Array.prototype.slice,c=Function.prototype.apply,u=Object.create,l=Object.prototype.hasOwnProperty;r(78).async=function(t,e){var r,h,f,p=u(null),d=u(null),g=e.memoized,_=e.original;e.memoized=o(function(t){var e=arguments,n=e[e.length-1];return"function"==typeof n&&(r=n,e=a.call(e,0,-1)),g.apply(h=this,f=e)},g);try{i(e.memoized,g)}catch(m){}e.on("get",function(t){var n,i,o;if(r){if(p[t])return"function"==typeof p[t]?p[t]=[p[t],r]:p[t].push(r),void(r=null);n=r,i=h,o=f,r=h=f=null,s(function(){var s;l.call(d,t)?(s=d[t],e.emit("getasync",t,o,i),c.call(n,s.context,s.args)):(r=n,h=i,f=o,g.apply(i,o))})}}),e.original=function(){var t,i,o,a;return r?(t=n(arguments),i=function u(t){var r,i,o=u.id;return null==o?void s(c.bind(u,this,arguments)):(delete u.id,r=p[o],delete p[o],r?(i=n(arguments),e.has(o)&&(t?e["delete"](o):(d[o]={context:this,args:i},e.emit("setasync",o,"function"==typeof r?1:r.length))),"function"==typeof r?a=c.call(r,this,i):r.forEach(function(t){a=c.call(t,this,i)},this),a):void 0)},o=r,r=h=f=null,t.push(i),a=c.call(_,this,t),i.cb=o,r=i,a):c.call(_,this,arguments)},e.on("set",function(t){return r?(p[t]?"function"==typeof p[t]?p[t]=[p[t],r.cb]:p[t].push(r.cb):p[t]=r.cb,delete r.cb,r.id=t,void(r=null)):void e["delete"](t)}),e.on("delete",function(t){var r;l.call(p,t)||d[t]&&(r=d[t],delete d[t],e.emit("deleteasync",t,r))}),e.on("clear",function(){var t=d;d=u(null),e.emit("clearasync",t)})}},function(t,e,r){(function(e,r){"use strict";var n,i;n=function(t){if("function"!=typeof t)throw new TypeError(t+" is not a function");return t},i=function(t){var e,r=document.createTextNode(""),i=0;return new t(function(){var t;if(e)return t=e,e=null,"function"==typeof t?void t():void t.forEach(function(t){t()})}).observe(r,{characterData:!0}),function(t){return n(t),e?void("function"==typeof e?e=[e,t]:e.push(t)):(e=t,void(r.data=i=++i%2))}},t.exports=function(){if("undefined"!=typeof e&&e&&"function"==typeof e.nextTick)return e.nextTick;if("object"==typeof document&&document){if("function"==typeof MutationObserver)return i(MutationObserver);if("function"==typeof WebKitMutationObserver)return i(WebKitMutationObserver)}return"function"==typeof r?function(t){r(n(t))}:"function"==typeof setTimeout?function(t){setTimeout(n(t),0)}:null}()}).call(e,r(3),r(118).setImmediate)},function(t,e,r){(function(t,n){function i(t,e){this._id=t,this._clearFn=e}var o=r(3).nextTick,s=Function.prototype.apply,a=Array.prototype.slice,c={},u=0;e.setTimeout=function(){return new i(s.call(setTimeout,window,arguments),clearTimeout)},e.setInterval=function(){return new i(s.call(setInterval,window,arguments),clearInterval)},e.clearTimeout=e.clearInterval=function(t){t.close()},i.prototype.unref=i.prototype.ref=function(){},i.prototype.close=function(){this._clearFn.call(window,this._id)},e.enroll=function(t,e){clearTimeout(t._idleTimeoutId),t._idleTimeout=e},e.unenroll=function(t){clearTimeout(t._idleTimeoutId),t._idleTimeout=-1},e._unrefActive=e.active=function(t){clearTimeout(t._idleTimeoutId);var e=t._idleTimeout;e>=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},e.setImmediate="function"==typeof t?t:function(t){var r=u++,n=arguments.length<2?!1:a.call(arguments,1);return c[r]=!0,o(function(){c[r]&&(n?t.apply(null,n):t.call(null),e.clearImmediate(r))}),r},e.clearImmediate="function"==typeof n?n:function(t){delete c[t]}}).call(e,r(118).setImmediate,r(118).clearImmediate)},function(t,e,r){"use strict";var n=r(74),i=r(75),o=r(78),s=Array.prototype.slice,a=Function.prototype.apply;o.dispose=function(t,e,r){var c;return n(t),r.async&&o.async?(e.on("deleteasync",c=function(e,r){a.call(t,null,s.call(r.args,1))}),void e.on("clearasync",function(t){i(t,function(t,e){c(e,t)})})):(e.on("delete",c=function(e,r){t(r)}),void e.on("clear",function(t){i(t,function(t,e){c(e,t)})}))}},function(t,e,r){"use strict";var n=r(97),i=r(107),o=r(75),s=r(121),a=r(78),c=Math.max,u=Math.min,l=Object.create;a.maxAge=function(t,e,r){var h,f,p,d;t=s(t),t&&(h=l(null),f=r.async&&a.async?"async":"",e.on("set"+f,function(r){h[r]=setTimeout(function(){e["delete"](r)},t),d&&(d[r]&&clearTimeout(d[r]),d[r]=setTimeout(function(){delete d[r]},p))}),e.on("delete"+f,function(t){clearTimeout(h[t]),delete h[t],d&&(clearTimeout(d[t]),delete d[t])}),r.preFetch&&(p=r.preFetch===!0||isNaN(r.preFetch)?.333:c(u(Number(r.preFetch),1),0),p&&(d={},p=(1-p)*t,e.on("get"+f,function(t,o,s){d[t]||(d[t]=setTimeout(function(){delete d[t],e["delete"](t),r.async&&(o=n(o),o.push(i)),e.memoized.apply(s,o)},0))}))),e.on("clear"+f,function(){o(h,function(t){clearTimeout(t)}),h={},d&&(o(d,function(t){clearTimeout(t)}),d={})}))}},function(t,e,r){"use strict";var n=r(68),i=r(122);t.exports=function(t){if(t=n(t),t>i)throw new TypeError(t+" exceeds maximum possible timeout");return t}},function(t,e){"use strict";t.exports=2147483647},function(t,e,r){"use strict";var n=r(68),i=r(124),o=r(78);o.max=function(t,e,r){var s,a,c;t=n(t),t&&(a=i(t),s=r.async&&o.async?"async":"",e.on("set"+s,c=function(t){t=a.hit(t),void 0!==t&&e["delete"](t)}),e.on("get"+s,c),e.on("delete"+s,a["delete"]),e.on("clear"+s,a.clear))}},function(t,e,r){"use strict";var n=r(68),i=Object.create,o=Object.prototype.hasOwnProperty;t.exports=function(t){var e,r=0,s=1,a=i(null),c=i(null),u=0;return t=n(t),{hit:function(n){var i=c[n],l=++u;if(a[l]=n,c[n]=l,!i){if(++r,t>=r)return;return n=a[s],e(n),n}if(delete a[i],s===i)for(;!o.call(a,++s);)continue},"delete":e=function(t){var e=c[t];if(e&&(delete a[e],delete c[t],--r,s===e)){if(!r)return u=0,void(s=1);for(;!o.call(a,++s);)continue}},clear:function(){r=0,s=1,a=i(null),c=i(null),u=0}}}},function(t,e,r){"use strict";var n=r(89),i=r(78),o=Object.create,s=Object.defineProperties;i.refCounter=function(t,e,r){var a,c;a=o(null),c=r.async&&i.async?"async":"",e.on("set"+c,function(t,e){a[t]=e||1}),e.on("get"+c,function(t){++a[t]}),e.on("delete"+c,function(t){delete a[t]}),e.on("clear"+c,function(){a={}}),s(e.memoized,{deleteRef:n(function(){var t=e.get(arguments);return null===t?null:a[t]?--a[t]?!1:(e["delete"](t),!0):null}),getRefCount:n(function(){ -var t=e.get(arguments);return null===t?0:a[t]?a[t]:0})})}}]); \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 6badafd2f..d46f55bf6 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,13 +1,12 @@ +var CopyWebpackPlugin = require('copy-webpack-plugin'); +var defaultsDeep = require('lodash.defaultsdeep'); +var path = require('path'); var webpack = require('webpack'); -module.exports = { - entry: { - 'vm': './src/index.js', - 'vm.min': './src/index.js' - }, - output: { - path: __dirname, - filename: '[name].js' +var base = { + devServer: { + contentBase: path.resolve(__dirname, 'playground'), + host: '0.0.0.0' }, module: { loaders: [ @@ -27,3 +26,93 @@ module.exports = { }) ] }; + +module.exports = [ + // Web-compatible, playground + defaultsDeep({}, base, { + entry: { + 'vm': './src/index.js', + 'vm.min': './src/index.js' + }, + output: { + path: __dirname, + filename: '[name].js' + }, + module: { + loaders: base.module.loaders.concat([ + { + test: require.resolve('./src/index.js'), + loader: 'expose?VirtualMachine' + } + ]) + } + }), + // Webpack-compatible + defaultsDeep({}, base, { + entry: { + 'dist': './src/index.js' + }, + + output: { + library: 'VirtualMachine', + libraryTarget: 'commonjs2', + path: __dirname, + filename: '[name].js' + } + }), + // Playground + defaultsDeep({}, base, { + entry: { + 'vm': './src/index.js', + 'vendor': [ + // FPS counter + 'stats.js/build/stats.min.js', + // Syntax highlighter + 'highlightjs/highlight.pack.min.js', + // Scratch Blocks + 'scratch-blocks/dist/vertical.js', + // Renderer + 'scratch-render' + ] + }, + output: { + path: path.resolve(__dirname, 'playground'), + filename: '[name].js' + }, + module: { + loaders: base.module.loaders.concat([ + { + test: require.resolve('./src/index.js'), + loader: 'expose?VirtualMachine' + }, + { + test: require.resolve('stats.js/build/stats.min.js'), + loader: 'script' + }, + { + test: require.resolve('highlightjs/highlight.pack.min.js'), + loader: 'script' + }, + { + test: require.resolve('scratch-blocks/dist/vertical.js'), + loader: 'expose?Blockly' + }, + { + test: require.resolve('scratch-render'), + loader: 'expose?RenderWebGL' + } + ]) + }, + plugins: base.plugins.concat([ + new CopyWebpackPlugin([{ + from: 'node_modules/scratch-blocks/media', + to: 'media' + }, { + from: 'node_modules/highlightjs/styles/zenburn.css' + }, { + from: 'assets', + to: 'assets' + }]) + ]) + }) +];