diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..66581ed --- /dev/null +++ b/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": [ + [ + "es2015", + { + "modules": false + } + ] + ], + "compact": true, +} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..126b9d1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +node_modules +.esm-cache diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..da8b87d --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +node_modules/ +public/ +.esm-cache +*hterm* diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..91a8f51 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,36 @@ +module.exports = { + env: { + es6 : true, + node: true, + }, + extends: ['airbnb'], + rules : { + 'linebreak-style' : ['error', 'unix'], + 'arrow-parens' : ['error', 'as-needed'], + 'no-param-reassign' : ['error', { props: false }], + 'func-style' : ['error', 'declaration', { allowArrowFunctions: true }], + 'no-use-before-define': ['error', { functions: false }], + 'no-shadow' : [ + 'error', + { + builtinGlobals: true, + hoist : 'functions', + allow : ['resolve', 'reject', 'err'], + }, + ], + 'no-console': [ + 'error', + { + allow: ['warn', 'trace', 'log', 'error'], + }, + ], + 'consistent-return': 0, + 'key-spacing' : [ + 'error', + { + multiLine: { beforeColon: false, afterColon: true }, + align : { beforeColon: false, afterColon: true, on: 'colon', mode: 'strict' }, + }, + ], + }, +}; diff --git a/.gitignore b/.gitignore index 03fe0f5..38311e2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ logs results npm-debug.log -node_modules/* \ No newline at end of file +node_modules/* +.esm-cache diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..31df1f2 --- /dev/null +++ b/.npmignore @@ -0,0 +1,21 @@ +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz + +tmp +pids +logs +results + +npm-debug.log +node_modules/* +.esm-cache +src +*.yml +Dockerfile +*.png diff --git a/Dockerfile b/Dockerfile index e223817..2dafc6e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,9 @@ -FROM node:0.10.38 -MAINTAINER Nathan LeClaire - -ADD . /app +FROM node:8-alpine +MAINTAINER butlerx@notthe.cloud WORKDIR /app -RUN npm install -RUN apt-get update -RUN apt-get install -y vim -RUN useradd -d /home/term -m -s /bin/bash term -RUN echo 'term:term' | chpasswd - +RUN adduser -D -h /home/term -s /bin/sh term && \ + echo "term:term" | chpasswd EXPOSE 3000 - -ENTRYPOINT ["node"] -CMD ["app.js", "-p", "3000"] +COPY . /app +RUN apk add --update build-base python openssh && yarn +CMD yarn start diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index ab9b1af..0000000 --- a/Gruntfile.js +++ /dev/null @@ -1,37 +0,0 @@ -module.exports = function (grunt) { - - require('load-grunt-tasks')(grunt); - - var config = { - mkdir: { - tmp: { - options: { - create: ['tmp'] - } - } - }, - gitclone: { - hterm: { - options: { - cwd: './tmp', - repository: 'https://chromium.googlesource.com/apps/libapps' - } - } - }, - shell: { - build_hterm: { - command: 'LIBDOT_SEARCH_PATH=$(pwd) ./libdot/bin/concat.sh -i ./hterm/concat/hterm_all.concat -o ../../public/wetty/hterm_all.js', - options: { - execOptions: { - cwd: './tmp/libapps' - } - } - } - }, - clean: ['./tmp'] - }; - - grunt.initConfig(config); - - grunt.registerTask('update-hterm', ['mkdir:tmp', 'gitclone:hterm', 'shell:build_hterm', 'clean']); -}; diff --git a/LICENSE b/LICENSE index be2f4e6..10fc4ba 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -The MIT License (MIT) +MIT License Copyright (c) 2014 Krishna Srinivas @@ -18,4 +18,4 @@ 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. \ No newline at end of file +SOFTWARE. diff --git a/README.md b/README.md index c49408e..0f1b48b 100644 --- a/README.md +++ b/README.md @@ -1,111 +1,173 @@ -Wetty = Web + tty ------------------ +## Wetty = Web + tty -Terminal over HTTP and HTTPS. Wetty is an alternative to -ajaxterm/anyterm but much better than them because wetty uses ChromeOS' -terminal emulator (hterm) which is a full fledged implementation of -terminal emulation written entirely in Javascript. Also it uses -websockets instead of Ajax and hence better response time. +Terminal over HTTP and HTTPS. Wetty is an alternative to ajaxterm/anyterm but +much better than them because wetty uses ChromeOS' terminal emulator (hterm) +which is a full fledged implementation of terminal emulation written entirely in +Javascript. Also it uses websockets instead of Ajax and hence better response +time. -hterm source - https://chromium.googlesource.com/apps/libapps/+/master/hterm/ +[hterm source](https://chromium.googlesource.com/apps/libapps/+/master/hterm/) ![Wetty](/terminal.png?raw=true) -Install -------- +## Install -* `git clone https://github.com/krishnasrinivas/wetty` +* `git clone https://github.com/krishnasrinivas/wetty` +* `cd wetty` +* `yarn` -* `cd wetty` +or -* `npm install` +`yarn add wetty` -Run on HTTP: ------------ +## Run on HTTP - node app.js -p 3000 +```bash +node bin/index.js -p 3000 +``` -If you run it as root it will launch `/bin/login` (where you can specify -the user name), else it will launch `ssh` and connect by default to -`localhost`. +If you run it as root it will launch `/bin/login` (where you can specify the +user name), else it will launch `ssh` and connect by default to `localhost`. -If instead you wish to connect to a remote host you can specify the -`--sshhost` option, the SSH port using the `--sshport` option and the -SSH user using the `--sshuser` option. +If instead you wish to connect to a remote host you can specify the `--sshhost` +option, the SSH port using the `--sshport` option and the SSH user using the +`--sshuser` option. You can also specify the SSH user name in the address bar like this: - `http://yourserver:3000/wetty/ssh/` +`http://yourserver:3000/wetty/ssh/` + +or -Run on HTTPS: ------------- +`http://yourserver:3000/ssh/` -Always use HTTPS! If you don't have SSL certificates from a CA you can -create a self signed certificate using this command: +## Run on HTTPS - `openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 30000 -nodes` +Always use HTTPS. If you don't have SSL certificates from a CA you can create a +self signed certificate using this command: + +``` +openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 30000 -nodes +``` And then run: - node app.js --sslkey key.pem --sslcert cert.pem -p 3000 +``` +node bin/index.js --sslkey key.pem --sslcert cert.pem -p 3000 +``` -Again, if you run it as root it will launch `/bin/login`, else it will -launch SSH to `localhost` or a specified host as explained above. +Again, if you run it as root it will launch `/bin/login`, else it will launch +SSH to `localhost` or a specified host as explained above. -Run wetty behind nginx: ----------------------- +## Run wetty behind nginx or apache Put the following configuration in nginx's conf: location /wetty { - proxy_pass http://127.0.0.1:3000/wetty; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_read_timeout 43200000; - - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; - proxy_set_header X-NginX-Proxy true; + proxy_pass http://127.0.0.1:3000/wetty; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 43200000; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header X-NginX-Proxy true; } -If you are running `app.js` as `root` and have an Nginx proxy you have to use: +Put the following configuration in apache's conf: - http://yourserver.com/wetty + RewriteCond %{REQUEST_URI} ^/wetty/socket.io [NC] + RewriteCond %{QUERY_STRING} transport=websocket [NC] + RewriteRule /wetty/socket.io/(.*) ws://localhost:9123/wetty/socket.io/$1 [P,L] -Else if you are running `app.js` as a regular user you have to use: + + DirectorySlash On + Require all granted + ProxyPassMatch http://127.0.0.1:9123 + ProxyPassReverse /wetty/ + - http://yourserver.com/wetty/ssh/ +If you are running `bin/index.js` as `root` and have an Nginx proxy you have to +use: -**Note that if your Nginx is configured for HTTPS you should run wetty without SSL.** +``` +http://yourserver.com/wetty +``` -Dockerized Version ------------------- +Else if you are running `bin/index.js` as a regular user you can use: -This repo includes a Dockerfile you can use to run a Dockerized version of wetty. You can run -whatever you want! +``` +http://yourserver.com/wetty/ssh/ +``` -Just do: +or ``` - docker run --name term -p 3000 -dt krishnasrinivas/wetty +http://yourserver.com/wetty ``` -Visit the appropriate URL in your browser (`[localhost|$(boot2docker ip)]:PORT`). -The username is `term` and the password is `term`. +**Note that if your Nginx is configured for HTTPS you should run wetty without +SSL.** + +## Dockerized Version -Run wetty as a service daemon ------------------------------ +This repo includes a Dockerfile you can use to run a Dockerized version of +wetty. You can run whatever you want! + +Just modify docker-compose and run: + +``` +docker-compose up -d +``` -Install wetty globally with -g option: +Visit the appropriate URL in your browser +(`[localhost|$(boot2docker ip)]:PORT`). + +The default username is `term` and the password is `term`, if you did not modify +`SSHHOST` + +If you dont want to build the image yourself just remove the line `build; .` + +## Run wetty as a service daemon + +Install wetty globally with global option: + +### init.d + +```bash +$ sudo yarn global add wetty +$ sudo cp /usr/local/lib/node_modules/wetty.js/bin/wetty.conf /etc/init +$ sudo start wetty +``` + +### systemd ```bash - $ sudo npm install wetty -g - $ sudo cp /usr/local/lib/node_modules/wetty/bin/wetty.conf /etc/init - $ sudo start wetty +$ yarn global add wetty +$ cp ~/.config/yarn/global/node_modules/wetty.js/bin/wetty.service ~/.config/systemd/user/ +$ systemctl --user enable wetty +$ systemctl --user start wetty +``` + +This will start wetty on port 3000. If you want to change the port or redirect +stdout/stderr you should change the last line in `wetty.conf` file, something +like this: + ``` +exec sudo -u root wetty -p 80 >> /var/log/wetty.log 2>&1 +``` + +## FAQ + +### What browsers are supported? + +Wetty supports all browsers that Google's hterm supports. Wetty has been +[reported](https://github.com/krishnasrinivas/wetty/issues/45#issuecomment-181448586) +to work on Google Chrome, Firefox and IE 11. -This will start wetty on port 3000. If you want to change the port or redirect stdout/stderr you should change the last line in `wetty.conf` file, something like this: +### Why isn't Wetty working with IE? - exec sudo -u root wetty -p 80 >> /var/log/wetty.log 2>&1 +[This fix](https://stackoverflow.com/questions/13102116/access-denied-for-localstorage-in-ie10#20848924) +has been known to help some users. diff --git a/app.js b/app.js deleted file mode 100644 index da33a48..0000000 --- a/app.js +++ /dev/null @@ -1,134 +0,0 @@ -var express = require('express'); -var http = require('http'); -var https = require('https'); -var path = require('path'); -var server = require('socket.io'); -var pty = require('pty.js'); -var fs = require('fs'); - -var opts = require('optimist') - .options({ - sslkey: { - demand: false, - description: 'path to SSL key' - }, - sslcert: { - demand: false, - description: 'path to SSL certificate' - }, - sshhost: { - demand: false, - description: 'ssh server host' - }, - sshport: { - demand: false, - description: 'ssh server port' - }, - sshuser: { - demand: false, - description: 'ssh user' - }, - sshauth: { - demand: false, - description: 'defaults to "password", you can use "publickey,password" instead' - }, - port: { - demand: true, - alias: 'p', - description: 'wetty listen port' - }, - }).boolean('allow_discovery').argv; - -var runhttps = false; -var sshport = 22; -var sshhost = 'localhost'; -var sshauth = 'password,keyboard-interactive'; -var globalsshuser = ''; - -if (opts.sshport) { - sshport = opts.sshport; -} - -if (opts.sshhost) { - sshhost = opts.sshhost; -} - -if (opts.sshauth) { - sshauth = opts.sshauth -} - -if (opts.sshuser) { - globalsshuser = opts.sshuser; -} - -if (opts.sslkey && opts.sslcert) { - runhttps = true; - opts['ssl'] = {}; - opts.ssl['key'] = fs.readFileSync(path.resolve(opts.sslkey)); - opts.ssl['cert'] = fs.readFileSync(path.resolve(opts.sslcert)); -} - -process.on('uncaughtException', function(e) { - console.error('Error: ' + e); -}); - -var httpserv; - -var app = express(); -app.get('/wetty/ssh/:user', function(req, res) { - res.sendfile(__dirname + '/public/wetty/index.html'); -}); -app.use('/', express.static(path.join(__dirname, 'public'))); - -if (runhttps) { - httpserv = https.createServer(opts.ssl, app).listen(opts.port, function() { - console.log('https on port ' + opts.port); - }); -} else { - httpserv = http.createServer(app).listen(opts.port, function() { - console.log('http on port ' + opts.port); - }); -} - -var io = server(httpserv,{path: '/wetty/socket.io'}); -io.on('connection', function(socket){ - var sshuser = ''; - var request = socket.request; - console.log((new Date()) + ' Connection accepted.'); - if (match = request.headers.referer.match('/wetty/ssh/.+$')) { - sshuser = match[0].replace('/wetty/ssh/', '') + '@'; - } else if (globalsshuser) { - sshuser = globalsshuser + '@'; - } - - var term; - if (process.getuid() == 0) { - term = pty.spawn('/usr/bin/env', ['login'], { - name: 'xterm-256color', - cols: 80, - rows: 30 - }); - } else { - term = pty.spawn('ssh', [sshuser + sshhost, '-p', sshport, '-o', 'PreferredAuthentications=' + sshauth], { - name: 'xterm-256color', - cols: 80, - rows: 30 - }); - } - console.log((new Date()) + " PID=" + term.pid + " STARTED on behalf of user=" + sshuser) - term.on('data', function(data) { - socket.emit('output', data); - }); - term.on('exit', function(code) { - console.log((new Date()) + " PID=" + term.pid + " ENDED") - }); - socket.on('resize', function(data) { - term.resize(data.col, data.row); - }); - socket.on('input', function(data) { - term.write(data); - }); - socket.on('disconnect', function() { - term.end(); - }); -}) diff --git a/bin/index.js b/bin/index.js new file mode 100644 index 0000000..a24a2ac --- /dev/null +++ b/bin/index.js @@ -0,0 +1,3 @@ +#! /usr/bin/env node +require = require('@std/esm')(module); // eslint-disable-line no-global-assign +require('../cli.mjs'); diff --git a/bin/ssh b/bin/ssh new file mode 100755 index 0000000..2ee4207 --- /dev/null +++ b/bin/ssh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +userAtAddress="$1" +USER=$(echo "$userAtAddress" | cut -d"@" -f1); +HOST=$(echo "$userAtAddress" | cut -d"@" -f2); + +if [ "$USER" = "$HOST" ] +then + printf "Enter your username: " + read -r USER + USER=$(echo "${USER}" | tr -d '[:space:]') + ssh "$USER"@"$HOST" +else + ssh "$userAtAddress" +fi diff --git a/bin/wetty.js b/bin/wetty.js deleted file mode 100644 index 16e2dea..0000000 --- a/bin/wetty.js +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node - -require("../app"); diff --git a/bin/wetty.service b/bin/wetty.service index dd79a27..1eff15e 100644 --- a/bin/wetty.service +++ b/bin/wetty.service @@ -9,11 +9,9 @@ Description=Wetty Web Terminal After=network.target [Service] -User=root -Group=root -WorkingDirectory=/home/akadmin/pack/wetty # CHANGE ME -ExecStart=/usr/bin/node app.js -p 9123 --host 127.0.0.1 +WorkingDirectory=$HOME/.config/yarn/global/node_modules/wetty.js/ +ExecStart=/usr/bin/node app.js -p 3000 --host 127.0.0.1 [Install] WantedBy=multi-user.target diff --git a/cli.mjs b/cli.mjs new file mode 100644 index 0000000..2f14363 --- /dev/null +++ b/cli.mjs @@ -0,0 +1,95 @@ +import fs from 'fs-extra'; +import path from 'path'; +import optimist from 'optimist'; +import wetty from './wetty'; + +const opts = optimist + .options({ + sslkey: { + demand : false, + description: 'path to SSL key', + }, + sslcert: { + demand : false, + description: 'path to SSL certificate', + }, + sshhost: { + demand : false, + description: 'ssh server host', + }, + sshport: { + demand : false, + description: 'ssh server port', + }, + sshuser: { + demand : false, + description: 'ssh user', + }, + sshauth: { + demand : false, + description: 'defaults to "password", you can use "publickey,password" instead', + }, + port: { + demand : false, + alias : 'p', + description: 'wetty listen port', + }, + help: { + demand : false, + alias : 'h', + description: 'Print help message', + }, + }) + .boolean('allow_discovery').argv; + +if (opts.help) { + optimist.showHelp(); + process.exit(0); +} + +const sshuser = opts.sshuser || process.env.SSHUSER || ''; +const sshhost = opts.sshhost || process.env.SSHHOST || 'localhost'; +const sshauth = opts.sshauth || process.env.SSHAUTH || 'password,keyboard-interactive'; +const sshport = opts.sshport || process.env.SSHPOST || 22; +const port = opts.port || process.env.PORT || 3000; + +loadSSL(opts) + .then(ssl => { + opts.ssl = ssl; + }) + .catch(err => { + console.error(`Error: ${err}`); + process.exit(1); + }); + +process.on('uncaughtException', err => { + console.error(`Error: ${err}`); +}); + +const tty = wetty(port, sshuser, sshhost, sshport, sshauth, opts.ssl); +tty.on('exit', code => { + console.log(`exit with code: ${code}`); +}); +tty.on('disconnect', () => { + console.log('disconnect'); +}); + +function loadSSL({ sslkey, sslcert }) { + return new Promise((resolve, reject) => { + const ssl = {}; + if (sslkey && sslcert) { + fs + .readFile(path.resolve(sslkey)) + .then(key => { + ssl.key = key; + }) + .then(fs.readFile(path.resolve(sslcert))) + .then(cert => { + ssl.cert = cert; + }) + .then(resolve(ssl)) + .catch(reject); + } + resolve(ssl); + }); +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..310fd8f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +version: "3" + +services: + wetty: + build: . + image: butlerx/wetty + container_name: wetty + tty: true + working_dir: /app + ports: + - "3000:3000" + environment: + PORT: 3000 + SSHHOST: 'localhost' + SSHPORT: 22 diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..6cbbadc --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,40 @@ +const gulp = require('gulp'); +const concat = require('gulp-concat'); +const minify = require('gulp-minify'); +const babel = require('gulp-babel'); +const shell = require('gulp-shell'); +const del = require('del'); + +gulp.task('compress', [], () => + gulp + .src(['./src/hterm_all.js', './src/wetty.js']) + .pipe(concat('wetty.js')) + .pipe(babel()) + .pipe( + minify({ + ext: { + min: '.min.js', + }, + exclude : ['tasks'], + noSource : true, + ignoreFiles: ['.combo.js', '*.min.js'], + }), + ) + .pipe(gulp.dest('./public/wetty')), +); + +gulp.task( + 'hterm', + shell.task( + [ + 'git clone https://chromium.googlesource.com/apps/libapps', + 'LIBDOT_SEARCH_PATH=$(pwd)/libapps ./libapps/libdot/bin/concat.sh -i ./libapps/hterm/concat/hterm_all.concat -o ./src/hterm_all.js', + ], + { + verbose: true, + }, + ), +); + +gulp.task('default', ['compress']); +gulp.task('upgrade', ['hterm'], () => del(['./libapps'])); diff --git a/index.js b/index.js new file mode 100644 index 0000000..26aecd1 --- /dev/null +++ b/index.js @@ -0,0 +1,2 @@ +require = require('@std/esm')(module); // eslint-disable-line no-global-assign +module.exports = require('./wetty.mjs').default; diff --git a/package.json b/package.json index 9c088d6..2db8d2b 100644 --- a/package.json +++ b/package.json @@ -1,34 +1,91 @@ { - "name": "wetty", - "version": "0.2.0", - "dependencies": { - "express": "3.5.1", - "socket.io": "^1.3.7", - "pty.js": "^0.3.0", - "optimist": "^0.6" - }, - "devDependencies": { - "load-grunt-tasks": "^3.0", - "grunt": "^0.4", - "grunt-shell": "^1.1", - "grunt-mkdir": "^0.1", - "grunt-git": "^0.3", - "grunt-contrib-clean": "^0.6" - }, - "description": "Wetty = Web + tty. Terminal access in browser over http/https ", - "main": "app.js", - "repository": { - "type": "git", - "url": "git://github.com/krishnasrinivas/wetty.git" - }, - "author": "Krishna Srinivas (https://github.com/krishnasrinivas)", - "license": "MIT", - "bugs": { - "url": "https://github.com/krishnasrinivas/wetty/issues" - }, - "homepage": "https://github.com/krishnasrinivas/wetty", - "preferGlobal": "true", - "bin": { - "wetty": "./bin/wetty.js" - } + "name": "wetty.js", + "version": "0.5.1", + "description": "Wetty = Web + tty. Terminal access in browser over http/https ", + "homepage": "https://github.com/krishnasrinivas/wetty", + "repository": { + "type": "git", + "url": "git://github.com/krishnasrinivas/wetty.git" + }, + "author": "Krishna Srinivas (https://github.com/krishnasrinivas)", + "license": "MIT", + "bugs": { + "url": "https://github.com/butlerx/wetty/issues" + }, + "main": "index.js", + "scripts": { + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "build": "gulp", + "start": "node bin", + "commit": "git add public", + "fix": "eslint . --fix" + }, + "bin": { + "wetty": "./bin/index.js" + }, + "pre-commit": [ + "fix", + "commit" + ], + "preferGlobal": "true", + "@std/esm": { + "cjs": "true" + }, + "dependencies": { + "@std/esm": "^0.12.1", + "express": "^4.15.3", + "fs-extra": "^4.0.1", + "optimist": "^0.6", + "pre-commit": "^1.2.2", + "node-pty": "^0.7.4", + "serve-favicon": "^2.4.3", + "socket.io": "^1.3.7" + }, + "devDependencies": { + "babel-cli": "6.24.1", + "babel-core": "6.24.1", + "babel-eslint": "7.2.3", + "babel-plugin-add-module-exports": "0.2.1", + "babel-plugin-es6-promise": "1.1.1", + "babel-plugin-syntax-async-functions": "6.13.0", + "babel-plugin-transform-async-to-generator": "6.24.1", + "babel-plugin-transform-object-assign": "6.22.0", + "babel-preset-es2015": "6.24.1", + "del": "^3.0.0", + "es6-promise": "^4.1.1", + "eslint": "3.19.0", + "eslint-config-airbnb": "^15.1.0", + "eslint-config-standard": "10.2.1", + "eslint-plugin-import": "^2.7.0", + "eslint-plugin-jsx-a11y": "^5.1.1", + "eslint-plugin-node": "^5.1.1", + "eslint-plugin-promise": "^3.5.0", + "eslint-plugin-react": "^7.1.0", + "eslint-plugin-standard": "^3.0.1", + "gulp": "^3.9.1", + "gulp-babel": "^6.1.2", + "gulp-concat": "^2.6.1", + "gulp-minify": "^1.0.0", + "gulp-shell": "^0.6.3" + }, + "contributors": [ + "Krishna Srinivas ", + "butlerx ", + "Boyan Rabchev ", + "Boyan Rabchev ", + "Luca Milanesio ", + "Antonio Calatrava ", + "Krishna Srinivas ", + "Strubbl ", + "Jarrett Gilliam ", + "Nathan LeClaire ", + "nosemeocurrenada ", + "Andreas Kloeckner ", + "Farhan Khan ", + "Imuli ", + "James Turnbull ", + "Kasper Holbek Jensen ", + "mirtouf " + ] } diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..fe2f47d Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html deleted file mode 100644 index f28eb79..0000000 --- a/public/index.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - Wetty - The WebTTY Terminal Emulator - - - - - - - -
- - - diff --git a/public/wetty/index.html b/public/wetty/index.html index f28eb79..1f468f9 100644 --- a/public/wetty/index.html +++ b/public/wetty/index.html @@ -1,30 +1,41 @@ - - + Wetty - The WebTTY Terminal Emulator - - - - - + + +
- - + + diff --git a/public/wetty/wetty.js b/public/wetty/wetty.js deleted file mode 100644 index d7068a8..0000000 --- a/public/wetty/wetty.js +++ /dev/null @@ -1,64 +0,0 @@ -var term; -var socket = io(location.origin, {path: '/wetty/socket.io'}) -var buf = ''; - -function Wetty(argv) { - this.argv_ = argv; - this.io = null; - this.pid_ = -1; -} - -Wetty.prototype.run = function() { - this.io = this.argv_.io.push(); - - this.io.onVTKeystroke = this.sendString_.bind(this); - this.io.sendString = this.sendString_.bind(this); - this.io.onTerminalResize = this.onTerminalResize.bind(this); -} - -Wetty.prototype.sendString_ = function(str) { - socket.emit('input', str); -}; - -Wetty.prototype.onTerminalResize = function(col, row) { - socket.emit('resize', { col: col, row: row }); -}; - -socket.on('connect', function() { - lib.init(function() { - hterm.defaultStorage = new lib.Storage.Local(); - term = new hterm.Terminal(); - window.term = term; - term.decorate(document.getElementById('terminal')); - - term.setCursorPosition(0, 0); - term.setCursorVisible(true); - term.prefs_.set('ctrl-c-copy', true); - term.prefs_.set('ctrl-v-paste', true); - term.prefs_.set('use-default-window-copy', true); - - term.runCommandClass(Wetty, document.location.hash.substr(1)); - socket.emit('resize', { - col: term.screenSize.width, - row: term.screenSize.height - }); - - if (buf && buf != '') - { - term.io.writeUTF16(buf); - buf = ''; - } - }); -}); - -socket.on('output', function(data) { - if (!term) { - buf += data; - return; - } - term.io.writeUTF16(data); -}); - -socket.on('disconnect', function() { - console.log("Socket.io connection closed"); -}); diff --git a/public/wetty/wetty.min.js b/public/wetty/wetty.min.js new file mode 100644 index 0000000..334a558 --- /dev/null +++ b/public/wetty/wetty.min.js @@ -0,0 +1 @@ +"use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function handler(e){return e.returnValue="Are you sure?",e.returnValue}var _createClass=function(){function e(e,t){for(var r=0;r=3?r[2].replace(/^\s*at\s+/,""):r[1].replace(/^\s*global code@/,"")}for(var o=0;o3?e[3]:1;return"rgba("+e[0]+", "+e[1]+", "+e[2]+", "+t+")"},lib.colors.setAlpha=function(e,t){var r=lib.colors.crackRGB(e);return r[3]=t,lib.colors.arrayToRGBA(r)},lib.colors.mix=function(e,t,r){for(var o=lib.colors.crackRGB(e),i=lib.colors.crackRGB(t),s=0;s<4;++s){var n=i[s]-o[s];o[s]=Math.round(parseInt(o[s])+n*r)}return lib.colors.arrayToRGBA(o)},lib.colors.crackRGB=function(e){if("rgba"==e.substr(0,4)){if(t=e.match(lib.colors.re_.rgba))return t.shift(),t}else{var t=e.match(lib.colors.re_.rgb);if(t)return t.shift(),t.push(1),t}return console.error("Couldn't crack: "+e),null},lib.colors.nameToRGB=function(e){return e in lib.colors.colorNames?lib.colors.colorNames[e]:(e=e.toLowerCase())in lib.colors.colorNames?lib.colors.colorNames[e]:(e=e.replace(/\s+/g,""))in lib.colors.colorNames?lib.colors.colorNames[e]:null},lib.colors.stockColorPalette=lib.colors.hexToRGB(["#000000","#CC0000","#4E9A06","#C4A000","#3465A4","#75507B","#06989A","#D3D7CF","#555753","#EF2929","#00BA13","#FCE94F","#729FCF","#F200CB","#00B5BD","#EEEEEC","#000000","#00005F","#000087","#0000AF","#0000D7","#0000FF","#005F00","#005F5F","#005F87","#005FAF","#005FD7","#005FFF","#008700","#00875F","#008787","#0087AF","#0087D7","#0087FF","#00AF00","#00AF5F","#00AF87","#00AFAF","#00AFD7","#00AFFF","#00D700","#00D75F","#00D787","#00D7AF","#00D7D7","#00D7FF","#00FF00","#00FF5F","#00FF87","#00FFAF","#00FFD7","#00FFFF","#5F0000","#5F005F","#5F0087","#5F00AF","#5F00D7","#5F00FF","#5F5F00","#5F5F5F","#5F5F87","#5F5FAF","#5F5FD7","#5F5FFF","#5F8700","#5F875F","#5F8787","#5F87AF","#5F87D7","#5F87FF","#5FAF00","#5FAF5F","#5FAF87","#5FAFAF","#5FAFD7","#5FAFFF","#5FD700","#5FD75F","#5FD787","#5FD7AF","#5FD7D7","#5FD7FF","#5FFF00","#5FFF5F","#5FFF87","#5FFFAF","#5FFFD7","#5FFFFF","#870000","#87005F","#870087","#8700AF","#8700D7","#8700FF","#875F00","#875F5F","#875F87","#875FAF","#875FD7","#875FFF","#878700","#87875F","#878787","#8787AF","#8787D7","#8787FF","#87AF00","#87AF5F","#87AF87","#87AFAF","#87AFD7","#87AFFF","#87D700","#87D75F","#87D787","#87D7AF","#87D7D7","#87D7FF","#87FF00","#87FF5F","#87FF87","#87FFAF","#87FFD7","#87FFFF","#AF0000","#AF005F","#AF0087","#AF00AF","#AF00D7","#AF00FF","#AF5F00","#AF5F5F","#AF5F87","#AF5FAF","#AF5FD7","#AF5FFF","#AF8700","#AF875F","#AF8787","#AF87AF","#AF87D7","#AF87FF","#AFAF00","#AFAF5F","#AFAF87","#AFAFAF","#AFAFD7","#AFAFFF","#AFD700","#AFD75F","#AFD787","#AFD7AF","#AFD7D7","#AFD7FF","#AFFF00","#AFFF5F","#AFFF87","#AFFFAF","#AFFFD7","#AFFFFF","#D70000","#D7005F","#D70087","#D700AF","#D700D7","#D700FF","#D75F00","#D75F5F","#D75F87","#D75FAF","#D75FD7","#D75FFF","#D78700","#D7875F","#D78787","#D787AF","#D787D7","#D787FF","#D7AF00","#D7AF5F","#D7AF87","#D7AFAF","#D7AFD7","#D7AFFF","#D7D700","#D7D75F","#D7D787","#D7D7AF","#D7D7D7","#D7D7FF","#D7FF00","#D7FF5F","#D7FF87","#D7FFAF","#D7FFD7","#D7FFFF","#FF0000","#FF005F","#FF0087","#FF00AF","#FF00D7","#FF00FF","#FF5F00","#FF5F5F","#FF5F87","#FF5FAF","#FF5FD7","#FF5FFF","#FF8700","#FF875F","#FF8787","#FF87AF","#FF87D7","#FF87FF","#FFAF00","#FFAF5F","#FFAF87","#FFAFAF","#FFAFD7","#FFAFFF","#FFD700","#FFD75F","#FFD787","#FFD7AF","#FFD7D7","#FFD7FF","#FFFF00","#FFFF5F","#FFFF87","#FFFFAF","#FFFFD7","#FFFFFF","#080808","#121212","#1C1C1C","#262626","#303030","#3A3A3A","#444444","#4E4E4E","#585858","#626262","#6C6C6C","#767676","#808080","#8A8A8A","#949494","#9E9E9E","#A8A8A8","#B2B2B2","#BCBCBC","#C6C6C6","#D0D0D0","#DADADA","#E4E4E4","#EEEEEE"]),lib.colors.colorPalette=lib.colors.stockColorPalette,lib.colors.colorNames={aliceblue:"rgb(240, 248, 255)",antiquewhite:"rgb(250, 235, 215)",antiquewhite1:"rgb(255, 239, 219)",antiquewhite2:"rgb(238, 223, 204)",antiquewhite3:"rgb(205, 192, 176)",antiquewhite4:"rgb(139, 131, 120)",aquamarine:"rgb(127, 255, 212)",aquamarine1:"rgb(127, 255, 212)",aquamarine2:"rgb(118, 238, 198)",aquamarine3:"rgb(102, 205, 170)",aquamarine4:"rgb(69, 139, 116)",azure:"rgb(240, 255, 255)",azure1:"rgb(240, 255, 255)",azure2:"rgb(224, 238, 238)",azure3:"rgb(193, 205, 205)",azure4:"rgb(131, 139, 139)",beige:"rgb(245, 245, 220)",bisque:"rgb(255, 228, 196)",bisque1:"rgb(255, 228, 196)",bisque2:"rgb(238, 213, 183)",bisque3:"rgb(205, 183, 158)",bisque4:"rgb(139, 125, 107)",black:"rgb(0, 0, 0)",blanchedalmond:"rgb(255, 235, 205)",blue:"rgb(0, 0, 255)",blue1:"rgb(0, 0, 255)",blue2:"rgb(0, 0, 238)",blue3:"rgb(0, 0, 205)",blue4:"rgb(0, 0, 139)",blueviolet:"rgb(138, 43, 226)",brown:"rgb(165, 42, 42)",brown1:"rgb(255, 64, 64)",brown2:"rgb(238, 59, 59)",brown3:"rgb(205, 51, 51)",brown4:"rgb(139, 35, 35)",burlywood:"rgb(222, 184, 135)",burlywood1:"rgb(255, 211, 155)",burlywood2:"rgb(238, 197, 145)",burlywood3:"rgb(205, 170, 125)",burlywood4:"rgb(139, 115, 85)",cadetblue:"rgb(95, 158, 160)",cadetblue1:"rgb(152, 245, 255)",cadetblue2:"rgb(142, 229, 238)",cadetblue3:"rgb(122, 197, 205)",cadetblue4:"rgb(83, 134, 139)",chartreuse:"rgb(127, 255, 0)",chartreuse1:"rgb(127, 255, 0)",chartreuse2:"rgb(118, 238, 0)",chartreuse3:"rgb(102, 205, 0)",chartreuse4:"rgb(69, 139, 0)",chocolate:"rgb(210, 105, 30)",chocolate1:"rgb(255, 127, 36)",chocolate2:"rgb(238, 118, 33)",chocolate3:"rgb(205, 102, 29)",chocolate4:"rgb(139, 69, 19)",coral:"rgb(255, 127, 80)",coral1:"rgb(255, 114, 86)",coral2:"rgb(238, 106, 80)",coral3:"rgb(205, 91, 69)",coral4:"rgb(139, 62, 47)",cornflowerblue:"rgb(100, 149, 237)",cornsilk:"rgb(255, 248, 220)",cornsilk1:"rgb(255, 248, 220)",cornsilk2:"rgb(238, 232, 205)",cornsilk3:"rgb(205, 200, 177)",cornsilk4:"rgb(139, 136, 120)",cyan:"rgb(0, 255, 255)",cyan1:"rgb(0, 255, 255)",cyan2:"rgb(0, 238, 238)",cyan3:"rgb(0, 205, 205)",cyan4:"rgb(0, 139, 139)",darkblue:"rgb(0, 0, 139)",darkcyan:"rgb(0, 139, 139)",darkgoldenrod:"rgb(184, 134, 11)",darkgoldenrod1:"rgb(255, 185, 15)",darkgoldenrod2:"rgb(238, 173, 14)",darkgoldenrod3:"rgb(205, 149, 12)",darkgoldenrod4:"rgb(139, 101, 8)",darkgray:"rgb(169, 169, 169)",darkgreen:"rgb(0, 100, 0)",darkgrey:"rgb(169, 169, 169)",darkkhaki:"rgb(189, 183, 107)",darkmagenta:"rgb(139, 0, 139)",darkolivegreen:"rgb(85, 107, 47)",darkolivegreen1:"rgb(202, 255, 112)",darkolivegreen2:"rgb(188, 238, 104)",darkolivegreen3:"rgb(162, 205, 90)",darkolivegreen4:"rgb(110, 139, 61)",darkorange:"rgb(255, 140, 0)",darkorange1:"rgb(255, 127, 0)",darkorange2:"rgb(238, 118, 0)",darkorange3:"rgb(205, 102, 0)",darkorange4:"rgb(139, 69, 0)",darkorchid:"rgb(153, 50, 204)",darkorchid1:"rgb(191, 62, 255)",darkorchid2:"rgb(178, 58, 238)",darkorchid3:"rgb(154, 50, 205)",darkorchid4:"rgb(104, 34, 139)",darkred:"rgb(139, 0, 0)",darksalmon:"rgb(233, 150, 122)",darkseagreen:"rgb(143, 188, 143)",darkseagreen1:"rgb(193, 255, 193)",darkseagreen2:"rgb(180, 238, 180)",darkseagreen3:"rgb(155, 205, 155)",darkseagreen4:"rgb(105, 139, 105)",darkslateblue:"rgb(72, 61, 139)",darkslategray:"rgb(47, 79, 79)",darkslategray1:"rgb(151, 255, 255)",darkslategray2:"rgb(141, 238, 238)",darkslategray3:"rgb(121, 205, 205)",darkslategray4:"rgb(82, 139, 139)",darkslategrey:"rgb(47, 79, 79)",darkturquoise:"rgb(0, 206, 209)",darkviolet:"rgb(148, 0, 211)",debianred:"rgb(215, 7, 81)",deeppink:"rgb(255, 20, 147)",deeppink1:"rgb(255, 20, 147)",deeppink2:"rgb(238, 18, 137)",deeppink3:"rgb(205, 16, 118)",deeppink4:"rgb(139, 10, 80)",deepskyblue:"rgb(0, 191, 255)",deepskyblue1:"rgb(0, 191, 255)",deepskyblue2:"rgb(0, 178, 238)",deepskyblue3:"rgb(0, 154, 205)",deepskyblue4:"rgb(0, 104, 139)",dimgray:"rgb(105, 105, 105)",dimgrey:"rgb(105, 105, 105)",dodgerblue:"rgb(30, 144, 255)",dodgerblue1:"rgb(30, 144, 255)",dodgerblue2:"rgb(28, 134, 238)",dodgerblue3:"rgb(24, 116, 205)",dodgerblue4:"rgb(16, 78, 139)",firebrick:"rgb(178, 34, 34)",firebrick1:"rgb(255, 48, 48)",firebrick2:"rgb(238, 44, 44)",firebrick3:"rgb(205, 38, 38)",firebrick4:"rgb(139, 26, 26)",floralwhite:"rgb(255, 250, 240)",forestgreen:"rgb(34, 139, 34)",gainsboro:"rgb(220, 220, 220)",ghostwhite:"rgb(248, 248, 255)",gold:"rgb(255, 215, 0)",gold1:"rgb(255, 215, 0)",gold2:"rgb(238, 201, 0)",gold3:"rgb(205, 173, 0)",gold4:"rgb(139, 117, 0)",goldenrod:"rgb(218, 165, 32)",goldenrod1:"rgb(255, 193, 37)",goldenrod2:"rgb(238, 180, 34)",goldenrod3:"rgb(205, 155, 29)",goldenrod4:"rgb(139, 105, 20)",gray:"rgb(190, 190, 190)",gray0:"rgb(0, 0, 0)",gray1:"rgb(3, 3, 3)",gray10:"rgb(26, 26, 26)",gray100:"rgb(255, 255, 255)",gray11:"rgb(28, 28, 28)",gray12:"rgb(31, 31, 31)",gray13:"rgb(33, 33, 33)",gray14:"rgb(36, 36, 36)",gray15:"rgb(38, 38, 38)",gray16:"rgb(41, 41, 41)",gray17:"rgb(43, 43, 43)",gray18:"rgb(46, 46, 46)",gray19:"rgb(48, 48, 48)",gray2:"rgb(5, 5, 5)",gray20:"rgb(51, 51, 51)",gray21:"rgb(54, 54, 54)",gray22:"rgb(56, 56, 56)",gray23:"rgb(59, 59, 59)",gray24:"rgb(61, 61, 61)",gray25:"rgb(64, 64, 64)",gray26:"rgb(66, 66, 66)",gray27:"rgb(69, 69, 69)",gray28:"rgb(71, 71, 71)",gray29:"rgb(74, 74, 74)",gray3:"rgb(8, 8, 8)",gray30:"rgb(77, 77, 77)",gray31:"rgb(79, 79, 79)",gray32:"rgb(82, 82, 82)",gray33:"rgb(84, 84, 84)",gray34:"rgb(87, 87, 87)",gray35:"rgb(89, 89, 89)",gray36:"rgb(92, 92, 92)",gray37:"rgb(94, 94, 94)",gray38:"rgb(97, 97, 97)",gray39:"rgb(99, 99, 99)",gray4:"rgb(10, 10, 10)",gray40:"rgb(102, 102, 102)",gray41:"rgb(105, 105, 105)",gray42:"rgb(107, 107, 107)",gray43:"rgb(110, 110, 110)",gray44:"rgb(112, 112, 112)",gray45:"rgb(115, 115, 115)",gray46:"rgb(117, 117, 117)",gray47:"rgb(120, 120, 120)",gray48:"rgb(122, 122, 122)",gray49:"rgb(125, 125, 125)",gray5:"rgb(13, 13, 13)",gray50:"rgb(127, 127, 127)",gray51:"rgb(130, 130, 130)",gray52:"rgb(133, 133, 133)",gray53:"rgb(135, 135, 135)",gray54:"rgb(138, 138, 138)",gray55:"rgb(140, 140, 140)",gray56:"rgb(143, 143, 143)",gray57:"rgb(145, 145, 145)",gray58:"rgb(148, 148, 148)",gray59:"rgb(150, 150, 150)",gray6:"rgb(15, 15, 15)",gray60:"rgb(153, 153, 153)",gray61:"rgb(156, 156, 156)",gray62:"rgb(158, 158, 158)",gray63:"rgb(161, 161, 161)",gray64:"rgb(163, 163, 163)",gray65:"rgb(166, 166, 166)",gray66:"rgb(168, 168, 168)",gray67:"rgb(171, 171, 171)",gray68:"rgb(173, 173, 173)",gray69:"rgb(176, 176, 176)",gray7:"rgb(18, 18, 18)",gray70:"rgb(179, 179, 179)",gray71:"rgb(181, 181, 181)",gray72:"rgb(184, 184, 184)",gray73:"rgb(186, 186, 186)",gray74:"rgb(189, 189, 189)",gray75:"rgb(191, 191, 191)",gray76:"rgb(194, 194, 194)",gray77:"rgb(196, 196, 196)",gray78:"rgb(199, 199, 199)",gray79:"rgb(201, 201, 201)",gray8:"rgb(20, 20, 20)",gray80:"rgb(204, 204, 204)",gray81:"rgb(207, 207, 207)",gray82:"rgb(209, 209, 209)",gray83:"rgb(212, 212, 212)",gray84:"rgb(214, 214, 214)",gray85:"rgb(217, 217, 217)",gray86:"rgb(219, 219, 219)",gray87:"rgb(222, 222, 222)",gray88:"rgb(224, 224, 224)",gray89:"rgb(227, 227, 227)",gray9:"rgb(23, 23, 23)",gray90:"rgb(229, 229, 229)",gray91:"rgb(232, 232, 232)",gray92:"rgb(235, 235, 235)",gray93:"rgb(237, 237, 237)",gray94:"rgb(240, 240, 240)",gray95:"rgb(242, 242, 242)",gray96:"rgb(245, 245, 245)",gray97:"rgb(247, 247, 247)",gray98:"rgb(250, 250, 250)",gray99:"rgb(252, 252, 252)",green:"rgb(0, 255, 0)",green1:"rgb(0, 255, 0)",green2:"rgb(0, 238, 0)",green3:"rgb(0, 205, 0)",green4:"rgb(0, 139, 0)",greenyellow:"rgb(173, 255, 47)",grey:"rgb(190, 190, 190)",grey0:"rgb(0, 0, 0)",grey1:"rgb(3, 3, 3)",grey10:"rgb(26, 26, 26)",grey100:"rgb(255, 255, 255)",grey11:"rgb(28, 28, 28)",grey12:"rgb(31, 31, 31)",grey13:"rgb(33, 33, 33)",grey14:"rgb(36, 36, 36)",grey15:"rgb(38, 38, 38)",grey16:"rgb(41, 41, 41)",grey17:"rgb(43, 43, 43)",grey18:"rgb(46, 46, 46)",grey19:"rgb(48, 48, 48)",grey2:"rgb(5, 5, 5)",grey20:"rgb(51, 51, 51)",grey21:"rgb(54, 54, 54)",grey22:"rgb(56, 56, 56)",grey23:"rgb(59, 59, 59)",grey24:"rgb(61, 61, 61)",grey25:"rgb(64, 64, 64)",grey26:"rgb(66, 66, 66)",grey27:"rgb(69, 69, 69)",grey28:"rgb(71, 71, 71)",grey29:"rgb(74, 74, 74)",grey3:"rgb(8, 8, 8)",grey30:"rgb(77, 77, 77)",grey31:"rgb(79, 79, 79)",grey32:"rgb(82, 82, 82)",grey33:"rgb(84, 84, 84)",grey34:"rgb(87, 87, 87)",grey35:"rgb(89, 89, 89)",grey36:"rgb(92, 92, 92)",grey37:"rgb(94, 94, 94)",grey38:"rgb(97, 97, 97)",grey39:"rgb(99, 99, 99)",grey4:"rgb(10, 10, 10)",grey40:"rgb(102, 102, 102)",grey41:"rgb(105, 105, 105)",grey42:"rgb(107, 107, 107)",grey43:"rgb(110, 110, 110)",grey44:"rgb(112, 112, 112)",grey45:"rgb(115, 115, 115)",grey46:"rgb(117, 117, 117)",grey47:"rgb(120, 120, 120)",grey48:"rgb(122, 122, 122)",grey49:"rgb(125, 125, 125)",grey5:"rgb(13, 13, 13)",grey50:"rgb(127, 127, 127)",grey51:"rgb(130, 130, 130)",grey52:"rgb(133, 133, 133)",grey53:"rgb(135, 135, 135)",grey54:"rgb(138, 138, 138)",grey55:"rgb(140, 140, 140)",grey56:"rgb(143, 143, 143)",grey57:"rgb(145, 145, 145)",grey58:"rgb(148, 148, 148)",grey59:"rgb(150, 150, 150)",grey6:"rgb(15, 15, 15)",grey60:"rgb(153, 153, 153)",grey61:"rgb(156, 156, 156)",grey62:"rgb(158, 158, 158)",grey63:"rgb(161, 161, 161)",grey64:"rgb(163, 163, 163)",grey65:"rgb(166, 166, 166)",grey66:"rgb(168, 168, 168)",grey67:"rgb(171, 171, 171)",grey68:"rgb(173, 173, 173)",grey69:"rgb(176, 176, 176)",grey7:"rgb(18, 18, 18)",grey70:"rgb(179, 179, 179)",grey71:"rgb(181, 181, 181)",grey72:"rgb(184, 184, 184)",grey73:"rgb(186, 186, 186)",grey74:"rgb(189, 189, 189)",grey75:"rgb(191, 191, 191)",grey76:"rgb(194, 194, 194)",grey77:"rgb(196, 196, 196)",grey78:"rgb(199, 199, 199)",grey79:"rgb(201, 201, 201)",grey8:"rgb(20, 20, 20)",grey80:"rgb(204, 204, 204)",grey81:"rgb(207, 207, 207)",grey82:"rgb(209, 209, 209)",grey83:"rgb(212, 212, 212)",grey84:"rgb(214, 214, 214)",grey85:"rgb(217, 217, 217)",grey86:"rgb(219, 219, 219)",grey87:"rgb(222, 222, 222)",grey88:"rgb(224, 224, 224)",grey89:"rgb(227, 227, 227)",grey9:"rgb(23, 23, 23)",grey90:"rgb(229, 229, 229)",grey91:"rgb(232, 232, 232)",grey92:"rgb(235, 235, 235)",grey93:"rgb(237, 237, 237)",grey94:"rgb(240, 240, 240)",grey95:"rgb(242, 242, 242)",grey96:"rgb(245, 245, 245)",grey97:"rgb(247, 247, 247)",grey98:"rgb(250, 250, 250)",grey99:"rgb(252, 252, 252)",honeydew:"rgb(240, 255, 240)",honeydew1:"rgb(240, 255, 240)",honeydew2:"rgb(224, 238, 224)",honeydew3:"rgb(193, 205, 193)",honeydew4:"rgb(131, 139, 131)",hotpink:"rgb(255, 105, 180)",hotpink1:"rgb(255, 110, 180)",hotpink2:"rgb(238, 106, 167)",hotpink3:"rgb(205, 96, 144)",hotpink4:"rgb(139, 58, 98)",indianred:"rgb(205, 92, 92)",indianred1:"rgb(255, 106, 106)",indianred2:"rgb(238, 99, 99)",indianred3:"rgb(205, 85, 85)",indianred4:"rgb(139, 58, 58)",ivory:"rgb(255, 255, 240)",ivory1:"rgb(255, 255, 240)",ivory2:"rgb(238, 238, 224)",ivory3:"rgb(205, 205, 193)",ivory4:"rgb(139, 139, 131)",khaki:"rgb(240, 230, 140)",khaki1:"rgb(255, 246, 143)",khaki2:"rgb(238, 230, 133)",khaki3:"rgb(205, 198, 115)",khaki4:"rgb(139, 134, 78)",lavender:"rgb(230, 230, 250)",lavenderblush:"rgb(255, 240, 245)",lavenderblush1:"rgb(255, 240, 245)",lavenderblush2:"rgb(238, 224, 229)",lavenderblush3:"rgb(205, 193, 197)",lavenderblush4:"rgb(139, 131, 134)",lawngreen:"rgb(124, 252, 0)",lemonchiffon:"rgb(255, 250, 205)",lemonchiffon1:"rgb(255, 250, 205)",lemonchiffon2:"rgb(238, 233, 191)",lemonchiffon3:"rgb(205, 201, 165)",lemonchiffon4:"rgb(139, 137, 112)",lightblue:"rgb(173, 216, 230)",lightblue1:"rgb(191, 239, 255)",lightblue2:"rgb(178, 223, 238)",lightblue3:"rgb(154, 192, 205)",lightblue4:"rgb(104, 131, 139)",lightcoral:"rgb(240, 128, 128)",lightcyan:"rgb(224, 255, 255)",lightcyan1:"rgb(224, 255, 255)",lightcyan2:"rgb(209, 238, 238)",lightcyan3:"rgb(180, 205, 205)",lightcyan4:"rgb(122, 139, 139)",lightgoldenrod:"rgb(238, 221, 130)",lightgoldenrod1:"rgb(255, 236, 139)",lightgoldenrod2:"rgb(238, 220, 130)",lightgoldenrod3:"rgb(205, 190, 112)",lightgoldenrod4:"rgb(139, 129, 76)",lightgoldenrodyellow:"rgb(250, 250, 210)",lightgray:"rgb(211, 211, 211)",lightgreen:"rgb(144, 238, 144)",lightgrey:"rgb(211, 211, 211)",lightpink:"rgb(255, 182, 193)",lightpink1:"rgb(255, 174, 185)",lightpink2:"rgb(238, 162, 173)",lightpink3:"rgb(205, 140, 149)",lightpink4:"rgb(139, 95, 101)",lightsalmon:"rgb(255, 160, 122)",lightsalmon1:"rgb(255, 160, 122)",lightsalmon2:"rgb(238, 149, 114)",lightsalmon3:"rgb(205, 129, 98)",lightsalmon4:"rgb(139, 87, 66)",lightseagreen:"rgb(32, 178, 170)",lightskyblue:"rgb(135, 206, 250)",lightskyblue1:"rgb(176, 226, 255)",lightskyblue2:"rgb(164, 211, 238)",lightskyblue3:"rgb(141, 182, 205)",lightskyblue4:"rgb(96, 123, 139)",lightslateblue:"rgb(132, 112, 255)",lightslategray:"rgb(119, 136, 153)",lightslategrey:"rgb(119, 136, 153)",lightsteelblue:"rgb(176, 196, 222)",lightsteelblue1:"rgb(202, 225, 255)",lightsteelblue2:"rgb(188, 210, 238)",lightsteelblue3:"rgb(162, 181, 205)",lightsteelblue4:"rgb(110, 123, 139)",lightyellow:"rgb(255, 255, 224)",lightyellow1:"rgb(255, 255, 224)",lightyellow2:"rgb(238, 238, 209)",lightyellow3:"rgb(205, 205, 180)",lightyellow4:"rgb(139, 139, 122)",limegreen:"rgb(50, 205, 50)",linen:"rgb(250, 240, 230)",magenta:"rgb(255, 0, 255)",magenta1:"rgb(255, 0, 255)",magenta2:"rgb(238, 0, 238)",magenta3:"rgb(205, 0, 205)",magenta4:"rgb(139, 0, 139)",maroon:"rgb(176, 48, 96)",maroon1:"rgb(255, 52, 179)",maroon2:"rgb(238, 48, 167)",maroon3:"rgb(205, 41, 144)",maroon4:"rgb(139, 28, 98)",mediumaquamarine:"rgb(102, 205, 170)",mediumblue:"rgb(0, 0, 205)",mediumorchid:"rgb(186, 85, 211)",mediumorchid1:"rgb(224, 102, 255)",mediumorchid2:"rgb(209, 95, 238)",mediumorchid3:"rgb(180, 82, 205)",mediumorchid4:"rgb(122, 55, 139)",mediumpurple:"rgb(147, 112, 219)",mediumpurple1:"rgb(171, 130, 255)",mediumpurple2:"rgb(159, 121, 238)",mediumpurple3:"rgb(137, 104, 205)",mediumpurple4:"rgb(93, 71, 139)",mediumseagreen:"rgb(60, 179, 113)",mediumslateblue:"rgb(123, 104, 238)",mediumspringgreen:"rgb(0, 250, 154)",mediumturquoise:"rgb(72, 209, 204)",mediumvioletred:"rgb(199, 21, 133)",midnightblue:"rgb(25, 25, 112)",mintcream:"rgb(245, 255, 250)",mistyrose:"rgb(255, 228, 225)",mistyrose1:"rgb(255, 228, 225)",mistyrose2:"rgb(238, 213, 210)",mistyrose3:"rgb(205, 183, 181)",mistyrose4:"rgb(139, 125, 123)",moccasin:"rgb(255, 228, 181)",navajowhite:"rgb(255, 222, 173)",navajowhite1:"rgb(255, 222, 173)",navajowhite2:"rgb(238, 207, 161)",navajowhite3:"rgb(205, 179, 139)",navajowhite4:"rgb(139, 121, 94)",navy:"rgb(0, 0, 128)",navyblue:"rgb(0, 0, 128)",oldlace:"rgb(253, 245, 230)",olivedrab:"rgb(107, 142, 35)",olivedrab1:"rgb(192, 255, 62)",olivedrab2:"rgb(179, 238, 58)",olivedrab3:"rgb(154, 205, 50)",olivedrab4:"rgb(105, 139, 34)",orange:"rgb(255, 165, 0)",orange1:"rgb(255, 165, 0)",orange2:"rgb(238, 154, 0)",orange3:"rgb(205, 133, 0)",orange4:"rgb(139, 90, 0)",orangered:"rgb(255, 69, 0)",orangered1:"rgb(255, 69, 0)",orangered2:"rgb(238, 64, 0)",orangered3:"rgb(205, 55, 0)",orangered4:"rgb(139, 37, 0)",orchid:"rgb(218, 112, 214)",orchid1:"rgb(255, 131, 250)",orchid2:"rgb(238, 122, 233)",orchid3:"rgb(205, 105, 201)",orchid4:"rgb(139, 71, 137)",palegoldenrod:"rgb(238, 232, 170)",palegreen:"rgb(152, 251, 152)",palegreen1:"rgb(154, 255, 154)",palegreen2:"rgb(144, 238, 144)",palegreen3:"rgb(124, 205, 124)",palegreen4:"rgb(84, 139, 84)",paleturquoise:"rgb(175, 238, 238)",paleturquoise1:"rgb(187, 255, 255)",paleturquoise2:"rgb(174, 238, 238)",paleturquoise3:"rgb(150, 205, 205)",paleturquoise4:"rgb(102, 139, 139)",palevioletred:"rgb(219, 112, 147)",palevioletred1:"rgb(255, 130, 171)",palevioletred2:"rgb(238, 121, 159)",palevioletred3:"rgb(205, 104, 137)",palevioletred4:"rgb(139, 71, 93)",papayawhip:"rgb(255, 239, 213)",peachpuff:"rgb(255, 218, 185)",peachpuff1:"rgb(255, 218, 185)",peachpuff2:"rgb(238, 203, 173)",peachpuff3:"rgb(205, 175, 149)",peachpuff4:"rgb(139, 119, 101)",peru:"rgb(205, 133, 63)",pink:"rgb(255, 192, 203)",pink1:"rgb(255, 181, 197)",pink2:"rgb(238, 169, 184)",pink3:"rgb(205, 145, 158)",pink4:"rgb(139, 99, 108)",plum:"rgb(221, 160, 221)",plum1:"rgb(255, 187, 255)",plum2:"rgb(238, 174, 238)",plum3:"rgb(205, 150, 205)",plum4:"rgb(139, 102, 139)",powderblue:"rgb(176, 224, 230)",purple:"rgb(160, 32, 240)",purple1:"rgb(155, 48, 255)",purple2:"rgb(145, 44, 238)",purple3:"rgb(125, 38, 205)",purple4:"rgb(85, 26, 139)",red:"rgb(255, 0, 0)",red1:"rgb(255, 0, 0)",red2:"rgb(238, 0, 0)",red3:"rgb(205, 0, 0)",red4:"rgb(139, 0, 0)",rosybrown:"rgb(188, 143, 143)",rosybrown1:"rgb(255, 193, 193)",rosybrown2:"rgb(238, 180, 180)",rosybrown3:"rgb(205, 155, 155)",rosybrown4:"rgb(139, 105, 105)",royalblue:"rgb(65, 105, 225)",royalblue1:"rgb(72, 118, 255)",royalblue2:"rgb(67, 110, 238)",royalblue3:"rgb(58, 95, 205)",royalblue4:"rgb(39, 64, 139)",saddlebrown:"rgb(139, 69, 19)",salmon:"rgb(250, 128, 114)",salmon1:"rgb(255, 140, 105)",salmon2:"rgb(238, 130, 98)",salmon3:"rgb(205, 112, 84)",salmon4:"rgb(139, 76, 57)",sandybrown:"rgb(244, 164, 96)",seagreen:"rgb(46, 139, 87)",seagreen1:"rgb(84, 255, 159)",seagreen2:"rgb(78, 238, 148)",seagreen3:"rgb(67, 205, 128)",seagreen4:"rgb(46, 139, 87)",seashell:"rgb(255, 245, 238)",seashell1:"rgb(255, 245, 238)",seashell2:"rgb(238, 229, 222)",seashell3:"rgb(205, 197, 191)",seashell4:"rgb(139, 134, 130)",sienna:"rgb(160, 82, 45)",sienna1:"rgb(255, 130, 71)",sienna2:"rgb(238, 121, 66)",sienna3:"rgb(205, 104, 57)",sienna4:"rgb(139, 71, 38)",skyblue:"rgb(135, 206, 235)",skyblue1:"rgb(135, 206, 255)",skyblue2:"rgb(126, 192, 238)",skyblue3:"rgb(108, 166, 205)",skyblue4:"rgb(74, 112, 139)",slateblue:"rgb(106, 90, 205)",slateblue1:"rgb(131, 111, 255)",slateblue2:"rgb(122, 103, 238)",slateblue3:"rgb(105, 89, 205)",slateblue4:"rgb(71, 60, 139)",slategray:"rgb(112, 128, 144)",slategray1:"rgb(198, 226, 255)",slategray2:"rgb(185, 211, 238)",slategray3:"rgb(159, 182, 205)",slategray4:"rgb(108, 123, 139)",slategrey:"rgb(112, 128, 144)",snow:"rgb(255, 250, 250)",snow1:"rgb(255, 250, 250)",snow2:"rgb(238, 233, 233)",snow3:"rgb(205, 201, 201)",snow4:"rgb(139, 137, 137)",springgreen:"rgb(0, 255, 127)",springgreen1:"rgb(0, 255, 127)",springgreen2:"rgb(0, 238, 118)",springgreen3:"rgb(0, 205, 102)",springgreen4:"rgb(0, 139, 69)",steelblue:"rgb(70, 130, 180)",steelblue1:"rgb(99, 184, 255)",steelblue2:"rgb(92, 172, 238)",steelblue3:"rgb(79, 148, 205)",steelblue4:"rgb(54, 100, 139)",tan:"rgb(210, 180, 140)",tan1:"rgb(255, 165, 79)",tan2:"rgb(238, 154, 73)",tan3:"rgb(205, 133, 63)",tan4:"rgb(139, 90, 43)",thistle:"rgb(216, 191, 216)",thistle1:"rgb(255, 225, 255)",thistle2:"rgb(238, 210, 238)",thistle3:"rgb(205, 181, 205)",thistle4:"rgb(139, 123, 139)",tomato:"rgb(255, 99, 71)",tomato1:"rgb(255, 99, 71)",tomato2:"rgb(238, 92, 66)",tomato3:"rgb(205, 79, 57)",tomato4:"rgb(139, 54, 38)",turquoise:"rgb(64, 224, 208)",turquoise1:"rgb(0, 245, 255)",turquoise2:"rgb(0, 229, 238)",turquoise3:"rgb(0, 197, 205)",turquoise4:"rgb(0, 134, 139)",violet:"rgb(238, 130, 238)",violetred:"rgb(208, 32, 144)",violetred1:"rgb(255, 62, 150)",violetred2:"rgb(238, 58, 140)",violetred3:"rgb(205, 50, 120)",violetred4:"rgb(139, 34, 82)",wheat:"rgb(245, 222, 179)",wheat1:"rgb(255, 231, 186)",wheat2:"rgb(238, 216, 174)",wheat3:"rgb(205, 186, 150)",wheat4:"rgb(139, 126, 102)",white:"rgb(255, 255, 255)",whitesmoke:"rgb(245, 245, 245)",yellow:"rgb(255, 255, 0)",yellow1:"rgb(255, 255, 0)",yellow2:"rgb(238, 238, 0)",yellow3:"rgb(205, 205, 0)",yellow4:"rgb(139, 139, 0)",yellowgreen:"rgb(154, 205, 50)"},lib.f={},lib.f.replaceVars=function(e,t){return e.replace(/%([a-z]*)\(([^\)]+)\)/gi,function(e,r,o){if(void 0===t[o])throw"Unknown variable: "+o;var i=t[o];if(r in lib.f.replaceVars.functions)i=lib.f.replaceVars.functions[r](i);else if(r)throw"Unknown escape function: "+r;return i})},lib.f.replaceVars.functions={encodeURI:encodeURI,encodeURIComponent:encodeURIComponent,escapeHTML:function(e){var t={"<":"<",">":">","&":"&",'"':""","'":"'"};return e.replace(/[<>&\"\']/g,function(e){return t[e]})}},lib.f.getAcceptLanguages=function(e){window.chrome&&chrome.i18n?chrome.i18n.getAcceptLanguages(e):setTimeout(function(){e([navigator.language.replace(/-/g,"_")])},0)},lib.f.parseQuery=function(e){"?"==e.substr(0,1)&&(e=e.substr(1));for(var t={},r=e.split("&"),o=0;or?r:e},lib.f.lpad=function(e,t,r){for(e=String(e),r=r||" ";e.lengtht.whitespace.length;)t.whitespace+=t.whitespace;return t.whitespace.substr(0,e)},lib.f.alarm=function(e,t){var r=t||5e3,o=lib.f.getStack(1);return function(){var t=setTimeout(function(){var i="string"==typeof e?i:e.name;i=i?": "+i:"",console.warn("lib.f.alarm: timeout expired: "+r/1e3+"s"+i),console.log(o),t=null},r),i=function(e){return function(){return t&&(clearTimeout(t),t=null),e.apply(null,arguments)}};return"string"==typeof e?i:i(e)}()},lib.f.getStack=function(e){var t,r=e?e+2:2;try{throw new Error}catch(e){t=e.stack.split("\n")}for(var o={},i=r;i=0&&this.observers.splice(t,1)},lib.PreferenceManager.Record.prototype.get=function(){return this.currentValue===this.DEFAULT_VALUE?/^(string|number)$/.test(_typeof(this.defaultValue))?this.defaultValue:"object"==_typeof(this.defaultValue)?JSON.parse(JSON.stringify(this.defaultValue)):this.defaultValue:this.currentValue},lib.PreferenceManager.prototype.deactivate=function(){if(!this.isActive_)throw new Error("Not activated");this.isActive_=!1,this.storage.removeObserver(this.storageObserver_)},lib.PreferenceManager.prototype.activate=function(){if(this.isActive_)throw new Error("Already activated");this.isActive_=!0,this.storage.addObserver(this.storageObserver_)},lib.PreferenceManager.prototype.readStorage=function(e){function t(){0==--r&&e&&e()}var r=0,o=Object.keys(this.prefRecords_).map(function(e){return this.prefix+e}.bind(this));this.trace&&console.log("Preferences read: "+this.prefix),this.storage.getItems(o,function(o){var i=this.prefix.length;for(var s in o){var n=o[s],a=s.substr(i),l=a in this.childLists_&&JSON.stringify(n)!=JSON.stringify(this.prefRecords_[a].currentValue);this.prefRecords_[a].currentValue=n,l&&(r++,this.syncChildList(a,t))}0==r&&e&&setTimeout(e)}.bind(this))},lib.PreferenceManager.prototype.definePreference=function(e,t,r){var o=this.prefRecords_[e];o?this.changeDefault(e,t):o=this.prefRecords_[e]=new lib.PreferenceManager.Record(e,t),r&&o.addObserver(r)},lib.PreferenceManager.prototype.definePreferences=function(e){for(var t=0;t=0&&i.splice(a,1),!this.childLists_[e][n]){var l=this.childFactories_[e](this,n);if(!l){console.warn("Unable to restore child: "+e+": "+n);continue}l.trace=this.trace,this.childLists_[e][n]=l,r++,l.readStorage(function(){0==--r&&t&&t()})}}for(s=0;s=0;o--){var i=e[o],s=this.storage_.getItem(i);if("string"==typeof s)try{r[i]=JSON.parse(s)}catch(e){r[i]=s}else e.splice(o,1)}setTimeout(t.bind(null,r),0)},lib.Storage.Local.prototype.setItem=function(e,t,r){this.storage_.setItem(e,JSON.stringify(t)),r&&setTimeout(r,0)},lib.Storage.Local.prototype.setItems=function(e,t){for(var r in e)this.storage_.setItem(r,JSON.stringify(e[r]));t&&setTimeout(t,0)},lib.Storage.Local.prototype.removeItem=function(e,t){this.storage_.removeItem(e),t&&setTimeout(t,0)},lib.Storage.Local.prototype.removeItems=function(e,t){for(var r=0;r=0;o--){var i=e[o],s=this.storage_[i];if("string"==typeof s)try{r[i]=JSON.parse(s)}catch(e){r[i]=s}else e.splice(o,1)}setTimeout(t.bind(null,r),0)},lib.Storage.Memory.prototype.setItem=function(e,t,r){var o=this.storage_[e];this.storage_[e]=JSON.stringify(t);var i={};i[e]={oldValue:o,newValue:t},setTimeout(function(){for(var e=0;e"),lib.TestManager.TestRun.prototype.selectTest=function(e){this.testQueue_.push(e)},lib.TestManager.TestRun.prototype.selectSuite=function(e,t){for(var r=t||this.ALL_TESTS,o=0,i=e.getTestList(),s=0;s=0&&(this.passes.splice(r,1),this.failures.push(e))},lib.TestManager.TestRun.prototype.runNextTest_=function(){if(this.panic||!this.testQueue_.length)return this.onTestRunComplete_();if(this.maxFailures&&this.failures.length>=this.maxFailures)return this.log.println("Maximum failure count reached, aborting test run."),this.onTestRunComplete_();var e=this.testQueue_[0],t=this.currentResult?this.currentResult.suite:null;try{t&&t instanceof e.suiteClass||(this.log.println("Initializing suite: "+e.suiteClass.suiteName),t=new e.suiteClass(this.testManager,this.cx))}catch(e){return this.log.println("Exception during setup: "+(e.stack?e.stack:e)),this.panic=!0,void this.onTestRunComplete_()}try{this.log.print("Test: "+e.fullName+" {"),this.log.pushPrefix(" "),this.currentResult=new lib.TestManager.Result(this,t,e),t.preamble(this.currentResult,this.cx),this.testQueue_.shift()}catch(e){return this.log.println("Unexpected exception during test preamble: "+(e.stack?e.stack:e)),this.log.popPrefix(),this.log.println("}"),this.panic=!0,void this.onTestRunComplete_()}try{this.currentResult.run()}catch(e){this.log.println("Unexpected exception during test run: "+(e.stack?e.stack:e)),this.panic=!0}},lib.TestManager.TestRun.prototype.run=function(){this.log.println("Running "+this.testQueue_.length+" test(s) {"),this.log.pushPrefix(" "),window.onerror=this.onUncaughtException_.bind(this),this.startDate=new Date,this.runNextTest_()},lib.TestManager.TestRun.prototype.msToSeconds_=function(e){return(e/1e3).toFixed(2)+"s"},lib.TestManager.TestRun.prototype.summarize=function(){if(this.failures.length)for(var e=0;e1?"\n"+t.join("\n"):t.join("\n")}if(e!==t){var i=r?"["+r+"]":"";this.fail("assertEQ"+i+": "+this.getCallerLocation_(1)+": "+o(e)+" !== "+o(t))}},lib.TestManager.Result.prototype.assert=function(e,t){if(!0!==e){var r=t?"["+t+"]":"";this.fail("assert"+r+": "+this.getCallerLocation_(1)+": "+String(e))}},lib.TestManager.Result.prototype.getCallerLocation_=function(e){try{throw new Error}catch(r){var t=r.stack.split("\n")[e+2].match(/([^/]+:\d+):\d+\)?$/);return t?t[1]:"???"}},lib.TestManager.Result.prototype.println=function(e){this.testRun.log.println(e)},lib.TestManager.Result.prototype.fail=function(e){arguments.length&&this.println(e),this.completeTest_(this.FAILED,!0)},lib.TestManager.Result.prototype.pass=function(){this.completeTest_(this.PASSED,!0)},lib.UTF8Decoder=function(){this.bytesLeft=0,this.codePoint=0,this.lowerBound=0},lib.UTF8Decoder.prototype.decode=function(e){for(var t="",r=0;r1114111?t+="�":i<65536?t+=String.fromCharCode(i):(i-=65536,t+=String.fromCharCode(55296+(i>>>10&1023),56320+(1023&i)))}}else t+="�",this.bytesLeft=0,r--}return t},lib.decodeUTF8=function(e){return(new lib.UTF8Decoder).decode(e)},lib.encodeUTF8=function(e){for(var t="",r=0;r>>6),s=1):o<=65535?(t+=String.fromCharCode(224|o>>>12),s=2):(t+=String.fromCharCode(240|o>>>18),s=3);s>0;)s--,t+=String.fromCharCode(128|o>>>6*s&63)}return t},lib.wc={},lib.wc.nulWidth=0,lib.wc.controlWidth=0,lib.wc.regardCjkAmbiguous=!1,lib.wc.cjkAmbiguousWidth=2,lib.wc.combining=[[768,879],[1155,1158],[1160,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1539],[1552,1557],[1611,1630],[1648,1648],[1750,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2305,2306],[2364,2364],[2369,2376],[2381,2381],[2385,2388],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2672,2673],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2817,2817],[2876,2876],[2879,2879],[2881,2883],[2893,2893],[2902,2902],[2946,2946],[3008,3008],[3021,3021],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3393,3395],[3405,3405],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3984,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4146],[4150,4151],[4153,4153],[4184,4185],[4448,4607],[4959,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7616,7626],[7678,7679],[8203,8207],[8234,8238],[8288,8291],[8298,8303],[8400,8431],[12330,12335],[12441,12442],[43014,43014],[43019,43019],[43045,43046],[64286,64286],[65024,65039],[65056,65059],[65279,65279],[65529,65531],[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[917505,917505],[917536,917631],[917760,917999]],lib.wc.ambiguous=[[161,161],[164,164],[167,168],[170,170],[174,174],[176,180],[182,186],[188,191],[198,198],[208,208],[215,216],[222,225],[230,230],[232,234],[236,237],[240,240],[242,243],[247,250],[252,252],[254,254],[257,257],[273,273],[275,275],[283,283],[294,295],[299,299],[305,307],[312,312],[319,322],[324,324],[328,331],[333,333],[338,339],[358,359],[363,363],[462,462],[464,464],[466,466],[468,468],[470,470],[472,472],[474,474],[476,476],[593,593],[609,609],[708,708],[711,711],[713,715],[717,717],[720,720],[728,731],[733,733],[735,735],[913,929],[931,937],[945,961],[963,969],[1025,1025],[1040,1103],[1105,1105],[8208,8208],[8211,8214],[8216,8217],[8220,8221],[8224,8226],[8228,8231],[8240,8240],[8242,8243],[8245,8245],[8251,8251],[8254,8254],[8308,8308],[8319,8319],[8321,8324],[8364,8364],[8451,8451],[8453,8453],[8457,8457],[8467,8467],[8470,8470],[8481,8482],[8486,8486],[8491,8491],[8531,8532],[8539,8542],[8544,8555],[8560,8569],[8592,8601],[8632,8633],[8658,8658],[8660,8660],[8679,8679],[8704,8704],[8706,8707],[8711,8712],[8715,8715],[8719,8719],[8721,8721],[8725,8725],[8730,8730],[8733,8736],[8739,8739],[8741,8741],[8743,8748],[8750,8750],[8756,8759],[8764,8765],[8776,8776],[8780,8780],[8786,8786],[8800,8801],[8804,8807],[8810,8811],[8814,8815],[8834,8835],[8838,8839],[8853,8853],[8857,8857],[8869,8869],[8895,8895],[8978,8978],[9312,9449],[9451,9547],[9552,9587],[9600,9615],[9618,9621],[9632,9633],[9635,9641],[9650,9651],[9654,9655],[9660,9661],[9664,9665],[9670,9672],[9675,9675],[9678,9681],[9698,9701],[9711,9711],[9733,9734],[9737,9737],[9742,9743],[9748,9749],[9756,9756],[9758,9758],[9792,9792],[9794,9794],[9824,9825],[9827,9829],[9831,9834],[9836,9837],[9839,9839],[10045,10045],[10102,10111],[57344,63743],[65533,65533],[983040,1048573],[1048576,1114109]],lib.wc.isSpace=function(e){var t,r=0,o=lib.wc.combining.length-1;if(elib.wc.combining[o][1])return!1;for(;o>=r;)if(t=Math.floor((r+o)/2),e>lib.wc.combining[t][1])r=t+1;else{if(!(elib.wc.ambiguous[o][1])return!1;for(;o>=r;)if(t=Math.floor((r+o)/2),e>lib.wc.ambiguous[t][1])r=t+1;else{if(!(e=127&&e<160?lib.wc.controlWidth:e<127?1:lib.wc.isSpace(e)?0:1+(e>=4352&&(e<=4447||9001==e||9002==e||e>=11904&&e<=42191&&12351!=e||e>=44032&&e<=55203||e>=63744&&e<=64255||e>=65040&&e<=65049||e>=65072&&e<=65135||e>=65280&&e<=65376||e>=65504&&e<=65510||e>=131072&&e<=196605||e>=196608&&e<=262141))},lib.wc.charWidthRegardAmbiguous=function(e){return lib.wc.isCjkAmbiguous(e)?lib.wc.cjkAmbiguousWidth:lib.wc.charWidthDisregardAmbiguous(e)},lib.wc.strWidth=function(e){for(var t,r=0,o=0;ot);o++);if(void 0!=r){for(i=o,s=0;ir&&i--,e.substring(o,i)}return e.substr(o)},lib.wc.substring=function(e,t,r){return lib.wc.substr(e,t,r-t)},lib.resource.add("libdot/changelog/version","text/plain","1.9"),lib.resource.add("libdot/changelog/date","text/plain","2014-05-27"),lib.rtdep("lib.Storage");var hterm={};hterm.windowType=null,hterm.zoomWarningMessage="ZOOM != 100%",hterm.notifyCopyMessage="✂",hterm.desktopNotificationTitle="♪ %(title) ♪",hterm.testDeps=["hterm.ScrollPort.Tests","hterm.Screen.Tests","hterm.Terminal.Tests","hterm.VT.Tests","hterm.VT.CannedTests"],lib.registerInit("hterm",function(e){function t(t){hterm.windowType=t.type,setTimeout(e,0)}if(!hterm.defaultStorage){var r=navigator.userAgent.match(/\sChrome\/(\d\d)/),o=r?parseInt(r[1]):-1;window.chrome&&chrome.storage&&chrome.storage.sync&&o>21?hterm.defaultStorage=new lib.Storage.Chrome(chrome.storage.sync):hterm.defaultStorage=new lib.Storage.Local}s=!1;if(window.chrome&&chrome.runtime&&chrome.runtime.getManifest)var i=chrome.runtime.getManifest(),s=i.app&&i.app.background;s?setTimeout(t.bind(null,{type:"popup"}),0):window.chrome&&chrome.tabs?chrome.tabs.getCurrent(function(r){r&&window.chrome?chrome.windows.get(r.windowId,null,t):(hterm.windowType="normal",setTimeout(e,0))}):setTimeout(t.bind(null,{type:"normal"}),0)}),hterm.getClientSize=function(e){return e.getBoundingClientRect()},hterm.getClientWidth=function(e){return e.getBoundingClientRect().width},hterm.getClientHeight=function(e){return e.getBoundingClientRect().height},hterm.copySelectionToClipboard=function(e){try{e.execCommand("copy")}catch(e){}},hterm.pasteFromClipboard=function(e){try{e.execCommand("paste")}catch(e){}},hterm.Size=function(e,t){this.width=e,this.height=t},hterm.Size.prototype.resize=function(e,t){this.width=e,this.height=t},hterm.Size.prototype.clone=function(){return new hterm.Size(this.width,this.height)},hterm.Size.prototype.setTo=function(e){this.width=e.width,this.height=e.height},hterm.Size.prototype.equals=function(e){return this.width==e.width&&this.height==e.height},hterm.Size.prototype.toString=function(){return"[hterm.Size: "+this.width+", "+this.height+"]"},hterm.RowCol=function(e,t,r){this.row=e,this.column=t,this.overflow=!!r},hterm.RowCol.prototype.move=function(e,t,r){this.row=e,this.column=t,this.overflow=!!r},hterm.RowCol.prototype.clone=function(){return new hterm.RowCol(this.row,this.column,this.overflow)},hterm.RowCol.prototype.setTo=function(e){this.row=e.row,this.column=e.column,this.overflow=e.overflow},hterm.RowCol.prototype.equals=function(e){return this.row==e.row&&this.column==e.column&&this.overflow==e.overflow},hterm.RowCol.prototype.toString=function(){return"[hterm.RowCol: "+this.row+", "+this.column+", "+this.overflow+"]"},lib.rtdep("lib.f"),hterm.Frame=function(e,t,r){this.terminal_=e,this.div_=e.div_,this.url=t,this.options=r||{},this.iframe_=null,this.container_=null,this.messageChannel_=null},hterm.Frame.prototype.onMessage_=function(e){"ipc-init-ok"==e.data.name?(this.sendTerminalInfo_(),this.messageChannel_.port1.onmessage=this.onMessage.bind(this),this.onLoad()):console.log("Unknown message from frame:",e.data)},hterm.Frame.prototype.onMessage=function(){},hterm.Frame.prototype.onLoad_=function(){this.messageChannel_=new MessageChannel,this.messageChannel_.port1.onmessage=this.onMessage_.bind(this),this.messageChannel_.port1.start(),this.iframe_.contentWindow.postMessage({name:"ipc-init",argv:[{messagePort:this.messageChannel_.port2}]},[this.messageChannel_.port2],this.url)},hterm.Frame.prototype.onLoad=function(){},hterm.Frame.prototype.sendTerminalInfo_=function(){lib.f.getAcceptLanguages(function(e){this.postMessage("terminal-info",[{acceptLanguages:e,foregroundColor:this.terminal_.getForegroundColor(),backgroundColor:this.terminal_.getBackgroundColor(),cursorColor:this.terminal_.getCursorColor(),fontSize:this.terminal_.getFontSize(),fontFamily:this.terminal_.getFontFamily(),baseURL:lib.f.getURL("/")}])}.bind(this))},hterm.Frame.prototype.onCloseClicked_=function(){this.close()},hterm.Frame.prototype.close=function(){this.container_&&this.container_.parentNode&&(this.container_.parentNode.removeChild(this.container_),this.onClose())},hterm.Frame.prototype.onClose=function(){},hterm.Frame.prototype.postMessage=function(e,t){if(!this.messageChannel_)throw new Error("Message channel is not set up.");this.messageChannel_.port1.postMessage({name:e,argv:t})},hterm.Frame.prototype.show=function(){function e(e,r){return e in t.options?t.options[e]:r}var t=this,t=this;if(this.container_&&this.container_.parentNode)console.error("Frame already visible");else{var r=hterm.getClientSize(this.div_),o=e("width",640),i=e("height",480),s=(r.width,r.height,this.terminal_.document_),n=this.container_=s.createElement("div");n.style.cssText="position: absolute;display: -webkit-flex;-webkit-flex-direction: column;top: 10%;left: 4%;width: 90%;height: 80%;box-shadow: 0 0 2px "+this.terminal_.getForegroundColor()+";border: 2px "+this.terminal_.getForegroundColor()+" solid;";var a=s.createElement("div");a.style.cssText="display: -webkit-flex;-webkit-justify-content: flex-end;height: 16px;background-color: "+this.terminal_.getForegroundColor()+";color: "+this.terminal_.getBackgroundColor()+";font-size: 16px;font-family: "+this.terminal_.getFontFamily(),n.appendChild(a);var l=this.iframe_=s.createElement("iframe");l.onload=this.onLoad_.bind(this),l.style.cssText="display: -webkit-flex;-webkit-flex: 1;width: 100%",l.setAttribute("src",this.url),l.setAttribute("seamless",!0),n.appendChild(l),this.div_.appendChild(n)}},lib.rtdep("hterm.Keyboard.KeyMap"),hterm.Keyboard=function(e){this.terminal=e,this.keyboardElement_=null,this.handlers_=[["blur",this.onBlur_.bind(this)],["keydown",this.onKeyDown_.bind(this)],["keypress",this.onKeyPress_.bind(this)],["keyup",this.onKeyUp_.bind(this)],["textInput",this.onTextInput_.bind(this)]],this.keyMap=new hterm.Keyboard.KeyMap(this),this.altGrMode="none",this.shiftInsertPaste=!0,this.homeKeysScroll=!1,this.pageKeysScroll=!1,this.ctrlPlusMinusZeroZoom=!0,this.ctrlCCopy=!1,this.ctrlVPaste=!1,this.applicationKeypad=!1,this.applicationCursor=!1,this.backspaceSendsBackspace=!1,this.characterEncoding="utf-8",this.metaSendsEscape=!0,this.passMetaV=!0,this.altSendsWhat="escape",this.altIsMeta=!1,this.altBackspaceIsMetaBackspace=!1,this.altKeyPressed=0,this.mediaKeysAreFKeys=!1,this.previousAltSendsWhat_=null},hterm.Keyboard.KeyActions={CANCEL:new String("CANCEL"),DEFAULT:new String("DEFAULT"),PASS:new String("PASS"),STRIP:new String("STRIP")},hterm.Keyboard.prototype.encode=function(e){return"utf-8"==this.characterEncoding?this.terminal.vt.encodeUTF8(e):e},hterm.Keyboard.prototype.installKeyboard=function(e){if(e!=this.keyboardElement_){e&&this.keyboardElement_&&this.installKeyboard(null);for(var t=0;t=32&&(r=e.charCode);r&&this.terminal.onVTKeystroke(String.fromCharCode(r)),e.preventDefault(),e.stopPropagation()}},hterm.Keyboard.prototype.preventChromeAppNonShiftDefault_=function(e){window.chrome&&window.chrome.app&&window.chrome.app.window&&(e.shiftKey||e.preventDefault())},hterm.Keyboard.prototype.onBlur_=function(e){this.altKeyPressed=0},hterm.Keyboard.prototype.onKeyUp_=function(e){18==e.keyCode&&(this.altKeyPressed=this.altKeyPressed&~(1<=64&&b<=95&&(d=String.fromCharCode(b-64))),c&&"8-bit"==this.altSendsWhat&&1==d.length){var b=d.charCodeAt(0)+128;d=String.fromCharCode(b)}(c&&"escape"==this.altSendsWhat||u&&this.metaSendsEscape)&&(d=""+d)}this.terminal.onVTKeystroke(d)}else console.warn("Invalid action: "+JSON.stringify(d))}else console.warn("No definition for keyCode: "+e.keyCode)},lib.rtdep("hterm.Keyboard.KeyActions"),hterm.Keyboard.KeyMap=function(e){this.keyboard=e,this.keyDefs={},this.reset()},hterm.Keyboard.KeyMap.prototype.addKeyDef=function(e,t){e in this.keyDefs&&console.warn("Duplicate keyCode: "+e),this.keyDefs[e]=t},hterm.Keyboard.KeyMap.prototype.addKeyDefs=function(e){for(var t=0;t",u,i(d,g),u,u],[191,"/?",u,o(n("_"),n("?")),u,u],[17,"[CTRL]",g,g,g,g],[18,"[ALT]",g,g,g,g],[91,"[LAPL]",g,g,g,g],[32," ",u,n("@"),u,u],[92,"[RAPL]",g,g,g,g],[93,"[RMENU]",g,g,g,g],[42,"[PRTSCR]",g,g,g,g],[145,"[SCRLK]",g,g,g,g],[19,"[BREAK]",g,g,g,g],[45,"[INSERT]",a("onKeyInsert_"),u,u,u],[36,"[HOME]",a("onKeyHome_"),u,u,u],[33,"[PGUP]",a("onKeyPageUp_"),u,u,u],[46,"[DEL]",a("onKeyDel_"),u,u,u],[35,"[END]",a("onKeyEnd_"),u,u,u],[34,"[PGDOWN]",a("onKeyPageDown_"),u,u,u],[38,"[UP]",t("","OA"),u,u,u],[40,"[DOWN]",t("","OB"),u,u,u],[39,"[RIGHT]",t("","OC"),u,u,u],[37,"[LEFT]",t("","OD"),u,u,u],[144,"[NUMLOCK]",g,g,g,g],[96,"[KP0]",u,u,u,u],[97,"[KP1]",u,u,u,u],[98,"[KP2]",u,u,u,u],[99,"[KP3]",u,u,u,u],[100,"[KP4]",u,u,u,u],[101,"[KP5]",u,u,u,u],[102,"[KP6]",u,u,u,u],[103,"[KP7]",u,u,u,u],[104,"[KP8]",u,u,u,u],[105,"[KP9]",u,u,u,u],[107,"[KP+]",u,u,u,u],[109,"[KP-]",u,u,u,u],[106,"[KP*]",u,u,u,u],[111,"[KP/]",u,u,u,u],[110,"[KP.]",u,u,u,u],[166,"[BACK]",l(s("OP","")),u,"[23~",u],[167,"[FWD]",l(s("OQ","")),u,"[24~",u],[168,"[RELOAD]",l(s("OR","")),u,"[25~",u],[183,"[FSCR]",l(s("OS","")),u,"[26~",u],[182,"[WINS]",l("[15~"),u,"[28~",u],[216,"[BRIT-]",l("[17~"),u,"[29~",u],[217,"[BRIT+]",l("[18~"),u,"[31~",u])},hterm.Keyboard.KeyMap.prototype.onKeyInsert_=function(e){return this.keyboard.shiftInsertPaste&&e.shiftKey?hterm.Keyboard.KeyActions.PASS:"[2~"},hterm.Keyboard.KeyMap.prototype.onKeyHome_=function(e){return!this.keyboard.homeKeysScroll^e.shiftKey?e.altey||e.ctrlKey||e.shiftKey||!this.keyboard.applicationCursor?"":"OH":(this.keyboard.terminal.scrollHome(),hterm.Keyboard.KeyActions.CANCEL)},hterm.Keyboard.KeyMap.prototype.onKeyEnd_=function(e){return!this.keyboard.homeKeysScroll^e.shiftKey?e.altKey||e.ctrlKey||e.shiftKey||!this.keyboard.applicationCursor?"":"OF":(this.keyboard.terminal.scrollEnd(),hterm.Keyboard.KeyActions.CANCEL)},hterm.Keyboard.KeyMap.prototype.onKeyPageUp_=function(e){return!this.keyboard.pageKeysScroll^e.shiftKey?"[5~":(this.keyboard.terminal.scrollPageUp(),hterm.Keyboard.KeyActions.CANCEL)},hterm.Keyboard.KeyMap.prototype.onKeyDel_=function(e){return this.keyboard.altBackspaceIsMetaBackspace&&this.keyboard.altKeyPressed&&!e.altKey?"":"[3~"},hterm.Keyboard.KeyMap.prototype.onKeyPageDown_=function(e){return!this.keyboard.pageKeysScroll^e.shiftKey?"[6~":(this.keyboard.terminal.scrollPageDown(),hterm.Keyboard.KeyActions.CANCEL)},hterm.Keyboard.KeyMap.prototype.onClear_=function(e,t){return this.keyboard.terminal.wipeContents(),hterm.Keyboard.KeyActions.CANCEL},hterm.Keyboard.KeyMap.prototype.onCtrlNum_=function(e,t){function r(e){return String.fromCharCode(e.charCodeAt(0)-64)}if(this.keyboard.terminal.passCtrlNumber&&!e.shiftKey)return hterm.Keyboard.KeyActions.PASS;switch(t.keyCap.substr(0,1)){case"1":return"1";case"2":return r("@");case"3":return r("[");case"4":return r("\\");case"5":return r("]");case"6":return r("^");case"7":return r("_");case"8":return"";case"9":return"9"}},hterm.Keyboard.KeyMap.prototype.onAltNum_=function(e,t){return this.keyboard.terminal.passAltNumber&&!e.shiftKey?hterm.Keyboard.KeyActions.PASS:hterm.Keyboard.KeyActions.DEFAULT},hterm.Keyboard.KeyMap.prototype.onMetaNum_=function(e,t){return this.keyboard.terminal.passMetaNumber&&!e.shiftKey?hterm.Keyboard.KeyActions.PASS:hterm.Keyboard.KeyActions.DEFAULT},hterm.Keyboard.KeyMap.prototype.onCtrlC_=function(e,t){var r=this.keyboard.terminal.getDocument().getSelection();if(!r.isCollapsed){if(this.keyboard.ctrlCCopy&&!e.shiftKey)return this.keyboard.terminal.clearSelectionAfterCopy&&setTimeout(r.collapseToEnd.bind(r),50),this.keyboard.terminal.prefs_.get("enable-clipboard-notice")&&setTimeout(this.keyboard.terminal.showOverlay.bind(this.keyboard.terminal,hterm.notifyCopyMessage,500),200),hterm.Keyboard.KeyActions.PASS;if(!this.keyboard.ctrlCCopy&&e.shiftKey)return this.keyboard.terminal.clearSelectionAfterCopy&&setTimeout(r.collapseToEnd.bind(r),50),this.keyboard.terminal.copySelectionToClipboard(),hterm.Keyboard.KeyActions.CANCEL}return""},hterm.Keyboard.KeyMap.prototype.onCtrlN_=function(e,t){return e.shiftKey?(window.open(document.location.href,"","chrome=no,close=yes,resize=yes,scrollbars=yes,minimizable=yes,width="+window.innerWidth+",height="+window.innerHeight),hterm.Keyboard.KeyActions.CANCEL):""},hterm.Keyboard.KeyMap.prototype.onCtrlV_=function(e,t){return!e.shiftKey&&this.keyboard.ctrlVPaste||e.shiftKey&&!this.keyboard.ctrlVPaste?hterm.Keyboard.KeyActions.PASS:""},hterm.Keyboard.KeyMap.prototype.onMetaN_=function(e,t){return e.shiftKey?(window.open(document.location.href,"","chrome=no,close=yes,resize=yes,scrollbars=yes,minimizable=yes,width="+window.outerWidth+",height="+window.outerHeight),hterm.Keyboard.KeyActions.CANCEL):hterm.Keyboard.KeyActions.DEFAULT},hterm.Keyboard.KeyMap.prototype.onMetaC_=function(e,t){var r=this.keyboard.terminal.getDocument();return e.shiftKey||r.getSelection().isCollapsed?t.keyCap.substr(e.shiftKey?1:0,1):(this.keyboard.terminal.clearSelectionAfterCopy&&setTimeout(function(){r.getSelection().collapseToEnd()},50),hterm.Keyboard.KeyActions.PASS)},hterm.Keyboard.KeyMap.prototype.onMetaV_=function(e,t){return e.shiftKey?hterm.Keyboard.KeyActions.PASS:this.keyboard.passMetaV?hterm.Keyboard.KeyActions.PASS:hterm.Keyboard.KeyActions.DEFAULT},hterm.Keyboard.KeyMap.prototype.onPlusMinusZero_=function(e,t){if(!(this.keyboard.ctrlPlusMinusZeroZoom^e.shiftKey))return"-_"==t.keyCap?"":hterm.Keyboard.KeyActions.CANCEL;if(1!=this.keyboard.terminal.getZoomFactor())return hterm.Keyboard.KeyActions.PASS;var r=t.keyCap.substr(0,1);if("0"==r)this.keyboard.terminal.setFontSize(0);else{var o=this.keyboard.terminal.getFontSize();"-"==r?o-=1:o+=1,this.keyboard.terminal.setFontSize(o)}return hterm.Keyboard.KeyActions.CANCEL},hterm.Options=function(e){this.wraparound=!e||e.wraparound,this.reverseWraparound=!!e&&e.reverseWraparound,this.originMode=!!e&&e.originMode,this.autoCarriageReturn=!!e&&e.autoCarriageReturn,this.cursorVisible=!!e&&e.cursorVisible,this.cursorBlink=!!e&&e.cursorBlink,this.insertMode=!!e&&e.insertMode,this.reverseVideo=!!e&&e.reverseVideo,this.bracketedPaste=!!e&&e.bracketedPaste},lib.rtdep("lib.f","lib.Storage"),hterm.PreferenceManager=function(e){lib.PreferenceManager.call(this,hterm.defaultStorage,"/hterm/profiles/"+e);var t=hterm.PreferenceManager.defaultPreferences;Object.keys(t).forEach(function(e){this.definePreference(e,t[e])}.bind(this))},hterm.PreferenceManager.defaultPreferences={"alt-gr-mode":null,"alt-backspace-is-meta-backspace":!1,"alt-is-meta":!1,"alt-sends-what":"escape","audible-bell-sound":"lib-resource:hterm/audio/bell","desktop-notification-bell":!1,"background-color":"rgb(16, 16, 16)","background-image":"","background-size":"","background-position":"","backspace-sends-backspace":!1,"character-map-overrides":null,"close-on-exit":!0,"cursor-blink":!1,"cursor-blink-cycle":[1e3,500],"cursor-color":"rgba(255, 0, 0, 0.5)","color-palette-overrides":null,"copy-on-select":!0,"use-default-window-copy":!1,"clear-selection-after-copy":!0,"ctrl-plus-minus-zero-zoom":!0,"ctrl-c-copy":!1,"ctrl-v-paste":!1,"east-asian-ambiguous-as-two-column":!1,"enable-8-bit-control":!1,"enable-bold":null,"enable-bold-as-bright":!0,"enable-clipboard-notice":!0,"enable-clipboard-write":!0,"enable-dec12":!1,environment:{TERM:"xterm-256color"},"font-family":'"DejaVu Sans Mono", "Everson Mono", FreeMono, "Menlo", "Terminal", monospace',"font-size":15,"font-smoothing":"antialiased","foreground-color":"rgb(240, 240, 240)","home-keys-scroll":!1,"max-string-sequence":1e5,"media-keys-are-fkeys":!1,"meta-sends-escape":!0,"mouse-paste-button":null,"page-keys-scroll":!1,"pass-alt-number":null,"pass-ctrl-number":null,"pass-meta-number":null,"pass-meta-v":!0,"receive-encoding":"utf-8","scroll-on-keystroke":!0,"scroll-on-output":!1,"scrollbar-visible":!0,"scroll-wheel-move-multiplier":1,"send-encoding":"utf-8","shift-insert-paste":!0,"user-css":""},hterm.PreferenceManager.prototype={__proto__:lib.PreferenceManager.prototype},hterm.PubSub=function(){this.observers_={}},hterm.PubSub.addBehavior=function(e){var t=new hterm.PubSub;for(var r in hterm.PubSub.prototype)e[r]=hterm.PubSub.prototype[r].bind(t)},hterm.PubSub.prototype.subscribe=function(e,t){e in this.observers_||(this.observers_[e]=[]),this.observers_[e].push(t)},hterm.PubSub.prototype.unsubscribe=function(e,t){var r=this.observers_[e];if(!r)throw"Invalid subject: "+e;var o=r.indexOf(t);if(o<0)throw"Not subscribed: "+e;r.splice(o,1)},hterm.PubSub.prototype.publish=function(e,t,r){function o(e){e=e&&this.setCursorPosition(this.cursorPosition.row,e-1)},hterm.Screen.prototype.shiftRow=function(){return this.shiftRows(1)[0]},hterm.Screen.prototype.shiftRows=function(e){return this.rowsArray.splice(0,e)},hterm.Screen.prototype.unshiftRow=function(e){this.rowsArray.splice(0,0,e)},hterm.Screen.prototype.unshiftRows=function(e){this.rowsArray.unshift.apply(this.rowsArray,e)},hterm.Screen.prototype.popRow=function(){return this.popRows(1)[0]},hterm.Screen.prototype.popRows=function(e){return this.rowsArray.splice(this.rowsArray.length-e,e)},hterm.Screen.prototype.pushRow=function(e){this.rowsArray.push(e)},hterm.Screen.prototype.pushRows=function(e){e.push.apply(this.rowsArray,e)},hterm.Screen.prototype.insertRow=function(e,t){this.rowsArray.splice(e,0,t)},hterm.Screen.prototype.insertRows=function(e,t){for(var r=0;r=this.rowsArray.length?(console.error("Row out of bounds: "+e),e=this.rowsArray.length-1):e<0&&(console.error("Row out of bounds: "+e),e=0),t>=this.columnCount_?(console.error("Column out of bounds: "+t),t=this.columnCount_-1):t<0&&(console.error("Column out of bounds: "+t),t=0),this.cursorPosition.overflow=!1;var r=this.rowsArray[e],o=r.firstChild;o||(o=r.ownerDocument.createTextNode(""),r.appendChild(o));var i=0;for(r==this.cursorRowNode_?t>=this.cursorPosition.column-this.cursorOffset_&&(o=this.cursorNode_,i=this.cursorPosition.column-this.cursorOffset_):this.cursorRowNode_=r,this.cursorPosition.move(e,t);o;){var s=t-i,n=hterm.TextAttributes.nodeWidth(o);if(!o.nextSibling||n>s)return this.cursorNode_=o,void(this.cursorOffset_=s);i+=n,o=o.nextSibling}}else console.warn("Attempt to set cursor position on empty screen.")},hterm.Screen.prototype.syncSelectionCaret=function(e){try{e.collapse(this.cursorNode_,this.cursorOffset_)}catch(e){}},hterm.Screen.prototype.splitNode_=function(e,t){var r=e.cloneNode(!1),o=e.textContent;e.textContent=hterm.TextAttributes.nodeSubstr(e,0,t),r.textContent=lib.wc.substr(o,t),r.textContent&&e.parentNode.insertBefore(r,e.nextSibling),e.textContent||e.parentNode.removeChild(e)},hterm.Screen.prototype.maybeClipCurrentRow=function(){var e=hterm.TextAttributes.nodeWidth(this.cursorRowNode_);if(e<=this.columnCount_)this.cursorPosition.column>=this.columnCount_&&(this.setCursorPosition(this.cursorPosition.row,this.columnCount_-1),this.cursorPosition.overflow=!0);else{var t=this.cursorPosition.column;this.setCursorPosition(this.cursorPosition.row,this.columnCount_-1),e=hterm.TextAttributes.nodeWidth(this.cursorNode_),this.cursorOffset_hterm.TextAttributes.nodeWidth(e);){if(!e.hasAttribute("line-overflow")||!e.nextSibling)return-1;t-=hterm.TextAttributes.nodeWidth(e),e=e.nextSibling}return this.getNodeAndOffsetWithinRow_(e,t)},hterm.Screen.prototype.getNodeAndOffsetWithinRow_=function(e,t){for(var r=0;r\"'\\^!@#$%&*,;:`][^\\s\\[\\](){}<>\"'\\^]*$"),l=n.search(a);if(!(-1==l||l>o)){var h=lib.wc.substring(s,o,lib.wc.strWidth(s)),c=new RegExp("^[^\\s\\[\\](){}<>\"'\\^]*[^\\s\\[\\](){}<>\"'\\^!@#$%&*,;:~.`]"),u=h.match(c);if(u){var g=o+lib.wc.strWidth(u[0]);-1==g||gs.rowIndex)t();else if(o.focusNode==o.anchorNode)o.anchorOffset=this.lastRowCount_},hterm.ScrollPort.prototype.drawTopFold_=function(e){if(!this.selection.startRow||this.selection.startRow.rowIndex>=e)this.rowNodes_.firstChild!=this.topFold_&&this.rowNodes_.insertBefore(this.topFold_,this.rowNodes_.firstChild);else{if(!this.selection.isMultiline||this.selection.endRow.rowIndex>=e)this.selection.startRow.nextSibling!=this.topFold_&&this.rowNodes_.insertBefore(this.topFold_,this.selection.startRow.nextSibling);else for(this.selection.endRow.nextSibling!=this.topFold_&&this.rowNodes_.insertBefore(this.topFold_,this.selection.endRow.nextSibling);this.selection.startRow.nextSibling!=this.selection.endRow;)this.rowNodes_.removeChild(this.selection.startRow.nextSibling);for(;this.rowNodes_.firstChild!=this.selection.startRow;)this.rowNodes_.removeChild(this.rowNodes_.firstChild)}},hterm.ScrollPort.prototype.drawBottomFold_=function(e){if(!this.selection.endRow||this.selection.endRow.rowIndex<=e)this.rowNodes_.lastChild!=this.bottomFold_&&this.rowNodes_.appendChild(this.bottomFold_);else{if(!this.selection.isMultiline||this.selection.startRow.rowIndex<=e)this.bottomFold_.nextSibling!=this.selection.endRow&&this.rowNodes_.insertBefore(this.bottomFold_,this.selection.endRow);else for(this.bottomFold_.nextSibling!=this.selection.startRow&&this.rowNodes_.insertBefore(this.bottomFold_,this.selection.startRow);this.selection.startRow.nextSibling!=this.selection.endRow;)this.rowNodes_.removeChild(this.selection.startRow.nextSibling);for(;this.rowNodes_.lastChild!=this.selection.endRow;)this.rowNodes_.removeChild(this.rowNodes_.lastChild)}},hterm.ScrollPort.prototype.drawVisibleRows_=function(e,t){function r(e,t){for(;e!=t;){if(!e)throw"Did not encounter target node";if(e==o.bottomFold_)throw"Encountered bottom fold before target node";var r=e;e=e.nextSibling,r.parentNode.removeChild(r)}}for(var o=this,i=this.selection.startRow,s=this.selection.endRow,n=this.bottomFold_,a=this.topFold_.nextSibling,l=Math.min(this.visibleRowCount,this.rowProvider_.getRowCount()),h=0;h=this.lastRowCount_;var t=e*this.characterSize.height+this.visibleRowTopMargin,r=this.getScrollMax_();t>r&&(t=r),this.screen_.scrollTop!=t&&(this.screen_.scrollTop=t,this.scheduleRedraw())},hterm.ScrollPort.prototype.scrollRowToBottom=function(e){this.syncScrollHeight(),this.isScrolledEnd=e+this.visibleRowCount>=this.lastRowCount_;var t=e*this.characterSize.height+this.visibleRowTopMargin+this.visibleRowBottomMargin;(t-=this.visibleRowCount*this.characterSize.height)<0&&(t=0),this.screen_.scrollTop!=t&&(this.screen_.scrollTop=t)},hterm.ScrollPort.prototype.getTopRowIndex=function(){return lib.f.smartFloorDivide(this.screen_.scrollTop,this.characterSize.height)},hterm.ScrollPort.prototype.getBottomRowIndex=function(e){return e+this.visibleRowCount-1},hterm.ScrollPort.prototype.onScroll_=function(e){var t=this.getScreenSize();t.width==this.lastScreenWidth_&&t.height==this.lastScreenHeight_?(this.redraw_(),this.publish("scroll",{scrollPort:this})):this.resize()},hterm.ScrollPort.prototype.onScrollWheel=function(e){},hterm.ScrollPort.prototype.onScrollWheel_=function(e){if(this.onScrollWheel(e),!e.defaultPrevented){var t="DOMMouseScroll"==e.type?-1*e.detail:e.wheelDeltaY;t*=this.scrollWheelMultiplier_;var r=this.screen_.scrollTop-t;r<0&&(r=0);var o=this.getScrollMax_();r>o&&(r=o),r!=this.screen_.scrollTop&&(this.screen_.scrollTop=r,e.preventDefault())}},hterm.ScrollPort.prototype.onResize_=function(e){this.syncCharacterSize(),this.resize()},hterm.ScrollPort.prototype.onCopy=function(e){},hterm.ScrollPort.prototype.onCopy_=function(e){if(this.onCopy(e),!e.defaultPrevented&&(this.resetSelectBags_(),this.selection.sync(),this.selection.startRow&&!(this.selection.endRow.rowIndex-this.selection.startRow.rowIndex<2))){var t=this.getTopRowIndex(),r=this.getBottomRowIndex(t);if(this.selection.startRow.rowIndexr){var i;i=this.selection.startRow.rowIndex>r?this.selection.startRow.rowIndex+1:this.bottomFold_.previousSibling.rowIndex+1,this.bottomSelectBag_.textContent=this.rowProvider_.getRowsText(i,this.selection.endRow.rowIndex),this.rowNodes_.insertBefore(this.bottomSelectBag_,this.selection.endRow)}}},hterm.ScrollPort.prototype.onBodyKeyDown_=function(e){if(this.ctrlVPaste){var t=String.fromCharCode(e.which).toLowerCase();(e.ctrlKey||e.metaKey)&&"v"==t&&this.pasteTarget_.focus()}},hterm.ScrollPort.prototype.onPaste_=function(e){this.pasteTarget_.focus();var t=this;setTimeout(function(){t.publish("paste",{text:t.pasteTarget_.value}),t.pasteTarget_.value="",t.screen_.focus()},0)},hterm.ScrollPort.prototype.handlePasteTargetTextInput_=function(e){e.stopPropagation()},hterm.ScrollPort.prototype.setScrollbarVisible=function(e){this.screen_.style.overflowY=e?"scroll":"hidden"},hterm.ScrollPort.prototype.setScrollWheelMoveMultipler=function(e){this.scrollWheelMultiplier_=e},lib.rtdep("lib.colors","lib.PreferenceManager","lib.resource","lib.wc","lib.f","hterm.Keyboard","hterm.Options","hterm.PreferenceManager","hterm.Screen","hterm.ScrollPort","hterm.Size","hterm.TextAttributes","hterm.VT"),hterm.Terminal=function(e){this.profileId_=null,this.primaryScreen_=new hterm.Screen,this.alternateScreen_=new hterm.Screen,this.screen_=this.primaryScreen_,this.screenSize=new hterm.Size(0,0),this.scrollPort_=new hterm.ScrollPort(this),this.scrollPort_.subscribe("resize",this.onResize_.bind(this)),this.scrollPort_.subscribe("scroll",this.onScroll_.bind(this)),this.scrollPort_.subscribe("paste",this.onPaste_.bind(this)),this.scrollPort_.onCopy=this.onCopy_.bind(this),this.div_=null,this.document_=window.document,this.scrollbackRows_=[],this.tabStops_=[],this.defaultTabStops=!0,this.vtScrollTop_=null,this.vtScrollBottom_=null,this.cursorNode_=null,this.cursorShape_=hterm.Terminal.cursorShape.BLOCK,this.cursorColor_=null,this.cursorBlinkCycle_=[100,100],this.myOnCursorBlink_=this.onCursorBlink_.bind(this),this.backgroundColor_=null,this.foregroundColor_=null,this.scrollOnOutput_=null,this.scrollOnKeystroke_=null,this.reportMouseEvents_=!1,this.bellAudio_=this.document_.createElement("audio"),this.bellAudio_.setAttribute("preload","auto"),this.bellNotificationList_=[],this.desktopNotificationBell_=!1,this.savedOptions_={},this.options_=new hterm.Options,this.timeouts_={},this.vt=new hterm.VT(this),this.keyboard=new hterm.Keyboard(this),this.io=new hterm.Terminal.IO(this),this.enableMouseDragScroll=!0,this.copyOnSelect=null,this.mousePasteButton=null,this.useDefaultWindowCopy=!1,this.clearSelectionAfterCopy=!0,this.realizeSize_(80,24),this.setDefaultTabStops(),this.setProfile(e||"default",function(){this.onTerminalReady()}.bind(this))},hterm.Terminal.cursorShape={BLOCK:"BLOCK",BEAM:"BEAM",UNDERLINE:"UNDERLINE"},hterm.Terminal.prototype.onTerminalReady=function(){},hterm.Terminal.prototype.tabWidth=8,hterm.Terminal.prototype.setProfile=function(e,t){this.profileId_=e.replace(/\//g,"");var r=this;this.prefs_&&this.prefs_.deactivate(),this.prefs_=new hterm.PreferenceManager(this.profileId_),this.prefs_.addObservers(null,{"alt-gr-mode":function(e){e=null==e?"en-us"==navigator.language.toLowerCase()?"none":"right-alt":"string"==typeof e?e.toLowerCase():"none",/^(none|ctrl-alt|left-alt|right-alt)$/.test(e)||(e="none"),r.keyboard.altGrMode=e},"alt-backspace-is-meta-backspace":function(e){r.keyboard.altBackspaceIsMetaBackspace=e},"alt-is-meta":function(e){r.keyboard.altIsMeta=e},"alt-sends-what":function(e){/^(escape|8-bit|browser-key)$/.test(e)||(e="escape"),r.keyboard.altSendsWhat=e},"audible-bell-sound":function(e){var t=e.match(/^lib-resource:(\S+)/);t?r.bellAudio_.setAttribute("src",lib.resource.getDataUrl(t[1])):r.bellAudio_.setAttribute("src",e)},"desktop-notification-bell":function(e){e&&Notification?(r.desktopNotificationBell_="granted"===Notification.permission,r.desktopNotificationBell_||console.warn("desktop-notification-bell is true but we do not have permission to display notifications.")):r.desktopNotificationBell_=!1},"background-color":function(e){r.setBackgroundColor(e)},"background-image":function(e){r.scrollPort_.setBackgroundImage(e)},"background-size":function(e){r.scrollPort_.setBackgroundSize(e)},"background-position":function(e){r.scrollPort_.setBackgroundPosition(e)},"backspace-sends-backspace":function(e){r.keyboard.backspaceSendsBackspace=e},"character-map-overrides":function(e){if(null==e||e instanceof Object)for(var t in e){var r=hterm.VT.CharacterMap.maps[t].glmap;for(var o in e[t])r[o]=e[t][o];hterm.VT.CharacterMap.maps[t].reset(r)}else console.warn("Preference character-map-modifications is not an object: "+e)},"cursor-blink":function(e){r.setCursorBlink(!!e)},"cursor-blink-cycle":function(e){e instanceof Array&&"number"==typeof e[0]&&"number"==typeof e[1]?r.cursorBlinkCycle_=e:r.cursorBlinkCycle_="number"==typeof e?[e,e]:[100,100]},"cursor-color":function(e){r.setCursorColor(e)},"color-palette-overrides":function(e){if(null==e||e instanceof Object||e instanceof Array){if(lib.colors.colorPalette=lib.colors.stockColorPalette.concat(),e)for(var t in e){var o=parseInt(t);if(isNaN(o)||o<0||o>255)console.log("Invalid value in palette: "+t+": "+e[t]);else if(e[o]){var i=lib.colors.normalizeCSS(e[o]);i&&(lib.colors.colorPalette[o]=i)}}r.primaryScreen_.textAttributes.resetColorPalette(),r.alternateScreen_.textAttributes.resetColorPalette()}else console.warn("Preference color-palette-overrides is not an array or object: "+e)},"copy-on-select":function(e){r.copyOnSelect=!!e},"use-default-window-copy":function(e){r.useDefaultWindowCopy=!!e},"clear-selection-after-copy":function(e){r.clearSelectionAfterCopy=!!e},"ctrl-plus-minus-zero-zoom":function(e){r.keyboard.ctrlPlusMinusZeroZoom=e},"ctrl-c-copy":function(e){r.keyboard.ctrlCCopy=e},"ctrl-v-paste":function(e){r.keyboard.ctrlVPaste=e,r.scrollPort_.setCtrlVPaste(e)},"east-asian-ambiguous-as-two-column":function(e){lib.wc.regardCjkAmbiguous=e},"enable-8-bit-control":function(e){r.vt.enable8BitControl=!!e},"enable-bold":function(e){r.syncBoldSafeState()},"enable-bold-as-bright":function(e){r.primaryScreen_.textAttributes.enableBoldAsBright=!!e,r.alternateScreen_.textAttributes.enableBoldAsBright=!!e},"enable-clipboard-write":function(e){r.vt.enableClipboardWrite=!!e},"enable-dec12":function(e){r.vt.enableDec12=!!e},"font-family":function(e){r.syncFontFamily()},"font-size":function(e){r.setFontSize(e)},"font-smoothing":function(e){r.syncFontFamily()},"foreground-color":function(e){r.setForegroundColor(e)},"home-keys-scroll":function(e){r.keyboard.homeKeysScroll=e},"max-string-sequence":function(e){r.vt.maxStringSequence=e},"media-keys-are-fkeys":function(e){r.keyboard.mediaKeysAreFKeys=e},"meta-sends-escape":function(e){r.keyboard.metaSendsEscape=e},"mouse-paste-button":function(e){r.syncMousePasteButton()},"page-keys-scroll":function(e){r.keyboard.pageKeysScroll=e},"pass-alt-number":function(e){null==e&&(e=!window.navigator.userAgent.match(/Mac OS X/)&&"popup"!=hterm.windowType),r.passAltNumber=e},"pass-ctrl-number":function(e){null==e&&(e=!window.navigator.userAgent.match(/Mac OS X/)&&"popup"!=hterm.windowType),r.passCtrlNumber=e},"pass-meta-number":function(e){null==e&&(e=window.navigator.userAgent.match(/Mac OS X/)&&"popup"!=hterm.windowType),r.passMetaNumber=e},"pass-meta-v":function(e){r.keyboard.passMetaV=e},"receive-encoding":function(e){/^(utf-8|raw)$/.test(e)||(console.warn('Invalid value for "receive-encoding": '+e),e="utf-8"),r.vt.characterEncoding=e},"scroll-on-keystroke":function(e){r.scrollOnKeystroke_=e},"scroll-on-output":function(e){r.scrollOnOutput_=e},"scrollbar-visible":function(e){r.setScrollbarVisible(e)},"scroll-wheel-move-multiplier":function(e){r.setScrollWheelMoveMultipler(e)},"send-encoding":function(e){/^(utf-8|raw)$/.test(e)||(console.warn('Invalid value for "send-encoding": '+e),e="utf-8"),r.keyboard.characterEncoding=e},"shift-insert-paste":function(e){r.keyboard.shiftInsertPaste=e},"user-css":function(e){r.scrollPort_.setUserCss(e)}}),this.prefs_.readStorage(function(){this.prefs_.notifyAll(),t&&t()}.bind(this))},hterm.Terminal.prototype.getPrefs=function(){return this.prefs_},hterm.Terminal.prototype.setBracketedPaste=function(e){this.options_.bracketedPaste=e},hterm.Terminal.prototype.setCursorColor=function(e){this.cursorColor_=e,this.cursorNode_.style.backgroundColor=e,this.cursorNode_.style.borderColor=e},hterm.Terminal.prototype.getCursorColor=function(){return this.cursorColor_},hterm.Terminal.prototype.setSelectionEnabled=function(e){this.enableMouseDragScroll=e},hterm.Terminal.prototype.setBackgroundColor=function(e){this.backgroundColor_=lib.colors.normalizeCSS(e),this.primaryScreen_.textAttributes.setDefaults(this.foregroundColor_,this.backgroundColor_),this.alternateScreen_.textAttributes.setDefaults(this.foregroundColor_,this.backgroundColor_),this.scrollPort_.setBackgroundColor(e)},hterm.Terminal.prototype.getBackgroundColor=function(){return this.backgroundColor_},hterm.Terminal.prototype.setForegroundColor=function(e){this.foregroundColor_=lib.colors.normalizeCSS(e),this.primaryScreen_.textAttributes.setDefaults(this.foregroundColor_,this.backgroundColor_),this.alternateScreen_.textAttributes.setDefaults(this.foregroundColor_,this.backgroundColor_),this.scrollPort_.setForegroundColor(e)},hterm.Terminal.prototype.getForegroundColor=function(){return this.foregroundColor_},hterm.Terminal.prototype.runCommandClass=function(e,t){var r=this.prefs_.get("environment");"object"==(void 0===r?"undefined":_typeof(r))&&null!=r||(r={});var o=this;this.command=new e({argString:t||"",io:this.io.push(),environment:r,onExit:function(e){o.io.pop(),o.uninstallKeyboard(),o.prefs_.get("close-on-exit")&&window.close()}}),this.installKeyboard(),this.command.run()},hterm.Terminal.prototype.isPrimaryScreen=function(){return this.screen_==this.primaryScreen_},hterm.Terminal.prototype.installKeyboard=function(){this.keyboard.installKeyboard(this.scrollPort_.getDocument().body)},hterm.Terminal.prototype.uninstallKeyboard=function(){this.keyboard.installKeyboard(null)},hterm.Terminal.prototype.setFontSize=function(e){0===e&&(e=this.prefs_.get("font-size")),this.scrollPort_.setFontSize(e),this.wcCssRule_&&(this.wcCssRule_.style.width=2*this.scrollPort_.characterSize.width+"px")},hterm.Terminal.prototype.getFontSize=function(){return this.scrollPort_.getFontSize()},hterm.Terminal.prototype.getFontFamily=function(){return this.scrollPort_.getFontFamily()},hterm.Terminal.prototype.syncFontFamily=function(){this.scrollPort_.setFontFamily(this.prefs_.get("font-family"),this.prefs_.get("font-smoothing")),this.syncBoldSafeState()},hterm.Terminal.prototype.syncMousePasteButton=function(){var e=this.prefs_.get("mouse-paste-button");if("number"!=typeof e){var t=navigator.userAgent.match(/\(X11;\s+(\S+)/);t&&"CrOS"!=t[2]?this.mousePasteButton=3:this.mousePasteButton=2}else this.mousePasteButton=e},hterm.Terminal.prototype.syncBoldSafeState=function(){var e=this.prefs_.get("enable-bold");if(null!==e)return this.primaryScreen_.textAttributes.enableBold=e,void(this.alternateScreen_.textAttributes.enableBold=e);var t=this.scrollPort_.measureCharacterSize(),r=this.scrollPort_.measureCharacterSize("bold"),o=t.equals(r);o||console.warn("Bold characters disabled: Size of bold weight differs from normal. Font family is: "+this.scrollPort_.getFontFamily()),this.primaryScreen_.textAttributes.enableBold=o,this.alternateScreen_.textAttributes.enableBold=o},hterm.Terminal.prototype.saveCursor=function(){return this.screen_.cursorPosition.clone()},hterm.Terminal.prototype.getTextAttributes=function(){return this.screen_.textAttributes},hterm.Terminal.prototype.setTextAttributes=function(e){this.screen_.textAttributes=e},hterm.Terminal.prototype.getZoomFactor=function(){return this.scrollPort_.characterSize.zoomFactor},hterm.Terminal.prototype.setWindowTitle=function(e){window.document.title=e},hterm.Terminal.prototype.restoreCursor=function(e){var t=lib.f.clamp(e.row,0,this.screenSize.height-1),r=lib.f.clamp(e.column,0,this.screenSize.width-1);this.screen_.setCursorPosition(t,r),(e.column>r||e.column==r&&e.overflow)&&(this.screen_.cursorPosition.overflow=!0)},hterm.Terminal.prototype.clearCursorOverflow=function(){this.screen_.cursorPosition.overflow=!1},hterm.Terminal.prototype.setCursorShape=function(e){this.cursorShape_=e,this.restyleCursor_()},hterm.Terminal.prototype.getCursorShape=function(){return this.cursorShape_},hterm.Terminal.prototype.setWidth=function(e){null!=e?(this.div_.style.width=Math.ceil(this.scrollPort_.characterSize.width*e+this.scrollPort_.currentScrollbarWidthPx)+"px",this.realizeSize_(e,this.screenSize.height),this.scheduleSyncCursorPosition_()):this.div_.style.width="100%"},hterm.Terminal.prototype.setHeight=function(e){null!=e?(this.div_.style.height=this.scrollPort_.characterSize.height*e+"px",this.realizeSize_(this.screenSize.width,e),this.scheduleSyncCursorPosition_()):this.div_.style.height="100%"},hterm.Terminal.prototype.realizeSize_=function(e,t){e!=this.screenSize.width&&this.realizeWidth_(e),t!=this.screenSize.height&&this.realizeHeight_(t),this.io.onTerminalResize_(e,t)},hterm.Terminal.prototype.realizeWidth_=function(e){if(e<=0)throw new Error("Attempt to realize bad width: "+e);var t=e-this.screen_.getWidth();if(this.screenSize.width=e,this.screen_.setColumnCount(e),t>0)this.defaultTabStops&&this.setDefaultTabStops(this.screenSize.width-t);else for(var r=this.tabStops_.length-1;r>=0&&!(this.tabStops_[r]0){if(t<=this.scrollbackRows_.length){var s=Math.min(t,this.scrollbackRows_.length),n=this.scrollbackRows_.splice(this.scrollbackRows_.length-s,s);this.screen_.unshiftRows(n),t-=s,r.row+=s}t&&this.appendRows_(t)}this.setVTScrollRegion(null,null),this.restoreCursor(r)},hterm.Terminal.prototype.scrollHome=function(){this.scrollPort_.scrollRowToTop(0)},hterm.Terminal.prototype.scrollEnd=function(){this.scrollPort_.scrollRowToBottom(this.getRowCount())},hterm.Terminal.prototype.scrollPageUp=function(){var e=this.scrollPort_.getTopRowIndex();this.scrollPort_.scrollRowToTop(e-this.screenSize.height+1)},hterm.Terminal.prototype.scrollPageDown=function(){var e=this.scrollPort_.getTopRowIndex();this.scrollPort_.scrollRowToTop(e+this.screenSize.height-1)},hterm.Terminal.prototype.wipeContents=function(){this.scrollbackRows_.length=0,this.scrollPort_.resetCache(),[this.primaryScreen_,this.alternateScreen_].forEach(function(e){var t=e.getHeight();t>0&&(this.renumberRows_(0,t),this.clearHome(e))}.bind(this)),this.syncCursorPosition_(),this.scrollPort_.invalidate()},hterm.Terminal.prototype.reset=function(){this.clearAllTabStops(),this.setDefaultTabStops(),this.clearHome(this.primaryScreen_),this.primaryScreen_.textAttributes.reset(),this.clearHome(this.alternateScreen_),this.alternateScreen_.textAttributes.reset(),this.setCursorBlink(!!this.prefs_.get("cursor-blink")),this.vt.reset(),this.softReset()},hterm.Terminal.prototype.softReset=function(){this.options_=new hterm.Options,this.options_.cursorBlink=!!this.timeouts_.cursorBlink,this.primaryScreen_.textAttributes.resetColorPalette(),this.alternateScreen_.textAttributes.resetColorPalette(),this.setVTScrollRegion(null,null),this.setCursorVisible(!0)},hterm.Terminal.prototype.forwardTabStop=function(){for(var e=this.screen_.cursorPosition.column,t=0;te)return void this.setCursorColumn(this.tabStops_[t]);var r=this.screen_.cursorPosition.overflow;this.setCursorColumn(this.screenSize.width-1),this.screen_.cursorPosition.overflow=r},hterm.Terminal.prototype.backwardTabStop=function(){for(var e=this.screen_.cursorPosition.column,t=this.tabStops_.length-1;t>=0;t--)if(this.tabStops_[t]=0;t--){if(this.tabStops_[t]==e)return;if(this.tabStops_[t]0){var n=this.screen_.shiftRows(s);Array.prototype.push.apply(this.scrollbackRows_,n),this.scrollPort_.isScrolledEnd&&this.scheduleScrollDown_()}t>=this.screen_.rowsArray.length&&(t=this.screen_.rowsArray.length-1),this.setAbsoluteCursorPosition(t,0)},hterm.Terminal.prototype.moveRows_=function(e,t,r){var o=this.screen_.removeRows(e,t);this.screen_.insertRows(r,o);var i,s;e=this.screenSize.width&&(s=!0,i=this.screenSize.width-this.screen_.cursorPosition.column),s&&!this.options_.wraparound?(o=lib.wc.substr(e,t,i-1)+lib.wc.substr(e,r-1),i=r):o=lib.wc.substr(e,t,i);for(var n=hterm.TextAttributes.splitWidecharString(o),a=0;a=0;i--)this.setAbsoluteCursorPosition(t+i,0),this.screen_.clearCursorRow()},hterm.Terminal.prototype.deleteLines=function(e){var t=this.saveCursor(),r=t.row,o=this.getVTScrollBottom(),i=o-r+1,s=o-(e=Math.min(e,i))+1;e!=i&&this.moveRows_(r,e,s);for(var n=0;nt)this.cursorNode_.style.top=-this.scrollPort_.characterSize.height+"px";else{this.options_.cursorVisible&&"none"==this.cursorNode_.style.display&&(this.cursorNode_.style.display=""),this.cursorNode_.style.top=this.scrollPort_.visibleRowTopMargin+this.scrollPort_.characterSize.height*(r-e)+"px",this.cursorNode_.style.left=this.scrollPort_.characterSize.width*this.screen_.cursorPosition.column+"px",this.cursorNode_.setAttribute("title","("+this.screen_.cursorPosition.row+", "+this.screen_.cursorPosition.column+")");var o=this.document_.getSelection();o&&o.isCollapsed&&this.screen_.syncSelectionCaret(o)}},hterm.Terminal.prototype.restyleCursor_=function(){var e=this.cursorShape_;"false"==this.cursorNode_.getAttribute("focus")&&(e=hterm.Terminal.cursorShape.BLOCK);var t=this.cursorNode_.style;switch(t.width=this.scrollPort_.characterSize.width+"px",e){case hterm.Terminal.cursorShape.BEAM:t.height=this.scrollPort_.characterSize.height+"px",t.backgroundColor="transparent",t.borderBottomStyle=null,t.borderLeftStyle="solid";break;case hterm.Terminal.cursorShape.UNDERLINE:t.height=this.scrollPort_.characterSize.baseline+"px",t.backgroundColor="transparent",t.borderBottomStyle="solid",t.borderLeftStyle=null;break;default:t.height=this.scrollPort_.characterSize.height+"px",t.backgroundColor=this.cursorColor_,t.borderBottomStyle=null,t.borderLeftStyle=null}},hterm.Terminal.prototype.scheduleSyncCursorPosition_=function(){if(!this.timeouts_.syncCursor){var e=this;this.timeouts_.syncCursor=setTimeout(function(){e.syncCursorPosition_(),delete e.timeouts_.syncCursor},0)}},hterm.Terminal.prototype.showZoomWarning_=function(e){if(!this.zoomWarningNode_){if(!e)return;this.zoomWarningNode_=this.document_.createElement("div"),this.zoomWarningNode_.style.cssText="color: black;background-color: #ff2222;font-size: large;border-radius: 8px;opacity: 0.75;padding: 0.2em 0.5em 0.2em 0.5em;top: 0.5em;right: 1.2em;position: absolute;-webkit-text-size-adjust: none;-webkit-user-select: none;-moz-text-size-adjust: none;-moz-user-select: none;"}this.zoomWarningNode_.textContent=lib.MessageManager.replaceReferences(hterm.zoomWarningMessage,[parseInt(100*this.scrollPort_.characterSize.zoomFactor)]),this.zoomWarningNode_.style.fontFamily=this.prefs_.get("font-family"),e?this.zoomWarningNode_.parentNode||this.div_.parentNode.appendChild(this.zoomWarningNode_):this.zoomWarningNode_.parentNode&&this.zoomWarningNode_.parentNode.removeChild(this.zoomWarningNode_)},hterm.Terminal.prototype.showOverlay=function(e,t){if(!this.overlayNode_){if(!this.div_)return;this.overlayNode_=this.document_.createElement("div"),this.overlayNode_.style.cssText="border-radius: 15px;font-size: xx-large;opacity: 0.75;padding: 0.2em 0.5em 0.2em 0.5em;position: absolute;-webkit-user-select: none;-webkit-transition: opacity 180ms ease-in;-moz-user-select: none;-moz-transition: opacity 180ms ease-in;",this.overlayNode_.addEventListener("mousedown",function(e){e.preventDefault(),e.stopPropagation()},!0)}this.overlayNode_.style.color=this.prefs_.get("background-color"),this.overlayNode_.style.backgroundColor=this.prefs_.get("foreground-color"),this.overlayNode_.style.fontFamily=this.prefs_.get("font-family"),this.overlayNode_.textContent=e,this.overlayNode_.style.opacity="0.75",this.overlayNode_.parentNode||this.div_.appendChild(this.overlayNode_);var r=hterm.getClientSize(this.div_),o=hterm.getClientSize(this.overlayNode_);this.overlayNode_.style.top=(r.height-o.height)/2+"px",this.overlayNode_.style.left=(r.width-o.width-this.scrollPort_.currentScrollbarWidthPx)/2+"px";var i=this;this.overlayTimeout_&&clearTimeout(this.overlayTimeout_),null!==t&&(this.overlayTimeout_=setTimeout(function(){i.overlayNode_.style.opacity="0",i.overlayTimeout_=setTimeout(function(){i.overlayNode_.parentNode&&i.overlayNode_.parentNode.removeChild(i.overlayNode_),i.overlayTimeout_=null,i.overlayNode_.style.opacity="0.75"},200)},t||1500))},hterm.Terminal.prototype.paste=function(){hterm.pasteFromClipboard(this.document_)},hterm.Terminal.prototype.copyStringToClipboard=function(e){this.prefs_.get("enable-clipboard-notice")&&setTimeout(this.showOverlay.bind(this,hterm.notifyCopyMessage,500),200);var t=this.document_.createElement("pre");t.textContent=e,t.style.cssText="-webkit-user-select: text;-moz-user-select: text;position: absolute;top: -99px",this.document_.body.appendChild(t);var r=this.document_.getSelection(),o=r.anchorNode,i=r.anchorOffset,s=r.focusNode,n=r.focusOffset;r.selectAllChildren(t),hterm.copySelectionToClipboard(this.document_),r.extend&&(r.collapse(o,i),r.extend(s,n)),t.parentNode.removeChild(t)},hterm.Terminal.prototype.getSelectionText=function(){var e=this.scrollPort_.selection;if(e.sync(),e.isCollapsed)return null;var t=e.startOffset,r=e.startNode;if("X-ROW"!=r.nodeName)for("#text"==r.nodeName&&"SPAN"==r.parentNode.nodeName&&(r=r.parentNode);r.previousSibling;)r=r.previousSibling,t+=hterm.TextAttributes.nodeWidth(r);var o=hterm.TextAttributes.nodeWidth(e.endNode)-e.endOffset;if("X-ROW"!=(r=e.endNode).nodeName)for("#text"==r.nodeName&&"SPAN"==r.parentNode.nodeName&&(r=r.parentNode);r.nextSibling;)r=r.nextSibling,o+=hterm.TextAttributes.nodeWidth(r);var i=this.getRowsText(e.startRow.rowIndex,e.endRow.rowIndex+1);return lib.wc.substring(i,t,lib.wc.strWidth(i)-o)},hterm.Terminal.prototype.copySelectionToClipboard=function(){var e=this.getSelectionText();null!=e&&this.copyStringToClipboard(e)},hterm.Terminal.prototype.overlaySize=function(){this.showOverlay(this.screenSize.width+"x"+this.screenSize.height)},hterm.Terminal.prototype.onVTKeystroke=function(e){this.scrollOnKeystroke_&&this.scrollPort_.scrollRowToBottom(this.getRowCount()),this.io.onVTKeystroke(this.keyboard.encode(e))},hterm.Terminal.prototype.onMouse_=function(e){e.processedByTerminalHandler_||(e.processedByTerminalHandler_=!0,e.terminalRow=parseInt((e.clientY-this.scrollPort_.visibleRowTopMargin)/this.scrollPort_.characterSize.height)+1,e.terminalColumn=parseInt(e.clientX/this.scrollPort_.characterSize.width)+1,"mousedown"==e.type&&e.terminalColumn>this.screenSize.width||(this.options_.cursorVisible&&this.vt.mouseReport==this.vt.MOUSE_REPORT_DISABLED&&(e.terminalRow-1==this.screen_.cursorPosition.row&&e.terminalColumn-1==this.screen_.cursorPosition.column?this.cursorNode_.style.display="none":"none"==this.cursorNode_.style.display&&(this.cursorNode_.style.display="")),"mousedown"==e.type&&(e.altKey||this.vt.mouseReport==this.vt.MOUSE_REPORT_DISABLED?(this.reportMouseEvents_=!1,this.setSelectionEnabled(!0)):(this.reportMouseEvents_=!0,this.document_.getSelection().collapseToEnd(),this.setSelectionEnabled(!1),e.preventDefault())),this.reportMouseEvents_?(this.scrollBlockerNode_.engaged||("mousedown"==e.type?(this.scrollBlockerNode_.engaged=!0,this.scrollBlockerNode_.style.top=e.clientY-5+"px",this.scrollBlockerNode_.style.left=e.clientX-5+"px"):"mousemove"==e.type&&(this.document_.getSelection().collapseToEnd(),e.preventDefault())),this.onMouse(e)):("dblclick"==e.type&&(this.screen_.expandSelection(this.document_.getSelection()),hterm.copySelectionToClipboard(this.document_)),"mousedown"==e.type&&e.which==this.mousePasteButton&&this.paste(),"mouseup"==e.type&&1==e.which&&this.copyOnSelect&&!this.document_.getSelection().isCollapsed&&hterm.copySelectionToClipboard(this.document_),"mousemove"!=e.type&&"mouseup"!=e.type||!this.scrollBlockerNode_.engaged||(this.scrollBlockerNode_.engaged=!1,this.scrollBlockerNode_.style.top="-99px")),"mouseup"==e.type&&this.document_.getSelection().isCollapsed&&(this.reportMouseEvents_=this.vt.mouseReport!=this.vt.MOUSE_REPORT_DISABLED)))},hterm.Terminal.prototype.onMouse=function(e){},hterm.Terminal.prototype.onFocusChange_=function(e){this.cursorNode_.setAttribute("focus",e),this.restyleCursor_(),!0===e&&this.closeBellNotifications_()},hterm.Terminal.prototype.onScroll_=function(){this.scheduleSyncCursorPosition_()},hterm.Terminal.prototype.onPaste_=function(e){var t=e.text.replace(/\n/gm,"\r");t=this.keyboard.encode(t),this.options_.bracketedPaste&&(t="[200~"+t+"[201~"),this.io.sendString(t)},hterm.Terminal.prototype.onCopy_=function(e){this.useDefaultWindowCopy||(e.preventDefault(),setTimeout(this.copySelectionToClipboard.bind(this),0))},hterm.Terminal.prototype.onResize_=function(){var e=Math.floor(this.scrollPort_.getScreenWidth()/this.scrollPort_.characterSize.width),t=lib.f.smartFloorDivide(this.scrollPort_.getScreenHeight(),this.scrollPort_.characterSize.height);if(!(e<=0||t<=0)){var r=e!=this.screenSize.width||t!=this.screenSize.height;this.realizeSize_(e,t),this.showZoomWarning_(1!=this.scrollPort_.characterSize.zoomFactor),r&&this.overlaySize(),this.restyleCursor_(),this.scheduleSyncCursorPosition_()}},hterm.Terminal.prototype.onCursorBlink_=function(){this.options_.cursorBlink?"false"==this.cursorNode_.getAttribute("focus")||"0"==this.cursorNode_.style.opacity?(this.cursorNode_.style.opacity="1",this.timeouts_.cursorBlink=setTimeout(this.myOnCursorBlink_,this.cursorBlinkCycle_[0])):(this.cursorNode_.style.opacity="0",this.timeouts_.cursorBlink=setTimeout(this.myOnCursorBlink_,this.cursorBlinkCycle_[1])):delete this.timeouts_.cursorBlink},hterm.Terminal.prototype.setScrollbarVisible=function(e){this.scrollPort_.setScrollbarVisible(e)},hterm.Terminal.prototype.setScrollWheelMoveMultipler=function(e){this.scrollPort_.setScrollWheelMoveMultipler(e)},hterm.Terminal.prototype.closeBellNotifications_=function(){this.bellNotificationList_.forEach(function(e){e.close()}),this.bellNotificationList_.length=0},lib.rtdep("lib.encodeUTF8"),hterm.Terminal.IO=function(e){this.terminal_=e,this.previousIO_=null},hterm.Terminal.IO.prototype.showOverlay=function(e,t){this.terminal_.showOverlay(e,t)},hterm.Terminal.IO.prototype.createFrame=function(e,t){return new hterm.Frame(this.terminal_,e,t)},hterm.Terminal.IO.prototype.setTerminalProfile=function(e){this.terminal_.setProfile(e)},hterm.Terminal.IO.prototype.push=function(){var e=new hterm.Terminal.IO(this.terminal_);return e.keyboardCaptured_=this.keyboardCaptured_,e.columnCount=this.columnCount,e.rowCount=this.rowCount,e.previousIO_=this.terminal_.io,this.terminal_.io=e,e},hterm.Terminal.IO.prototype.pop=function(){this.terminal_.io=this.previousIO_},hterm.Terminal.IO.prototype.sendString=function(e){console.log("Unhandled sendString: "+e)},hterm.Terminal.IO.prototype.onVTKeystroke=function(e){console.log("Unobserverd VT keystroke: "+JSON.stringify(e))},hterm.Terminal.IO.prototype.onTerminalResize_=function(e,t){for(var r=this;r;)r.columnCount=e,r.rowCount=t,r=r.previousIO_;this.onTerminalResize(e,t)},hterm.Terminal.IO.prototype.onTerminalResize=function(e,t){},hterm.Terminal.IO.prototype.writeUTF8=function(e){if(this.terminal_.io!=this)throw"Attempt to print from inactive IO object.";this.terminal_.interpret(e)},hterm.Terminal.IO.prototype.writelnUTF8=function(e){if(this.terminal_.io!=this)throw"Attempt to print from inactive IO object.";this.terminal_.interpret(e+"\r\n")},hterm.Terminal.IO.prototype.print=hterm.Terminal.IO.prototype.writeUTF16=function(e){this.writeUTF8(lib.encodeUTF8(e))},hterm.Terminal.IO.prototype.println=hterm.Terminal.IO.prototype.writelnUTF16=function(e){this.writelnUTF8(lib.encodeUTF8(e))},lib.rtdep("lib.colors"),hterm.TextAttributes=function(e){this.document_=e,this.foregroundSource=this.SRC_DEFAULT,this.backgroundSource=this.SRC_DEFAULT,this.foreground=this.DEFAULT_COLOR,this.background=this.DEFAULT_COLOR,this.defaultForeground="rgb(255, 255, 255)",this.defaultBackground="rgb(0, 0, 0)",this.bold=!1,this.faint=!1,this.italic=!1,this.blink=!1,this.underline=!1,this.strikethrough=!1,this.inverse=!1,this.invisible=!1,this.wcNode=!1,this.tileData=null,this.colorPalette=null,this.resetColorPalette()},hterm.TextAttributes.prototype.enableBold=!0,hterm.TextAttributes.prototype.enableBoldAsBright=!0,hterm.TextAttributes.prototype.DEFAULT_COLOR=new String(""),hterm.TextAttributes.prototype.SRC_DEFAULT="default",hterm.TextAttributes.prototype.SRC_RGB="rgb",hterm.TextAttributes.prototype.setDocument=function(e){this.document_=e},hterm.TextAttributes.prototype.clone=function(){var e=new hterm.TextAttributes(null);for(var t in this)e[t]=this[t];return e.colorPalette=this.colorPalette.concat(),e},hterm.TextAttributes.prototype.reset=function(){this.foregroundSource=this.SRC_DEFAULT,this.backgroundSource=this.SRC_DEFAULT,this.foreground=this.DEFAULT_COLOR,this.background=this.DEFAULT_COLOR,this.bold=!1,this.faint=!1,this.italic=!1,this.blink=!1,this.underline=!1,this.strikethrough=!1,this.inverse=!1,this.invisible=!1,this.wcNode=!1},hterm.TextAttributes.prototype.resetColorPalette=function(){this.colorPalette=lib.colors.colorPalette.concat(),this.syncColors()},hterm.TextAttributes.prototype.isDefault=function(){return!(this.foregroundSource!=this.SRC_DEFAULT||this.backgroundSource!=this.SRC_DEFAULT||this.bold||this.faint||this.italic||this.blink||this.underline||this.strikethrough||this.inverse||this.invisible||this.wcNode||null!=this.tileData)},hterm.TextAttributes.prototype.createContainer=function(e){var t=this.document_.createElement("span"),r=t.style;this.foreground!=this.DEFAULT_COLOR?r.color=this.foreground:r.color=this.defaultForeground,this.background!=this.DEFAULT_COLOR&&(r.backgroundColor=this.background),this.enableBold&&this.bold&&(r.fontWeight="bold"),this.faint&&(t.faint=!0),this.italic&&(r.fontStyle="italic"),this.blink&&(r.fontStyle="italic");var o="";return this.underline&&(o+=" underline",t.underline=!0),this.strikethrough&&(o+=" line-through",t.strikethrough=!0),o&&(r.textDecoration=o),this.wcNode&&(t.className="wc-node",t.wcNode=!0),null!=this.tileData&&(t.className+=" tile tile_"+this.tileData,t.tileNode=!0),e&&(t.textContent=e),t},hterm.TextAttributes.prototype.matchesContainer=function(e){return!1},hterm.TextAttributes.prototype.setDefaults=function(e,t){this.defaultForeground=e,this.defaultBackground=t,this.syncColors()},hterm.TextAttributes.prototype.syncColors=function(){var e=this.foregroundSource,t=this.backgroundSource,r=this.DEFAULT_COLOR,o=this.DEFAULT_COLOR;if(this.inverse&&(e=this.backgroundSource,t=this.foregroundSource,r=this.defaultBackground,o=this.defaultForeground),this.enableBoldAsBright&&this.bold&&e!=this.SRC_DEFAULT&&e!=this.SRC_RGB&&(e=function(e){return e<8?e+8:e}(e)),this.invisible&&(e=t,r=this.defaultBackground),e!=this.SRC_RGB&&(this.foreground=e==this.SRC_DEFAULT?r:this.colorPalette[e]),this.faint&&!this.invisible){var i=this.foreground==this.DEFAULT_COLOR?this.defaultForeground:this.foreground;this.foreground=lib.colors.mix(i,"rgb(0, 0, 0)",.3333)}t!=this.SRC_RGB&&(this.background=t==this.SRC_DEFAULT?o:this.colorPalette[t])},hterm.TextAttributes.containersMatch=function(e,t){if("string"==typeof e)return hterm.TextAttributes.containerIsDefault(t);if(e.nodeType!=t.nodeType)return!1;if(3==e.nodeType)return!0;var r=e.style,o=t.style;return r.color==o.color&&r.backgroundColor==o.backgroundColor&&r.fontWeight==o.fontWeight&&r.fontStyle==o.fontStyle&&r.textDecoration==o.textDecoration},hterm.TextAttributes.containerIsDefault=function(e){return"string"==typeof e||3==e.nodeType},hterm.TextAttributes.nodeWidth=function(e){return e.wcNode?lib.wc.strWidth(e.textContent):e.textContent.length},hterm.TextAttributes.nodeSubstr=function(e,t,r){return e.wcNode?lib.wc.substr(e.textContent,t,r):e.textContent.substr(t,r)},hterm.TextAttributes.nodeSubstring=function(e,t,r){return e.wcNode?lib.wc.substring(e.textContent,t,r):e.textContent.substring(t,r)},hterm.TextAttributes.splitWidecharString=function(e){for(var t=[],r=0,o=0,i=0;i0?0:1),s|=r,t=""+String.fromCharCode(s)+o+i,e.preventDefault();break;case"mousedown":var s=Math.min(e.which-1,2)+32;s|=r,t=""+String.fromCharCode(s)+o+i;break;case"mouseup":t="#"+o+i;break;case"mousemove":this.mouseReport==this.MOUSE_REPORT_DRAG&&e.which&&(s=32+Math.min(e.which-1,2),s+=32,s|=r,t=""+String.fromCharCode(s)+o+i);break;case"click":case"dblclick":break;default:console.error("Unknown mouse event: "+e.type,e)}t&&this.terminal.io.sendString(t)}},hterm.VT.prototype.interpret=function(e){for(this.parseState_.resetBuf(this.decode(e));!this.parseState_.isComplete();){var t=this.parseState_.func,r=this.parseState_.pos,e=this.parseState_.buf;if(this.parseState_.func.call(this,this.parseState_),this.parseState_.func==t&&this.parseState_.pos==r&&this.parseState_.buf==e)throw"Parser did not alter the state!"}},hterm.VT.prototype.decode=function(e){return"utf-8"==this.characterEncoding?this.decodeUTF8(e):e},hterm.VT.prototype.encodeUTF8=function(e){return lib.encodeUTF8(e)},hterm.VT.prototype.decodeUTF8=function(e){return this.utf8Decoder_.decode(e)},hterm.VT.prototype.parseUnknown_=function(e){function t(e){r[r.GL].GL&&(e=r[r.GL].GL(e)),r[r.GR].GR&&(e=r[r.GR].GR(e)),r.terminal.print(e)}var r=this,o=e.peekRemainingBuf(),i=o.search(this.cc1Pattern_);return 0==i?(this.dispatch("CC1",o.substr(0,1),e),void e.advance(1)):-1==i?(t(o),void e.reset()):(t(o.substr(0,i)),this.dispatch("CC1",o.substr(i,1),e),void e.advance(i+1))},hterm.VT.prototype.parseCSI_=function(e){var t=e.peekChar(),r=e.args;t>="@"&&t<="~"?(this.dispatch("CSI",this.leadingModifier_+this.trailingModifier_+t,e),e.resetParseFunction()):";"==t?this.trailingModifier_?e.resetParseFunction():(r.length||r.push(""),r.push("")):t>="0"&&t<="9"?this.trailingModifier_?e.resetParseFunction():r.length?r[r.length-1]+=t:r[0]=t:t>=" "&&t<="?"&&":"!=t?r.length?this.trailingModifier_+=t:this.leadingModifier_+=t:this.cc1Pattern_.test(t)?this.dispatch("CC1",t,e):e.resetParseFunction(),e.advance(1)},hterm.VT.prototype.parseUntilStringTerminator_=function(e){var t=e.peekRemainingBuf(),r=t.search(/(\x1b\\|\x07)/),o=e.args;if(o.length||(o[0]="",o[1]=new Date),-1==r){o[0]+=t;var i;return o[0].length>this.maxStringSequence&&(i="too long: "+o[0].length),-1!=o[0].indexOf("")&&(i="embedded escape: "+o[0].indexOf("")),new Date-o[1]>this.oscTimeLimit_&&(i="timeout expired: "+new Date-o[1]),i?(console.log("parseUntilStringTerminator_: aborting: "+i,o[0]),e.reset(o[0]),!1):(e.advance(t.length),!0)}return o[0].length+r>this.maxStringSequence?(e.reset(o[0]+t),!1):(o[0]+=t.substr(0,r),e.resetParseFunction(),e.advance(r+(""==t.substr(r,1)?2:1)),!0)},hterm.VT.prototype.dispatch=function(e,t,r){var o=hterm.VT[e][t];o?o!=hterm.VT.ignore?"CC1"==e&&t>""&&!this.enable8BitControl?console.warn("Ignoring 8-bit control code: 0x"+t.charCodeAt(0).toString(16)):o.apply(this,[r,t]):this.warnUnimplemented&&console.warn("Ignored "+e+" code: "+JSON.stringify(t)):this.warnUnimplemented&&console.warn("Unknown "+e+" code: "+JSON.stringify(t))},hterm.VT.prototype.setANSIMode=function(e,t){"4"==e?this.terminal.setInsertMode(t):"20"==e?this.terminal.setAutoCarriageReturn(t):this.warnUnimplemented&&console.warn("Unimplemented ANSI Mode: "+e)},hterm.VT.prototype.setDECMode=function(e,t){switch(e){case"1":this.terminal.keyboard.applicationCursor=t;break;case"3":this.allowColumnWidthChanges_&&(this.terminal.setWidth(t?132:80),this.terminal.clearHome(),this.terminal.setVTScrollRegion(null,null));break;case"5":this.terminal.setReverseVideo(t);break;case"6":this.terminal.setOriginMode(t);break;case"7":this.terminal.setWraparound(t);break;case"12":this.enableDec12&&this.terminal.setCursorBlink(t);break;case"25":this.terminal.setCursorVisible(t);break;case"40":this.terminal.allowColumnWidthChanges_=t;break;case"45":this.terminal.setReverseWraparound(t);break;case"67":this.terminal.keyboard.backspaceSendsBackspace=t;break;case"1000":this.mouseReport=t?this.MOUSE_REPORT_CLICK:this.MOUSE_REPORT_DISABLED;break;case"1002":this.mouseReport=t?this.MOUSE_REPORT_DRAG:this.MOUSE_REPORT_DISABLED;break;case"1010":this.terminal.scrollOnOutput=t;break;case"1011":this.terminal.scrollOnKeystroke=t;break;case"1036":this.terminal.keyboard.metaSendsEscape=t;break;case"1039":t?this.terminal.keyboard.previousAltSendsWhat_||(this.terminal.keyboard.previousAltSendsWhat_=this.terminal.keyboard.altSendsWhat,this.terminal.keyboard.altSendsWhat="escape"):this.terminal.keyboard.previousAltSendsWhat_&&(this.terminal.keyboard.altSendsWhat=this.terminal.keyboard.previousAltSendsWhat_,this.terminal.keyboard.previousAltSendsWhat_=null);break;case"47":case"1047":this.terminal.setAlternateMode(t);break;case"1048":this.savedState_.save();case"1049":t?(this.savedState_.save(),this.terminal.setAlternateMode(t),this.terminal.clear()):(this.terminal.setAlternateMode(t),this.savedState_.restore());break;case"2004":this.terminal.setBracketedPaste(t);break;default:this.warnUnimplemented&&console.warn("Unimplemented DEC Private Mode: "+e)}},hterm.VT.ignore=function(){},hterm.VT.CC1={},hterm.VT.ESC={},hterm.VT.CSI={},hterm.VT.OSC={},hterm.VT.VT52={},hterm.VT.CC1["\0"]=function(){},hterm.VT.CC1[""]=hterm.VT.ignore,hterm.VT.CC1[""]=function(){this.terminal.ringBell()},hterm.VT.CC1["\b"]=function(){this.terminal.cursorLeft(1)},hterm.VT.CC1["\t"]=function(){this.terminal.forwardTabStop()},hterm.VT.CC1["\n"]=function(){this.terminal.formFeed()},hterm.VT.CC1["\v"]=hterm.VT.CC1["\n"],hterm.VT.CC1["\f"]=function(){this.terminal.formFeed()},hterm.VT.CC1["\r"]=function(){this.terminal.setCursorColumn(0)},hterm.VT.CC1[""]=function(){this.GL="G1"},hterm.VT.CC1[""]=function(){this.GL="G0"},hterm.VT.CC1[""]=hterm.VT.ignore,hterm.VT.CC1[""]=hterm.VT.ignore,hterm.VT.CC1[""]=function(e){e.resetParseFunction(),this.terminal.print("?")},hterm.VT.CC1[""]=hterm.VT.CC1[""],hterm.VT.CC1[""]=function(e){function t(e){var r=e.consumeChar();""!=r&&(this.dispatch("ESC",r,e),e.func==t&&e.resetParseFunction())}e.func=t},hterm.VT.CC1[""]=hterm.VT.ignore,hterm.VT.CC1["„"]=hterm.VT.ESC.D=function(){this.terminal.lineFeed()},hterm.VT.CC1["…"]=hterm.VT.ESC.E=function(){this.terminal.setCursorColumn(0),this.terminal.cursorDown(1)},hterm.VT.CC1["ˆ"]=hterm.VT.ESC.H=function(){this.terminal.setTabStop(this.terminal.getCursorColumn())},hterm.VT.CC1[""]=hterm.VT.ESC.M=function(){this.terminal.reverseLineFeed()},hterm.VT.CC1["Ž"]=hterm.VT.ESC.N=hterm.VT.ignore,hterm.VT.CC1[""]=hterm.VT.ESC.O=hterm.VT.ignore,hterm.VT.CC1[""]=hterm.VT.ESC.P=function(e){e.resetArguments(),e.func=this.parseUntilStringTerminator_},hterm.VT.CC1["–"]=hterm.VT.ESC.V=hterm.VT.ignore,hterm.VT.CC1["—"]=hterm.VT.ESC.W=hterm.VT.ignore,hterm.VT.CC1["˜"]=hterm.VT.ESC.X=hterm.VT.ignore,hterm.VT.CC1["š"]=hterm.VT.ESC.Z=function(){this.terminal.io.sendString("[?1;2c")},hterm.VT.CC1["›"]=hterm.VT.ESC["["]=function(e){e.resetArguments(),this.leadingModifier_="",this.trailingModifier_="",e.func=this.parseCSI_},hterm.VT.CC1["œ"]=hterm.VT.ESC["\\"]=hterm.VT.ignore,hterm.VT.CC1[""]=hterm.VT.ESC["]"]=function(e){function t(e){if(this.parseUntilStringTerminator_(e)&&e.func!=t){var r=e.args[0].match(/^(\d+);(.*)$/);r?(e.args[0]=r[2],this.dispatch("OSC",r[1],e)):console.warn("Invalid OSC: "+JSON.stringify(e.args[0]))}}e.resetArguments(),e.func=t},hterm.VT.CC1["ž"]=hterm.VT.ESC["^"]=function(e){e.resetArguments(),e.func=this.parseUntilStringTerminator_},hterm.VT.CC1["Ÿ"]=hterm.VT.ESC._=function(e){e.resetArguments(),e.func=this.parseUntilStringTerminator_},hterm.VT.ESC[" "]=function(e){e.func=function(e){var t=e.consumeChar();this.warnUnimplemented&&console.warn("Unimplemented sequence: ESC 0x20 "+t),e.resetParseFunction()}},hterm.VT.ESC["#"]=function(e){e.func=function(e){"8"==e.consumeChar()&&this.terminal.fill("E"),e.resetParseFunction()}},hterm.VT.ESC["%"]=function(e){e.func=function(e){var t=e.consumeChar();"@"!=t&&"G"!=t&&this.warnUnimplemented&&console.warn("Unknown ESC % argument: "+JSON.stringify(t)),e.resetParseFunction()}},hterm.VT.ESC["("]=hterm.VT.ESC[")"]=hterm.VT.ESC["*"]=hterm.VT.ESC["+"]=hterm.VT.ESC["-"]=hterm.VT.ESC["."]=hterm.VT.ESC["/"]=function(e,t){e.func=function(e){var r=e.consumeChar();if(""==r)return e.resetParseFunction(),void e.func();r in hterm.VT.CharacterMap.maps?"("==t?this.G0=hterm.VT.CharacterMap.maps[r]:")"==t||"-"==t?this.G1=hterm.VT.CharacterMap.maps[r]:"*"==t||"."==t?this.G2=hterm.VT.CharacterMap.maps[r]:"+"!=t&&"/"!=t||(this.G3=hterm.VT.CharacterMap.maps[r]):this.warnUnimplemented&&console.log('Invalid character set for "'+t+'": '+r),e.resetParseFunction()}},hterm.VT.ESC[6]=hterm.VT.ignore,hterm.VT.ESC[7]=function(){this.savedState_.save()},hterm.VT.ESC[8]=function(){this.savedState_.restore()},hterm.VT.ESC[9]=hterm.VT.ignore,hterm.VT.ESC["="]=function(){this.terminal.keyboard.applicationKeypad=!0},hterm.VT.ESC[">"]=function(){this.terminal.keyboard.applicationKeypad=!1},hterm.VT.ESC.F=hterm.VT.ignore,hterm.VT.ESC.c=function(){this.reset(),this.terminal.reset()},hterm.VT.ESC.l=hterm.VT.ESC.m=hterm.VT.ignore,hterm.VT.ESC.n=function(){this.GL="G2"},hterm.VT.ESC.o=function(){this.GL="G3"},hterm.VT.ESC["|"]=function(){this.GR="G3"},hterm.VT.ESC["}"]=function(){this.GR="G2"},hterm.VT.ESC["~"]=function(){this.GR="G1"},hterm.VT.OSC[0]=function(e){this.terminal.setWindowTitle(e.args[0])},hterm.VT.OSC[2]=hterm.VT.OSC[0],hterm.VT.OSC[4]=function(e){for(var t=e.args[0].split(";"),r=parseInt(t.length/2),o=this.terminal.getTextAttributes().colorPalette,i=[],s=0;s=o.length||("?"!=a?(a=lib.colors.x11ToCSS(a))&&(o[n]=a):(a=lib.colors.rgbToX11(o[n]))&&i.push(n+";"+a))}i.length&&this.terminal.io.sendString("]4;"+i.join(";")+"")},hterm.VT.OSC[50]=function(e){var t=e.args[0].match(/CursorShape=(.)/i);if(t)switch(t[1]){case"1":this.terminal.setCursorShape(hterm.Terminal.cursorShape.BEAM);break;case"2":this.terminal.setCursorShape(hterm.Terminal.cursorShape.UNDERLINE);break;default:this.terminal.setCursorShape(hterm.Terminal.cursorShape.BLOCK)}else console.warn("Could not parse OSC 50 args: "+e.args[0])},hterm.VT.OSC[52]=function(e){var t=e.args[0].match(/^[cps01234567]*;(.*)/);if(t){var r=window.atob(t[1]);r&&this.terminal.copyStringToClipboard(this.decode(r))}},hterm.VT.CSI["@"]=function(e){this.terminal.insertSpace(e.iarg(0,1))},hterm.VT.CSI.A=function(e){this.terminal.cursorUp(e.iarg(0,1))},hterm.VT.CSI.B=function(e){this.terminal.cursorDown(e.iarg(0,1))},hterm.VT.CSI.C=function(e){this.terminal.cursorRight(e.iarg(0,1))},hterm.VT.CSI.D=function(e){this.terminal.cursorLeft(e.iarg(0,1))},hterm.VT.CSI.E=function(e){this.terminal.cursorDown(e.iarg(0,1)),this.terminal.setCursorColumn(0)},hterm.VT.CSI.F=function(e){this.terminal.cursorUp(e.iarg(0,1)),this.terminal.setCursorColumn(0)},hterm.VT.CSI.G=function(e){this.terminal.setCursorColumn(e.iarg(0,1)-1)},hterm.VT.CSI.H=function(e){this.terminal.setCursorPosition(e.iarg(0,1)-1,e.iarg(1,1)-1)},hterm.VT.CSI.I=function(e){var t=e.iarg(0,1);t=lib.f.clamp(t,1,this.terminal.screenSize.width);for(var r=0;rT"]=hterm.VT.ignore,hterm.VT.CSI.X=function(e){this.terminal.eraseToRight(e.iarg(0,1))},hterm.VT.CSI.Z=function(e){var t=e.iarg(0,1);t=lib.f.clamp(t,1,this.terminal.screenSize.width);for(var r=0;rc"]=function(e){this.terminal.io.sendString("[>0;256;0c")},hterm.VT.CSI.d=function(e){this.terminal.setAbsoluteCursorRow(e.iarg(0,1)-1)},hterm.VT.CSI.f=hterm.VT.CSI.H,hterm.VT.CSI.g=function(e){e.args[0]&&"0"!=e.args[0]?"3"==e.args[0]&&this.terminal.clearAllTabStops():this.terminal.clearTabStopAtCursor(!1)},hterm.VT.CSI.h=function(e){for(var t=0;t=o.colorPalette.length)continue;o.foregroundSource=a}else if(39==s)o.foregroundSource=o.SRC_DEFAULT;else if(s<48)o.backgroundSource=s-40;else if(48==s){var n=r(i);if(null!=n)o.backgroundSource=o.SRC_RGB,o.background=n,i+=5;else{var a=t(i);if(null==a)break;if(i+=2,a>=o.colorPalette.length)continue;o.backgroundSource=a}}else o.backgroundSource=o.SRC_DEFAULT;else s>=90&&s<=97?o.foregroundSource=s-90+8:s>=100&&s<=107&&(o.backgroundSource=s-100+8)}o.setDefaults(this.terminal.getForegroundColor(),this.terminal.getBackgroundColor())}else o.reset()},hterm.VT.CSI[">m"]=hterm.VT.ignore,hterm.VT.CSI.n=function(e){if("5"==e.args[0])this.terminal.io.sendString("0n");else if("6"==e.args[0]){var t=this.terminal.getCursorRow()+1,r=this.terminal.getCursorColumn()+1;this.terminal.io.sendString("["+t+";"+r+"R")}},hterm.VT.CSI[">n"]=hterm.VT.ignore,hterm.VT.CSI["?n"]=function(e){if("6"==e.args[0]){var t=this.terminal.getCursorRow()+1,r=this.terminal.getCursorColumn()+1;this.terminal.io.sendString("["+t+";"+r+"R")}else"15"==e.args[0]?this.terminal.io.sendString("[?11n"):"25"==e.args[0]?this.terminal.io.sendString("[?21n"):"26"==e.args[0]?this.terminal.io.sendString("[?12;1;0;0n"):"53"==e.args[0]&&this.terminal.io.sendString("[?50n")},hterm.VT.CSI[">p"]=hterm.VT.ignore,hterm.VT.CSI["!p"]=function(){this.reset(),this.terminal.softReset()},hterm.VT.CSI.$p=hterm.VT.ignore,hterm.VT.CSI["?$p"]=hterm.VT.ignore,hterm.VT.CSI['"p']=hterm.VT.ignore,hterm.VT.CSI.q=hterm.VT.ignore,hterm.VT.CSI[" q"]=function(e){var t=e.args[0];"0"==t||"1"==t?(this.terminal.setCursorShape(hterm.Terminal.cursorShape.BLOCK),this.terminal.setCursorBlink(!0)):"2"==t?(this.terminal.setCursorShape(hterm.Terminal.cursorShape.BLOCK),this.terminal.setCursorBlink(!1)):"3"==t?(this.terminal.setCursorShape(hterm.Terminal.cursorShape.UNDERLINE),this.terminal.setCursorBlink(!0)):"4"==t?(this.terminal.setCursorShape(hterm.Terminal.cursorShape.UNDERLINE),this.terminal.setCursorBlink(!1)):console.warn("Unknown cursor style: "+t)},hterm.VT.CSI['"q']=hterm.VT.ignore,hterm.VT.CSI.r=function(e){var t=e.args,r=t[0]?parseInt(t[0],10)-1:null,o=t[1]?parseInt(t[1],10)-1:null;this.terminal.setVTScrollRegion(r,o),this.terminal.setCursorPosition(0,0)},hterm.VT.CSI["?r"]=hterm.VT.ignore,hterm.VT.CSI.$r=hterm.VT.ignore,hterm.VT.CSI.s=function(){this.savedState_.save()},hterm.VT.CSI["?s"]=hterm.VT.ignore,hterm.VT.CSI.t=hterm.VT.ignore,hterm.VT.CSI.$t=hterm.VT.ignore,hterm.VT.CSI[">t"]=hterm.VT.ignore,hterm.VT.CSI[" t"]=hterm.VT.ignore,hterm.VT.CSI.u=function(){this.savedState_.restore()},hterm.VT.CSI[" u"]=hterm.VT.ignore,hterm.VT.CSI.$v=hterm.VT.ignore,hterm.VT.CSI["'w"]=hterm.VT.ignore,hterm.VT.CSI.x=hterm.VT.ignore,hterm.VT.CSI["*x"]=hterm.VT.ignore,hterm.VT.CSI.$x=hterm.VT.ignore,hterm.VT.CSI.z=function(e){if(!(e.args.length<1)){var t=e.args[0];if("0"==t){if(e.args.length<2)return;this.terminal.getTextAttributes().tileData=e.args[1]}else"1"==t&&(this.terminal.getTextAttributes().tileData=null)}},hterm.VT.CSI["'z"]=hterm.VT.ignore,hterm.VT.CSI.$z=hterm.VT.ignore,hterm.VT.CSI["'{"]=hterm.VT.ignore,hterm.VT.CSI["'|"]=hterm.VT.ignore,hterm.VT.CSI[" }"]=hterm.VT.ignore,hterm.VT.CSI[" ~"]=hterm.VT.ignore,lib.rtdep("lib.f"),hterm.VT.CharacterMap=function(e,t){this.name=e,this.GL=null,this.GR=null,t&&this.reset(t)},hterm.VT.CharacterMap.prototype.reset=function(e){this.glmap=e;var t=Object.keys(this.glmap).map(function(e){return"\\x"+lib.f.zpad(e.charCodeAt(0).toString(16))});this.glre=new RegExp("["+t.join("")+"]","g"),this.grmap={},t.forEach(function(e){var t=String.fromCharCode(128&e.charCodeAt(0));this.grmap[t]=this.glmap[e]}.bind(this));var r=Object.keys(this.grmap).map(function(e){return"\\x"+lib.f.zpad(e.charCodeAt(0).toString(16),2)});this.grre=new RegExp("["+r.join("")+"]","g"),this.GL=function(e){return e.replace(this.glre,function(e){return this.glmap[e]}.bind(this))}.bind(this),this.GR=function(e){return e.replace(this.grre,function(e){return this.grmap[e]}.bind(this))}.bind(this)},hterm.VT.CharacterMap.maps={},hterm.VT.CharacterMap.maps[0]=new hterm.VT.CharacterMap("graphic",{"`":"◆",a:"▒",b:"␉",c:"␌",d:"␍",e:"␊",f:"°",g:"±",h:"␤",i:"␋",j:"┘",k:"┐",l:"┌",m:"└",n:"┼",o:"⎺",p:"⎻",q:"─",r:"⎼",s:"⎽",t:"├",u:"┤",v:"┴",w:"┬",x:"│",y:"≤",z:"≥","{":"π","|":"≠","}":"£","~":"·"}),hterm.VT.CharacterMap.maps.A=new hterm.VT.CharacterMap("british",{"#":"£"}),hterm.VT.CharacterMap.maps.B=new hterm.VT.CharacterMap("us",null),hterm.VT.CharacterMap.maps[4]=new hterm.VT.CharacterMap("dutch",{"#":"£","@":"¾","[":"IJ","\\":"½","]":"|","{":"¨","|":"f","}":"¼","~":"´"}),hterm.VT.CharacterMap.maps.C=hterm.VT.CharacterMap.maps[5]=new hterm.VT.CharacterMap("finnish",{"[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"}),hterm.VT.CharacterMap.maps.R=new hterm.VT.CharacterMap("french",{"#":"£","@":"à","[":"°","\\":"ç","]":"§","{":"é","|":"ù","}":"è","~":"¨"}),hterm.VT.CharacterMap.maps.Q=new hterm.VT.CharacterMap("french canadian",{"@":"à","[":"â","\\":"ç","]":"ê","^":"î","`":"ô","{":"é","|":"ù","}":"è","~":"û"}),hterm.VT.CharacterMap.maps.K=new hterm.VT.CharacterMap("german",{"@":"§","[":"Ä","\\":"Ö","]":"Ü","{":"ä","|":"ö","}":"ü","~":"ß"}),hterm.VT.CharacterMap.maps.Y=new hterm.VT.CharacterMap("italian",{"#":"£","@":"§","[":"°","\\":"ç","]":"é","`":"ù","{":"à","|":"ò","}":"è","~":"ì"}),hterm.VT.CharacterMap.maps.E=hterm.VT.CharacterMap.maps[6]=new hterm.VT.CharacterMap("norwegian/danish",{"@":"Ä","[":"Æ","\\":"Ø","]":"Å","^":"Ü","`":"ä","{":"æ","|":"ø","}":"å","~":"ü"}),hterm.VT.CharacterMap.maps.Z=new hterm.VT.CharacterMap("spanish",{"#":"£","@":"§","[":"¡","\\":"Ñ","]":"¿","{":"°","|":"ñ","}":"ç"}),hterm.VT.CharacterMap.maps[7]=hterm.VT.CharacterMap.maps.H=new hterm.VT.CharacterMap("swedish",{"@":"É","[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"}),hterm.VT.CharacterMap.maps["="]=new hterm.VT.CharacterMap("swiss",{"#":"ù","@":"à","[":"é","\\":"ç","]":"ê","^":"î",_:"è","`":"ô","{":"ä","|":"ö","}":"ü","~":"û"}),lib.resource.add("hterm/audio/bell","audio/ogg;base64","T2dnUwACAAAAAAAAAADhqW5KAAAAAMFvEjYBHgF2b3JiaXMAAAAAAYC7AAAAAAAAAHcBAAAAAAC4AU9nZ1MAAAAAAAAAAAAA4aluSgEAAAAAesI3EC3//////////////////8kDdm9yYmlzHQAAAFhpcGguT3JnIGxpYlZvcmJpcyBJIDIwMDkwNzA5AAAAAAEFdm9yYmlzKUJDVgEACAAAADFMIMWA0JBVAAAQAABgJCkOk2ZJKaWUoSh5mJRISSmllMUwiZiUicUYY4wxxhhjjDHGGGOMIDRkFQAABACAKAmOo+ZJas45ZxgnjnKgOWlOOKcgB4pR4DkJwvUmY26mtKZrbs4pJQgNWQUAAAIAQEghhRRSSCGFFGKIIYYYYoghhxxyyCGnnHIKKqigggoyyCCDTDLppJNOOumoo4466ii00EILLbTSSkwx1VZjrr0GXXxzzjnnnHPOOeecc84JQkNWAQAgAAAEQgYZZBBCCCGFFFKIKaaYcgoyyIDQkFUAACAAgAAAAABHkRRJsRTLsRzN0SRP8ixREzXRM0VTVE1VVVVVdV1XdmXXdnXXdn1ZmIVbuH1ZuIVb2IVd94VhGIZhGIZhGIZh+H3f933f930gNGQVACABAKAjOZbjKaIiGqLiOaIDhIasAgBkAAAEACAJkiIpkqNJpmZqrmmbtmirtm3LsizLsgyEhqwCAAABAAQAAAAAAKBpmqZpmqZpmqZpmqZpmqZpmqZpmmZZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZQGjIKgBAAgBAx3Ecx3EkRVIkx3IsBwgNWQUAyAAACABAUizFcjRHczTHczzHczxHdETJlEzN9EwPCA1ZBQAAAgAIAAAAAABAMRzFcRzJ0SRPUi3TcjVXcz3Xc03XdV1XVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVYHQkFUAAAQAACGdZpZqgAgzkGEgNGQVAIAAAAAYoQhDDAgNWQUAAAQAAIih5CCa0JrzzTkOmuWgqRSb08GJVJsnuamYm3POOeecbM4Z45xzzinKmcWgmdCac85JDJqloJnQmnPOeRKbB62p0ppzzhnnnA7GGWGcc85p0poHqdlYm3POWdCa5qi5FJtzzomUmye1uVSbc84555xzzjnnnHPOqV6czsE54Zxzzonam2u5CV2cc875ZJzuzQnhnHPOOeecc84555xzzglCQ1YBAEAAAARh2BjGnYIgfY4GYhQhpiGTHnSPDpOgMcgppB6NjkZKqYNQUhknpXSC0JBVAAAgAACEEFJIIYUUUkghhRRSSCGGGGKIIaeccgoqqKSSiirKKLPMMssss8wyy6zDzjrrsMMQQwwxtNJKLDXVVmONteaec645SGultdZaK6WUUkoppSA0ZBUAAAIAQCBkkEEGGYUUUkghhphyyimnoIIKCA1ZBQAAAgAIAAAA8CTPER3RER3RER3RER3RER3P8RxREiVREiXRMi1TMz1VVFVXdm1Zl3Xbt4Vd2HXf133f141fF4ZlWZZlWZZlWZZlWZZlWZZlCUJDVgEAIAAAAEIIIYQUUkghhZRijDHHnINOQgmB0JBVAAAgAIAAAAAAR3EUx5EcyZEkS7IkTdIszfI0T/M00RNFUTRNUxVd0RV10xZlUzZd0zVl01Vl1XZl2bZlW7d9WbZ93/d93/d93/d93/d939d1IDRkFQAgAQCgIzmSIimSIjmO40iSBISGrAIAZAAABACgKI7iOI4jSZIkWZImeZZniZqpmZ7pqaIKhIasAgAAAQAEAAAAAACgaIqnmIqniIrniI4oiZZpiZqquaJsyq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7rukBoyCoAQAIAQEdyJEdyJEVSJEVyJAcIDVkFAMgAAAgAwDEcQ1Ikx7IsTfM0T/M00RM90TM9VXRFFwgNWQUAAAIACAAAAAAAwJAMS7EczdEkUVIt1VI11VItVVQ9VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV1TRN0zSB0JCVAAAZAAAjQQYZhBCKcpBCbj1YCDHmJAWhOQahxBiEpxAzDDkNInSQQSc9uJI5wwzz4FIoFURMg40lN44gDcKmXEnlOAhCQ1YEAFEAAIAxyDHEGHLOScmgRM4xCZ2UyDknpZPSSSktlhgzKSWmEmPjnKPSScmklBhLip2kEmOJrQAAgAAHAIAAC6HQkBUBQBQAAGIMUgophZRSzinmkFLKMeUcUko5p5xTzjkIHYTKMQadgxAppRxTzinHHITMQeWcg9BBKAAAIMABACDAQig0ZEUAECcA4HAkz5M0SxQlSxNFzxRl1xNN15U0zTQ1UVRVyxNV1VRV2xZNVbYlTRNNTfRUVRNFVRVV05ZNVbVtzzRl2VRV3RZV1bZl2xZ+V5Z13zNNWRZV1dZNVbV115Z9X9ZtXZg0zTQ1UVRVTRRV1VRV2zZV17Y1UXRVUVVlWVRVWXZlWfdVV9Z9SxRV1VNN2RVVVbZV2fVtVZZ94XRVXVdl2fdVWRZ+W9eF4fZ94RhV1dZN19V1VZZ9YdZlYbd13yhpmmlqoqiqmiiqqqmqtm2qrq1bouiqoqrKsmeqrqzKsq+rrmzrmiiqrqiqsiyqqiyrsqz7qizrtqiquq3KsrCbrqvrtu8LwyzrunCqrq6rsuz7qizruq3rxnHrujB8pinLpqvquqm6um7runHMtm0co6rqvirLwrDKsu/rui+0dSFRVXXdlF3jV2VZ921fd55b94WybTu/rfvKceu60vg5z28cubZtHLNuG7+t+8bzKz9hOI6lZ5q2baqqrZuqq+uybivDrOtCUVV9XZVl3zddWRdu3zeOW9eNoqrquirLvrDKsjHcxm8cuzAcXds2jlvXnbKtC31jyPcJz2vbxnH7OuP2daOvDAnHjwAAgAEHAIAAE8pAoSErAoA4AQAGIecUUxAqxSB0EFLqIKRUMQYhc05KxRyUUEpqIZTUKsYgVI5JyJyTEkpoKZTSUgehpVBKa6GU1lJrsabUYu0gpBZKaS2U0lpqqcbUWowRYxAy56RkzkkJpbQWSmktc05K56CkDkJKpaQUS0otVsxJyaCj0kFIqaQSU0mptVBKa6WkFktKMbYUW24x1hxKaS2kEltJKcYUU20txpojxiBkzknJnJMSSmktlNJa5ZiUDkJKmYOSSkqtlZJSzJyT0kFIqYOOSkkptpJKTKGU1kpKsYVSWmwx1pxSbDWU0lpJKcaSSmwtxlpbTLV1EFoLpbQWSmmttVZraq3GUEprJaUYS0qxtRZrbjHmGkppraQSW0mpxRZbji3GmlNrNabWam4x5hpbbT3WmnNKrdbUUo0txppjbb3VmnvvIKQWSmktlNJiai3G1mKtoZTWSiqxlZJabDHm2lqMOZTSYkmpxZJSjC3GmltsuaaWamwx5ppSi7Xm2nNsNfbUWqwtxppTS7XWWnOPufVWAADAgAMAQIAJZaDQkJUAQBQAAEGIUs5JaRByzDkqCULMOSepckxCKSlVzEEIJbXOOSkpxdY5CCWlFksqLcVWaykptRZrLQAAoMABACDABk2JxQEKDVkJAEQBACDGIMQYhAYZpRiD0BikFGMQIqUYc05KpRRjzknJGHMOQioZY85BKCmEUEoqKYUQSkklpQIAAAocAAACbNCUWByg0JAVAUAUAABgDGIMMYYgdFQyKhGETEonqYEQWgutddZSa6XFzFpqrbTYQAithdYySyXG1FpmrcSYWisAAOzAAQDswEIoNGQlAJAHAEAYoxRjzjlnEGLMOegcNAgx5hyEDirGnIMOQggVY85BCCGEzDkIIYQQQuYchBBCCKGDEEIIpZTSQQghhFJK6SCEEEIppXQQQgihlFIKAAAqcAAACLBRZHOCkaBCQ1YCAHkAAIAxSjkHoZRGKcYglJJSoxRjEEpJqXIMQikpxVY5B6GUlFrsIJTSWmw1dhBKaS3GWkNKrcVYa64hpdZirDXX1FqMteaaa0otxlprzbkAANwFBwCwAxtFNicYCSo0ZCUAkAcAgCCkFGOMMYYUYoox55xDCCnFmHPOKaYYc84555RijDnnnHOMMeecc845xphzzjnnHHPOOeecc44555xzzjnnnHPOOeecc84555xzzgkAACpwAAAIsFFkc4KRoEJDVgIAqQAAABFWYowxxhgbCDHGGGOMMUYSYowxxhhjbDHGGGOMMcaYYowxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY4wxxhhjjDHGGFtrrbXWWmuttdZaa6211lprrQBAvwoHAP8HG1ZHOCkaCyw0ZCUAEA4AABjDmHOOOQYdhIYp6KSEDkIIoUNKOSglhFBKKSlzTkpKpaSUWkqZc1JSKiWlllLqIKTUWkottdZaByWl1lJqrbXWOgiltNRaa6212EFIKaXWWostxlBKSq212GKMNYZSUmqtxdhirDGk0lJsLcYYY6yhlNZaazHGGGstKbXWYoy1xlprSam11mKLNdZaCwDgbnAAgEiwcYaVpLPC0eBCQ1YCACEBAARCjDnnnHMQQgghUoox56CDEEIIIURKMeYcdBBCCCGEjDHnoIMQQgghhJAx5hx0EEIIIYQQOucchBBCCKGEUkrnHHQQQgghlFBC6SCEEEIIoYRSSikdhBBCKKGEUkopJYQQQgmllFJKKaWEEEIIoYQSSimllBBCCKWUUkoppZQSQgghlFJKKaWUUkIIoZRQSimllFJKCCGEUkoppZRSSgkhhFBKKaWUUkopIYQSSimllFJKKaUAAIADBwCAACPoJKPKImw04cIDUGjISgCADAAAcdhq6ynWyCDFnISWS4SQchBiLhFSijlHsWVIGcUY1ZQxpRRTUmvonGKMUU+dY0oxw6yUVkookYLScqy1dswBAAAgCAAwECEzgUABFBjIAIADhAQpAKCwwNAxXAQE5BIyCgwKx4Rz0mkDABCEyAyRiFgMEhOqgaJiOgBYXGDIB4AMjY20iwvoMsAFXdx1IIQgBCGIxQEUkICDE2544g1PuMEJOkWlDgIAAAAA4AAAHgAAkg0gIiKaOY4Ojw+QEJERkhKTE5QAAAAAALABgA8AgCQFiIiIZo6jw+MDJERkhKTE5AQlAAAAAAAAAAAACAgIAAAAAAAEAAAACAhPZ2dTAAQYOwAAAAAAAOGpbkoCAAAAmc74DRgyNjM69TAzOTk74dnLubewsbagmZiNp4d0KbsExSY/I3XUTwJgkeZdn1HY4zoj33/q9DFtv3Ui1/jmx7lCUtPt18/sYf9MkgAsAGRBd3gMGP4sU+qCPYBy9VrA3YqJosW3W2/ef1iO/u3cg8ZG/57jU+pPmbGEJUgkfnaI39DbPqxddZphbMRmCc5rKlkUMkyx8iIoug5dJv1OYH9a59c+3Gevqc7Z2XFdDjL/qHztRfjWEWxJ/aiGezjohu9HsCZdQBKbiH0VtU/3m85lDG2T/+xkZcYnX+E+aqzv/xTgOoTFG+x7SNqQ4N+oAABSxuVXw77Jd5bmmTmuJakX7509HH0kGYKvARPpwfOSAPySPAc2EkneDwB2HwAAJlQDYK5586N79GJCjx4+p6aDUd27XSvRyXLJkIC5YZ1jLv5lpOhZTz0s+DmnF1diptrnM6UDgIW11Xh8cHTd0/SmbgOAdxcyWwMAAGIrZ3fNSfZbzKiYrK4+tPqtnMVLOeWOG2kVvUY+p2PJ/hkCl5aFRO4TLGYPZcIU3vYM1hohS4jHFlnyW/2T5J7kGsShXWT8N05V+3C/GPqJ1QdWisGPxEzHqXISBPIinWDUt7IeJv/f5OtzBxpTzZZQ+CYEhHXfqG4aABQli72GJhN4oJv+hXcApAJSErAW8G2raAX4NUcABnVt77CzZAB+LsHcVe+Q4h+QB1wh/ZrJTPxSBdI8mgTeAdTsQOoFUEng9BHcVPhxSRRYkKWZJXOFYP6V4AEripJoEjXgA2wJRZHSExmJDm8F0A6gEXsg5a4ZsALItrMB7+fh7UKLvYWSdtsDwFf1mzYzS1F82N1h2Oyt2e76B1QdS0SAsQigLPMOgJS9JRC7hFXA6kUsLFNKD5cA5cTRvgSqPc3Fl99xW3QTi/MHR8DEm6WnvaVQATwRqRKjywQ9BrrhugR2AKTsPQeQckrAOgDOhbTESyrXQ50CkNpXdtWjW7W2/3UjeX3U95gIdalfRAoAmqUEiwp53hCdcCwlg47fcbfzlmQMAgaBkh7c+fcDgF+ifwDXfzegLPcLYJsAAJQArTXjnh/uXGy3v1Hk3pV6/3t5ruW81f6prfbM2Q3WNVy98BwUtbCwhFhAWuPev6Oe/4ZaFQUcgKrVs4defzh1TADA1DEh5b3VlDaECw5b+bPfkKos3tIAue3vJZOih3ga3l6O3PSfIkrLv0PAS86PPdL7g8oc2KteNFKKzKRehOv2gJoFLBPXmaXvPBQILgJon0bbWBszrYZYYwE7jl2j+vTdU7Vpk21LiU0QajPkywAAHqbUC0/YsYOdb4e6BOp7E0cCi04Ao/TgD8ZVAMid6h/A8IeBNkp6/xsAACZELEYIk+yvI6Qz1NN6lIftB/6IMWjWJNOqPTMedAmyaj6Es0QBklJpiSWWHnQ2CoYbGWAmt+0gLQBFKCBnp2QUUQZ/1thtZDBJUpFWY82z34ocorB62oX7qB5y0oPAv/foxH25wVmgIHf2xFOr8leZcBq1Kx3ZvCq9Bga639AxuHuPNL/71YCF4EywJpqHFAX6XF0sjVbuANnvvdLcrufYwOM/iDa6iA468AYAAB6mNBMXcgTD8HSRqJ4vw8CjAlCEPACASlX/APwPOJKl9xQAAAPmnev2eWp33Xgyw3Dvfz6myGk3oyP8YTKsCOvzAgALQi0o1c6Nzs2O2Pg2h4ACIJAgAGP0aNn5x0BDgVfH7u2TtyfDcRIuYAyQhBF/lvSRAttgA6TPbWZA9gaUrZWAUEAA+Dx47Q3/r87HxUUqZmB0BmUuMlojFjHt1gDunnvuX8MImsjSq5WkzSzGS62OEIlOufWWezxWpv6FBgDgJVltfXFYtNAAnqU0xQoD0YLiXo5cF5QV4CnY1tBLAkZCOABAhbk/AM+/AwSCCdlWAAAMcFjS7owb8GVDzveDiZvznbt2tF4bL5odN1YKl88TAEABCZvufq9YCTBtMwVAQUEAwGtNltzSaHvADYC3TxLVjqiRA+OZAMhzcqEgRcAOwoCgvdTxsTHLQEF6+oOb2+PAI8ciPQcXg7pOY+LjxQSv2fjmFuj34gGwz310/bGK6z3xgT887eomWULEaDd04wHetYxdjcgV2SxvSwn0VoZXJRqkRC5ASQ/muVoAUsX7AgAQMBNaVwAAlABRxT/1PmfqLqSRNDbhXb07berpB3b94jpuWEZjBCD2OcdXFpCKEgCDfcFPMw8AAADUwT4lnUm50lmwrpMMhPQIKj6u0E8fr2vGBngMNdIlrZsigjahljud6AFVg+tzXwUnXL3TJLpajaWKA4VAAAAMiFfqJgKAZ08XrtS3dxtQNYcpPvYEG8ClvrQRJgBephwnNWJjtGqmp6VEPSvBe7EBiU3qgJbQAwD4Le8LAMDMhHbNAAAlgK+tFs5O+YyJc9yCnJa3rxLPulGnxwsXV9Fsk2k4PisCAHC8FkwbGE9gJQAAoMnyksj0CdFMZLLgoz8M+FxziwYBgIx+zHiCBAKAlBKNpF1sO9JpVcyEi9ar15YlHgrut5fPJnkdJ6vEwZPyAHQBIEDUrlMcBAAd2KAS0Qq+JwRsE4AJZtMnAD6GnOYwYlOIZvtzUNdjreB7fiMkWI0CmBB6AIAKc38A9osEFlTSGECB+cbeRDC0aRpLHqNPplcK/76Lxn2rpmqyXsYJWRi/FQAAAKBQk9MCAOibrQBQADCDsqpooPutd+05Ce9g6iEdiYXgVmQAI4+4wskEBEiBloNQ6Ki0/KTQ0QjWfjxzi+AeuXKoMjEVfQOZzr0y941qLgM2AExvbZOqcxZ6J6krlrj4y2j9AdgKDx6GnJsVLhbc42uq584+ouSdNBpoCiCVHrz+WzUA/DDtD8ATgA3h0lMCAAzcFv+S+fSSNkeYWlTpb34mf2RfmqqJeMeklhHAfu7VoAEACgAApKRktL+KkQDWMwYCUAAAAHCKsp80xhp91UjqQBw3x45cetqkjQEyu3G9B6N+R650Uq8OVig7wOm6Wun0ea4lKDPoabJs6aLqgbhPzpv4KR4iODilw88ZpY7q1IOMcbASAOAVtmcCnobcrkG4KGS7/ZnskVWRNF9J0RUHKOnByy9WA8Dv6L4AAARMCQUA4GritfVM2lcZfH3Q3T/vZ47J2YHhcmBazjfdyuV25gLAzrc0cwAAAAAYCh6PdwAAAGyWjFW4yScjaWa2mGcofHxWxewKALglWBpLUvwwk+UOh5eNGyUOs1/EF+pZr+ud5OzoGwYdAABg2p52LiSgAY/ZVlOmilEgHn6G3OcwYjzI7vOj1t6xsx4S3lBY96EUQBF6AIBAmPYH4PoGYCoJAADWe+OZJZi7/x76/yH7Lzf9M5XzRKnFPmveMsilQHwVAAAAAKB3LQD8PCIAAADga0QujBLywzeJ4a6Z/ERVBAUlAEDqvoM7BQBAuAguzFqILtmjH3Kd4wfKobnOhA3z85qWoRPm9hwoOHoDAAlCbwDAA56FHAuXflHo3fe2ttG9XUDeA9YmYCBQ0oPr/1QC8IvuCwAAApbUAQCK22MmE3O78VAbHQT9PIPNoT9zNc3l2Oe7TAVLANBufT8MAQAAAGzT4PS8AQAAoELGHb2uaCwwEv1EWhFriUkbAaAZ27/fVZnTZXbWz3BwWpjUaMZKRj7dZ0J//gUeTdpVEwAAZOFsNxKAjQSgA+ABPoY8Jj5y2wje81jsXc/1TOQWTDYZBmAkNDiqVwuA2NJ9AQAAEBKAt9Vrsfs/2N19MO91S9rd8EHTZHnzC5MYmfQEACy/FBcAAADA5c4gi4z8RANs/m6FNXVo9DV46JG1BBDukqlw/Va5G7QbuGVSI+2aZaoLXJrdVj2zlC9Z5QEAEFz/5QzgVZwAAAAA/oXcxyC6WfTu+09Ve/c766J4VTAGUFmA51+VANKi/QPoPwYgYAkA715OH4S0s5KDHvj99MMq8TPFc3roKZnGOoT1bmIhVgc7XAMBAAAAAMAW1VbQw3gapzOpJd+Kd2fc4iSO62fJv9+movui1wUNPAj059N3OVxzk4gV73PmE8FIA2F5mRq37Evc76vLXfF4rD5UJJAw46hW6LZCb5sNLdx+kzMCAAB+hfy95+965ZCLP7B3/VlTHCvDEKtQhTm4KiCgAEAbrfbWTPssAAAAXpee1tVrozYYn41wD1aeYtkKfswN5/SXPO0JDnhO/4laUortv/s412fybe/nONdncoCHnBVliu0CQGBWlPY/5Kwom2L/kruPM6Q7oz4tvDQy+bZ3HzOi+gNHA4DZEgA="),lib.resource.add("hterm/concat/date","text/plain","Fri, 03 Apr 2015 09:02:15 +0000"),lib.resource.add("hterm/changelog/version","text/plain","1.54"),lib.resource.add("hterm/changelog/date","text/plain","2015-03-19"),lib.resource.add("hterm/git/HEAD","text/plain","5db5b0ceefff97ce8b7a97edd3f5ba6857db54cf");var socket=io(location.origin,{path:"/wetty/socket.io"}),term=void 0,buf="",Wetty=function(){function e(t){_classCallCheck(this,e),this.argv_=t,this.io=null,this.pid_=-1}return _createClass(e,[{key:"run",value:function(){this.io=this.argv_.io.push(),this.io.onVTKeystroke=this.sendString_.bind(this),this.io.sendString=this.sendString_.bind(this),this.io.onTerminalResize=this.onTerminalResize.bind(this)}},{key:"sendString_",value:function(e){socket.emit("input",e)}},{key:"onTerminalResize",value:function(e,t){socket.emit("resize",{col:e,row:t})}}]),e}();socket.on("connect",function(){document.getElementById("overlay").style.display="none",window.addEventListener("beforeunload",handler,!1),lib.init(function(){hterm.defaultStorage=new lib.Storage.Local,term=new hterm.Terminal,window.term=term,term.decorate(document.getElementById("terminal")),term.setCursorPosition(0,0),term.setCursorVisible(!0),term.prefs_.set("ctrl-c-copy",!0),term.prefs_.set("ctrl-v-paste",!0),term.prefs_.set("use-default-window-copy",!0),term.prefs_.set("send-encoding","raw"),term.prefs_.set("receive-encoding","raw"),term.prefs_.set("font-size",14),term.scrollPort_.screen_.setAttribute("spellcheck","false"),term.scrollPort_.screen_.setAttribute("autocorrect","false"),term.scrollPort_.screen_.setAttribute("autocomplete","false"),term.scrollPort_.screen_.setAttribute("contenteditable","false"),term.runCommandClass(Wetty,document.location.hash.substr(1)),socket.emit("resize",{col:term.screenSize.width,row:term.screenSize.height}),buf&&""!==buf&&(term.io.writeUTF8(buf),buf="")})}),socket.on("output",function(e){term?term.io.writeUTF8(e):buf+=e}),socket.on("logout",function(){document.getElementById("overlay").style.display="block",window.removeEventListener("beforeunload",handler,!1)}),socket.on("disconnect",function(){document.getElementById("overlay").style.display="block",window.removeEventListener("beforeunload",handler,!1)}); \ No newline at end of file diff --git a/src/.eslintrc.js b/src/.eslintrc.js new file mode 100644 index 0000000..be1ea4f --- /dev/null +++ b/src/.eslintrc.js @@ -0,0 +1,37 @@ +module.exports = { + env: { + es6 : true, + browser: true, + }, + globals: { + hterm: true, + lib : true, + io : true, + }, + extends: ['airbnb'], + rules : { + 'no-underscore-dangle': 0, + 'class-methods-use-this': 0, + 'linebreak-style' : ['error', 'unix'], + 'arrow-parens' : ['error', 'as-needed'], + 'no-param-reassign' : ['error', { props: false }], + 'func-style' : ['error', 'declaration', { allowArrowFunctions: true }], + 'no-use-before-define': ['error', { functions: false }], + 'no-shadow' : [ + 'error', + { + builtinGlobals: true, + hoist : 'functions', + allow : ['resolve', 'reject', 'err'], + }, + ], + 'consistent-return': 0, + 'key-spacing' : [ + 'error', + { + multiLine: { beforeColon: false, afterColon: true }, + align : { beforeColon: false, afterColon: true, on: 'colon', mode: 'strict' }, + }, + ], + }, +}; diff --git a/public/wetty/hterm_all.js b/src/hterm_all.js similarity index 77% rename from public/wetty/hterm_all.js rename to src/hterm_all.js index 80a522d..ddc5d77 100644 --- a/public/wetty/hterm_all.js +++ b/src/hterm_all.js @@ -4,6 +4,8 @@ // files... // // libdot/js/lib.js +// libdot/js/lib_polyfill.js +// libdot/js/lib_array.js // libdot/js/lib_colors.js // libdot/js/lib_f.js // libdot/js/lib_message_manager.js @@ -15,12 +17,16 @@ // libdot/js/lib_storage_memory.js // libdot/js/lib_test_manager.js // libdot/js/lib_utf8.js -// libdot/js/lib_wc.js +// libdot/third_party/wcwidth/lib_wc.js // hterm/js/hterm.js // hterm/js/hterm_frame.js // hterm/js/hterm_keyboard.js +// hterm/js/hterm_keyboard_bindings.js // hterm/js/hterm_keyboard_keymap.js +// hterm/js/hterm_keyboard_keypattern.js // hterm/js/hterm_options.js +// hterm/js/hterm_parser.js +// hterm/js/hterm_parser_identifiers.js // hterm/js/hterm_preference_manager.js // hterm/js/hterm_pubsub.js // hterm/js/hterm_screen.js @@ -48,7 +54,7 @@ var lib = {}; * Map of "dependency" to ["source", ...]. * * Each dependency is a object name, like "lib.fs", "source" is the url that - * depdends on the object. + * depends on the object. */ lib.runtimeDependencies_ = {}; @@ -193,6 +199,167 @@ lib.init = function(onInit, opt_logFunction) { setTimeout(initNext, 0); }; +// SOURCE FILE: libdot/js/lib_polyfill.js +// Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +/** + * @fileoverview Polyfills for ES2016+ features we want to use. + */ + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart +if (!String.prototype.padStart) { + String.prototype.padStart = function(targetLength, padString) { + // If the string is already long enough, nothing to do! + targetLength -= this.length; + if (targetLength <= 0) + return String(this); + + if (padString === undefined) + padString = ' '; + + // In case the pad is multiple chars long. + if (targetLength > padString.length) + padString = padString.repeat((targetLength / padString.length) + 1); + + return padString.slice(0, targetLength) + String(this); + }; +} + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd +if (!String.prototype.padEnd) { + String.prototype.padEnd = function(targetLength, padString) { + // If the string is already long enough, nothing to do! + targetLength -= this.length; + if (targetLength <= 0) + return String(this); + + if (padString === undefined) + padString = ' '; + + // In case the pad is multiple chars long. + if (targetLength > padString.length) + padString = padString.repeat((targetLength / padString.length) + 1); + + return String(this) + padString.slice(0, targetLength); + }; +} + +// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Object/values +// https://github.com/tc39/proposal-object-values-entries/blob/master/polyfill.js +if (!Object.values || !Object.entries) { + const reduce = Function.bind.call(Function.call, Array.prototype.reduce); + const isEnumerable = Function.bind.call(Function.call, + Object.prototype.propertyIsEnumerable); + const concat = Function.bind.call(Function.call, Array.prototype.concat); + + if (!Object.values) { + Object.values = function values(O) { + return reduce(Reflect.ownKeys(O), (v, k) => concat(v, + typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : []), []); + }; + } + + if (!Object.entries) { + Object.entries = function entries(O) { + return reduce(Reflect.ownKeys(O), (e, k) => concat(e, + typeof k === 'string' && isEnumerable(O, k) ? [[k, O[k]]] : []), []); + }; + } +} +// SOURCE FILE: libdot/js/lib_array.js +// Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +/** + * @fileoverview Helper functions for (typed) arrays. + */ + +lib.array = {}; + +/** + * Convert an array of four unsigned bytes into an unsigned 32-bit integer (big + * endian). + * + * @param {!Array.} array + * @returns {!number} + */ +lib.array.arrayBigEndianToUint32 = function(array) { + const maybeSigned = + (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | (array[3] << 0); + // Interpret the result of the bit operations as an unsigned integer. + return maybeSigned >>> 0; +}; + +/** + * Convert an unsigned 32-bit integer into an array of four unsigned bytes (big + * endian). + * + * @param {!number} uint32 + * @returns {!Array.} + */ +lib.array.uint32ToArrayBigEndian = function(uint32) { + return [ + (uint32 >>> 24) & 0xFF, + (uint32 >>> 16) & 0xFF, + (uint32 >>> 8) & 0xFF, + (uint32 >>> 0) & 0xFF, + ]; +}; + +/** + * Concatenate an arbitrary number of typed arrays of the same type into a new + * typed array of this type. + * + * @template TYPED_ARRAY + * @param {...!TYPED_ARRAY} arrays + * @returns {!TYPED_ARRAY} + */ +lib.array.concatTyped = function(...arrays) { + let resultLength = 0; + for (const array of arrays) { + resultLength += array.length; + } + const result = new arrays[0].constructor(resultLength); + let pos = 0; + for (const array of arrays) { + result.set(array, pos); + pos += array.length; + } + return result; +}; + +/** + * Compare two array-like objects entrywise. + * + * @template ARRAY_LIKE + * @param {?ARRAY_LIKE} a + * @param {?ARRAY_LIKE} b + * @returns {!boolean} true if both arrays are null or they agree entrywise; + * false otherwise. + */ +lib.array.compare = function(a, b) { + if (a === null || b === null) { + return a === null && b === null; + } + + if (a.length !== b.length) { + return false; + } + + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return false; + } + } + return true; +}; // SOURCE FILE: libdot/js/lib_colors.js // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -254,7 +421,7 @@ lib.colors.re_ = { '(?:,/s*(/d+(?:/./d+)?)/s*)?/)/s*$' ).replace(/\//g, '\\'), 'i'), - // An X11 "rgb:ddd/ddd/ddd" value. + // An X11 "rgb:dddd/dddd/dddd" value. x11rgb: /^\s*rgb:([a-f0-9]{1,4})\/([a-f0-9]{1,4})\/([a-f0-9]{1,4})\s*$/i, // English color name. @@ -275,10 +442,7 @@ lib.colors.re_ = { lib.colors.rgbToX11 = function(value) { function scale(v) { v = (Math.min(v, 255) * 257).toString(16); - while (v.length < 4) - v = '0' + v; - - return v; + return lib.f.zpad(v, 4); } var ary = value.match(lib.colors.re_.rgbx); @@ -288,6 +452,48 @@ lib.colors.rgbToX11 = function(value) { return 'rgb:' + scale(ary[1]) + '/' + scale(ary[2]) + '/' + scale(ary[3]); }; +/** + * Convert a legacy X11 colover value into an CSS rgb(...) color value. + * + * They take the form: + * 12 bit: #RGB -> #R000G000B000 + * 24 bit: #RRGGBB -> #RR00GG00BB00 + * 36 bit: #RRRGGGBBB -> #RRR0GGG0BBB0 + * 48 bit: #RRRRGGGGBBBB + * These are the most significant bits. + * + * Truncate values back down to 24 bit since that's all CSS supports. + */ +lib.colors.x11HexToCSS = function(v) { + if (!v.startsWith('#')) + return null; + // Strip the leading # off. + v = v.substr(1); + + // Reject unknown sizes. + if ([3, 6, 9, 12].indexOf(v.length) == -1) + return null; + + // Reject non-hex values. + if (v.match(/[^a-f0-9]/i)) + return null; + + // Split the colors out. + var size = v.length / 3; + var r = v.substr(0, size); + var g = v.substr(size, size); + var b = v.substr(size + size, size); + + // Normalize to 16 bits. + function norm16(v) { + v = parseInt(v, 16); + return size == 2 ? v : // 16 bit + size == 1 ? v << 4 : // 8 bit + v >> (4 * (size - 2)); // 24 or 32 bit + } + return lib.colors.arrayToRGBA([r, g, b].map(norm16)); +}; + /** * Convert an X11 color value into an CSS rgb(...) color value. * @@ -304,7 +510,7 @@ lib.colors.x11ToCSS = function(v) { // Pad out values with less than four digits. This padding (probably) // matches xterm. It's difficult to say for sure since xterm seems to // arrive at a padded value and then perform some combination of - // gamma correction, color space tranformation, and quantization. + // gamma correction, color space transformation, and quantization. if (v.length == 1) { // Single digits pad out to four by repeating the character. "f" becomes @@ -332,8 +538,13 @@ lib.colors.x11ToCSS = function(v) { } var ary = v.match(lib.colors.re_.x11rgb); - if (!ary) - return lib.colors.nameToRGB(v); + if (!ary) { + // Handle the legacy format. + if (v.startsWith('#')) + return lib.colors.x11HexToCSS(v); + else + return lib.colors.nameToRGB(v); + } ary.splice(0, 1); return lib.colors.arrayToRGBA(ary.map(scale)); @@ -351,10 +562,16 @@ lib.colors.x11ToCSS = function(v) { * @return {string|Array.} The converted value or values. */ lib.colors.hexToRGB = function(arg) { + var hex16 = lib.colors.re_.hex16; + var hex24 = lib.colors.re_.hex24; + function convert(hex) { - var re = (hex.length == 4) ? - lib.colors.re_.hex16 : lib.colors.re_.hex24; - var ary = hex.match(re) + if (hex.length == 4) { + hex = hex.replace(hex16, function(h, r, g, b) { + return "#" + r + r + g + g + b + b; + }); + } + var ary = hex.match(hex24); if (!ary) return null; @@ -389,6 +606,8 @@ lib.colors.hexToRGB = function(arg) { lib.colors.rgbToHex = function(arg) { function convert(rgb) { var ary = lib.colors.crackRGB(rgb); + if (!ary) + return null; return '#' + lib.f.zpad(((parseInt(ary[0]) << 16) | (parseInt(ary[1]) << 8) | (parseInt(ary[2]) << 0)).toString(16), 6); @@ -411,7 +630,7 @@ lib.colors.rgbToHex = function(arg) { * Returns null if the value could not be normalized. */ lib.colors.normalizeCSS = function(def) { - if (def.substr(0, 1) == '#') + if (def.startsWith('#')) return lib.colors.hexToRGB(def); if (lib.colors.re_.rgbx.test(def)) @@ -459,7 +678,7 @@ lib.colors.mix = function(base, tint, percent) { * will be set to 1. */ lib.colors.crackRGB = function(color) { - if (color.substr(0, 4) == 'rgba') { + if (color.startsWith('rgba')) { var ary = color.match(lib.colors.re_.rgba); if (ary) { ary.shift(); @@ -469,7 +688,7 @@ lib.colors.crackRGB = function(color) { var ary = color.match(lib.colors.re_.rgb); if (ary) { ary.shift(); - ary.push(1); + ary.push('1'); return ary; } } @@ -1245,6 +1464,20 @@ lib.colors.colorNames = { */ lib.f = {}; +/** + * Create a unique enum value. + * + * @suppress {lintChecks} + * @param {string} name A human friendly name for debugging. + * @return {Object} A unique enum that won't compare equal to anything else. + */ +lib.f.createEnum = function(name) { + // We use a String object as nothing else should be using them -- we want to + // use string primitives normally. But debuggers will include our name. + // eslint-disable-next-line no-new-wrappers + return new String(name); +}; + /** * Replace variable references in a string. * @@ -1292,7 +1525,7 @@ lib.f.replaceVars.functions = { "'": ''' }; - return str.replace(/[<>&\"\']/g, function(m) { return map[m] }); + return str.replace(/[<>&\"\']/g, (m) => map[m]); } }; @@ -1303,7 +1536,7 @@ lib.f.replaceVars.functions = { * parameter is a list of locale names. */ lib.f.getAcceptLanguages = function(callback) { - if (window.chrome && chrome.i18n) { + if (lib.f.getAcceptLanguages.chromeSupported()) { chrome.i18n.getAcceptLanguages(callback); } else { setTimeout(function() { @@ -1312,6 +1545,10 @@ lib.f.getAcceptLanguages = function(callback) { } }; +lib.f.getAcceptLanguages.chromeSupported = function() { + return window.chrome && chrome.i18n; +}; + /** * Parse a query string into a hash. * @@ -1327,7 +1564,7 @@ lib.f.getAcceptLanguages = function(callback) { * leading '?', the '?' will be ignored. */ lib.f.parseQuery = function(queryString) { - if (queryString.substr(0, 1) == '?') + if (queryString.startsWith('?')) queryString = queryString.substr(1); var rv = {}; @@ -1342,12 +1579,16 @@ lib.f.parseQuery = function(queryString) { }; lib.f.getURL = function(path) { - if (window.chrome && chrome.runtime && chrome.runtime.getURL) + if (lib.f.getURL.chromeSupported()) return chrome.runtime.getURL(path); return path; }; +lib.f.getURL.chromeSupported = function() { + return window.chrome && chrome.runtime && chrome.runtime.getURL; +}; + /** * Clamp a given integer to a specified range. * @@ -1363,24 +1604,6 @@ lib.f.clamp = function(v, min, max) { return v; }; -/** - * Left pad a string to a given length using a given character. - * - * @param {string} str The string to pad. - * @param {integer} length The desired length. - * @param {string} opt_ch The optional padding character, defaults to ' '. - * @return {string} The padded string. - */ -lib.f.lpad = function(str, length, opt_ch) { - str = String(str); - opt_ch = opt_ch || ' '; - - while (str.length < length) - str = opt_ch + str; - - return str; -}; - /** * Left pad a number to a given length with leading zeros. * @@ -1389,7 +1612,7 @@ lib.f.lpad = function(str, length, opt_ch) { * @return {string} The padded number as a string. */ lib.f.zpad = function(number, length) { - return lib.f.lpad(number, length, '0'); + return String(number).padStart(length, '0'); }; /** @@ -1403,7 +1626,7 @@ lib.f.zpad = function(number, length) { * @param {string} A string of spaces of the requested length. */ lib.f.getWhitespace = function(length) { - if (length == 0) + if (length <= 0) return ''; var f = this.getWhitespace; @@ -1472,7 +1695,7 @@ lib.f.alarm = function(callback, opt_ms) { } return callback.apply(null, arguments); - } + }; }; if (typeof callback == 'string') @@ -1539,6 +1762,17 @@ lib.f.smartFloorDivide = function(numerator, denominator) { return Math.floor(val); } }; + +/** + * Get a random integer in a range (inclusive). + * + * @param {number} min The lowest integer in the range. + * @param {number} max The highest integer in the range. + * @return {number} A random number between min & max. + */ +lib.f.randomInt = function(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +}; // SOURCE FILE: libdot/js/lib_message_manager.js // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -1551,7 +1785,7 @@ lib.f.smartFloorDivide = function(numerator, denominator) { * * Note: chrome.i18n isn't sufficient because... * 1. There's a bug in chrome that makes it unavailable in iframes: - * http://crbug.com/130200 + * https://crbug.com/130200 * 2. The client code may not be packaged in a Chrome extension. * 3. The client code may be part of a library packaged in a third-party * Chrome extension. @@ -1561,8 +1795,7 @@ lib.f.smartFloorDivide = function(numerator, denominator) { * automatically added as the first language if it is not already present. */ lib.MessageManager = function(languages) { - this.languages_ = languages.map( - function(el) { return el.replace(/-/g, '_') }); + this.languages_ = languages.map((el) => el.replace(/-/g, '_')); if (this.languages_.indexOf('en') == -1) this.languages_.unshift('en'); @@ -1574,7 +1807,7 @@ lib.MessageManager = function(languages) { * Add message definitions to the message manager. * * This takes an object of the same format of a Chrome messages.json file. See - * . + * . */ lib.MessageManager.prototype.addMessages = function(defs) { for (var key in defs) { @@ -1688,7 +1921,7 @@ lib.MessageManager.prototype.get = function(msgname, opt_args, opt_default) { message = this.messages[msgname]; } else { - if (window.chrome.i18n) + if (window.chrome && window.chrome.i18n) message = chrome.i18n.getMessage(msgname); if (!message) { @@ -1709,10 +1942,22 @@ lib.MessageManager.prototype.get = function(msgname, opt_args, opt_default) { /** * Process all of the "i18n" html attributes found in a given dom fragment. * - * Each i18n attribute should contain a JSON object. The keys are taken to + * The real work happens in processI18nAttribute. + */ +lib.MessageManager.prototype.processI18nAttributes = function(dom) { + var nodes = dom.querySelectorAll('[i18n]'); + + for (var i = 0; i < nodes.length; i++) + this.processI18nAttribute(nodes[i]); +}; + +/** + * Process the "i18n" attribute in the specified node. + * + * The i18n attribute should contain a JSON object. The keys are taken to * be attribute names, and the values are message names. * - * If the JSON object has a "_" (underscore) key, it's value is used as the + * If the JSON object has a "_" (underscore) key, its value is used as the * textContent of the element. * * Message names can refer to other attributes on the same element with by @@ -1726,40 +1971,44 @@ lib.MessageManager.prototype.get = function(msgname, opt_args, opt_default) { * Notice that the "id" attribute was appended to the target attribute, and * the result converted to UPPER_AND_UNDER style. */ -lib.MessageManager.prototype.processI18nAttributes = function(dom) { +lib.MessageManager.prototype.processI18nAttribute = function(node) { // Convert the "lower-and-dashes" attribute names into // "UPPER_AND_UNDER" style. - function thunk(str) { return str.replace(/-/g, '_').toUpperCase() } + const thunk = (str) => str.replace(/-/g, '_').toUpperCase(); - var nodes = dom.querySelectorAll('[i18n]'); + var i18n = node.getAttribute('i18n'); + if (!i18n) + return; - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - var i18n = node.getAttribute('i18n'); + try { + i18n = JSON.parse(i18n); + } catch (ex) { + console.error('Can\'t parse ' + node.tagName + '#' + node.id + ': ' + i18n); + throw ex; + } - if (!i18n) - continue; + // Load all the messages specified in the i18n attributes. + for (var key in i18n) { + // The node attribute we'll be setting. + var attr = key; - try { - i18n = JSON.parse(i18n); - } catch (ex) { - console.error('Can\'t parse ' + node.tagName + '#' + node.id + ': ' + - i18n); - throw ex; + var msgname = i18n[key]; + // For "=foo", re-use the referenced message name. + if (msgname.startsWith('=')) { + key = msgname.substr(1); + msgname = i18n[key]; } - for (var key in i18n) { - var msgname = i18n[key]; - if (msgname.substr(0, 1) == '$') - msgname = thunk(node.getAttribute(msgname.substr(1)) + '_' + key); + // For "$foo", calculate the message name. + if (msgname.startsWith('$')) + msgname = thunk(node.getAttribute(msgname.substr(1)) + '_' + key); - var msg = this.get(msgname); - if (key == '_') { - node.textContent = msg; - } else { - node.setAttribute(key, msg); - } - } + // Finally load the message. + var msg = this.get(msgname); + if (attr == '_') + node.textContent = msg; + else + node.setAttribute(attr, msg); } }; // SOURCE FILE: libdot/js/lib_preference_manager.js @@ -1783,7 +2032,7 @@ lib.MessageManager.prototype.processI18nAttributes = function(dom) { * @param {lib.Storage.*} storage The storage object to use as a backing * store. * @param {string} opt_prefix The optional prefix to be used for all preference - * names. The '/' character should be used to separate levels of heirarchy, + * names. The '/' character should be used to separate levels of hierarchy, * if you're going to have that kind of thing. If provided, the prefix * should start with a '/'. If not provided, it defaults to '/'. */ @@ -1797,7 +2046,7 @@ lib.PreferenceManager = function(storage, opt_prefix) { this.trace = false; var prefix = opt_prefix || '/'; - if (prefix.substr(prefix.length - 1) != '/') + if (!prefix.endsWith('/')) prefix += '/'; this.prefix = prefix; @@ -1830,12 +2079,12 @@ lib.PreferenceManager = function(storage, opt_prefix) { * * Equality tests against this value MUST use '===' or '!==' to be accurate. */ -lib.PreferenceManager.prototype.DEFAULT_VALUE = new String('DEFAULT'); +lib.PreferenceManager.prototype.DEFAULT_VALUE = lib.f.createEnum('DEFAULT'); /** * An individual preference. * - * These objects are managed by the PreferenceManager, you shoudn't need to + * These objects are managed by the PreferenceManager, you shouldn't need to * handle them directly. */ lib.PreferenceManager.Record = function(name, defaultValue) { @@ -1946,8 +2195,7 @@ lib.PreferenceManager.prototype.readStorage = function(opt_callback) { opt_callback(); } - var keys = Object.keys(this.prefRecords_).map( - function(el) { return this.prefix + el }.bind(this)); + var keys = Object.keys(this.prefRecords_).map((el) => this.prefix + el); if (this.trace) console.log('Preferences read: ' + this.prefix); @@ -2032,7 +2280,7 @@ lib.PreferenceManager.prototype.definePreferences = function(defaults) { * child ids. It is also used in get/add/remove operations to identify the * list of children to operate on. * @param {function} childFactory A function that will be used to generate - * instances of these childred. The factory function will receive the + * instances of these children. The factory function will receive the * parent lib.PreferenceManager object and a unique id for the new child * preferences. */ @@ -2131,7 +2379,7 @@ lib.PreferenceManager.prototype.createChild = function(listName, opt_hint, } else { // Pick a random, unique 4-digit hex identifier for the new profile. while (!id || ids.indexOf(id) != -1) { - id = Math.floor(Math.random() * 0xffff + 1).toString(16); + id = lib.f.randomInt(1, 0xffff).toString(16); id = lib.f.zpad(id, 4); if (opt_hint) id = opt_hint + ':' + id; @@ -2473,7 +2721,7 @@ lib.PreferenceManager.prototype.get = function(name) { }; /** - * Return all non-default preferences as a JSON onject. + * Return all non-default preferences as a JSON object. * * This includes any nested preference managers as well. */ @@ -2504,7 +2752,13 @@ lib.PreferenceManager.prototype.exportAsJson = function() { * * This will create nested preference managers as well. */ -lib.PreferenceManager.prototype.importFromJson = function(json) { +lib.PreferenceManager.prototype.importFromJson = function(json, opt_onComplete) { + let pendingWrites = 0; + const onWriteStorage = () => { + if (--pendingWrites < 1 && opt_onComplete) + opt_onComplete(); + }; + for (var name in json) { if (name in this.childLists_) { var childList = json[name]; @@ -2515,11 +2769,13 @@ lib.PreferenceManager.prototype.importFromJson = function(json) { if (!childPrefManager) childPrefManager = this.createChild(name, null, id); - childPrefManager.importFromJson(childList[i].json); + childPrefManager.importFromJson(childList[i].json, onWriteStorage); + pendingWrites++; } } else { - this.set(name, json[name]); + this.set(name, json[name], onWriteStorage); + pendingWrites++; } } }; @@ -2556,7 +2812,7 @@ lib.PreferenceManager.prototype.onStorageChange_ = function(map) { currentValue = (void 0); if (this.diff(currentValue, newValue)) { - if (typeof newValue == 'undefined') { + if (typeof newValue == 'undefined' || newValue === null) { record.currentValue = record.DEFAULT_VALUE; } else { record.currentValue = newValue; @@ -2766,9 +3022,27 @@ lib.Storage.Chrome.prototype.getItems = function(keys, callback) { * to read the value, since the local cache is updated synchronously. */ lib.Storage.Chrome.prototype.setItem = function(key, value, opt_callback) { + const onComplete = () => { + if (chrome.runtime.lastError) { + // Doesn't seem to be any better way of handling this. + // https://crbug.com/764759 + if (chrome.runtime.lastError.message.indexOf('MAX_WRITE_OPERATIONS')) { + console.warn(`Will retry save of ${key} after exceeding quota`, + chrome.runtime.lastError); + setTimeout(() => this.setItem(key, value, onComplete), 1000); + return; + } else { + console.error('Unknown runtime error', chrome.runtime.lastError); + } + } + + if (opt_callback) + opt_callback(); + }; + var obj = {}; obj[key] = value; - this.storage_.set(obj, opt_callback); + this.storage_.set(obj, onComplete); }; /** @@ -2830,9 +3104,11 @@ lib.Storage.Local.prototype.onStorage_ = function(e) { if (e.storageArea != this.storage_) return; - // IE throws an exception if JSON.parse is given an empty string. - var prevValue = e.oldValue ? JSON.parse(e.oldValue) : ""; - var curValue = e.newValue ? JSON.parse(e.newValue) : ""; + // JS throws an exception if JSON.parse is given an empty string. So here we + // only parse if the value is truthy. This mean the empty string, undefined + // and null will not be parsed. + var prevValue = e.oldValue ? JSON.parse(e.oldValue) : e.oldValue; + var curValue = e.newValue ? JSON.parse(e.newValue) : e.newValue; var o = {}; o[e.key] = { oldValue: prevValue, @@ -3213,14 +3489,14 @@ lib.Storage.Memory.prototype.removeItems = function(ary, opt_callback) { */ /** - * Root object in the unit test heirarchy, and keeper of the log object. + * Root object in the unit test hierarchy, and keeper of the log object. * * @param {lib.TestManager.Log} opt_log Optional lib.TestManager.Log object. - * Logs to the JavaScript console if ommitted. + * Logs to the JavaScript console if omitted. */ lib.TestManager = function(opt_log) { this.log = opt_log || new lib.TestManager.Log(); -} +}; /** * Create a new test run object for this test manager. @@ -3242,85 +3518,76 @@ lib.TestManager.prototype.createTestRun = function(opt_cx) { lib.TestManager.prototype.onTestRunComplete = function(testRun) {}; /** - * Destination for test case output. + * Called before a test associated with this test manager is run. * - * @param {function(string)} opt_logFunction Optional function to call to - * write a string to the log. If ommitted, console.log is used. + * @param {lib.TestManager.Result} result The result object for the upcoming + * test. + * @param {Object} cx The context object for a test run. */ -lib.TestManager.Log = function(opt_logFunction) { - this.logFunction_ = opt_logFunction || function(s) { console.log(s) }; - this.pending_ = ''; - this.prefix_ = ''; - this.prefixStack_ = []; -}; +lib.TestManager.prototype.testPreamble = function(result, cx) {}; /** - * Add a prefix to log messages. + * Called after a test associated with this test manager finishes. * - * This only affects log messages that are added after the prefix is pushed. - * - * @param {string} str The prefix to prepend to future log messages. - */ -lib.TestManager.Log.prototype.pushPrefix = function(str) { - this.prefixStack_.push(str); - this.prefix_ = this.prefixStack_.join(''); -}; - -/** - * Remove the most recently added message prefix. + * @param {lib.TestManager.Result} result The result object for the finished + * test. + * @param {Object} cx The context object for a test run. */ -lib.TestManager.Log.prototype.popPrefix = function() { - this.prefixStack_.pop(); - this.prefix_ = this.prefixStack_.join(''); -}; +lib.TestManager.prototype.testPostamble = function(result, cx) {}; /** - * Queue up a string to print to the log. - * - * If a line is already pending, this string is added to it. - * - * The string is not actually printed to the log until flush() or println() - * is called. The following call sequence will result in TWO lines in the - * log... - * - * log.print('hello'); - * log.print(' '); - * log.println('world'); - * - * While a typical stream-like thing would result in 'hello world\n', this one - * results in 'hello \nworld\n'. + * Destination for test case output. * - * @param {string} str The string to add to the log. - */ -lib.TestManager.Log.prototype.print = function(str) { - if (this.pending_) { - this.pending_ += str; - } else { - this.pending_ = this.prefix_ + str; - } -}; - -/** - * Print a line to the log and flush it immediately. + * Thw API will be the same as the console object. e.g. We support info(), + * warn(), error(), etc... just like console.info(), etc... * - * @param {string} str The string to add to the log. + * @param {Object} opt_console The console object to route all logging through. + * Should provide saome API as the standard console API. */ -lib.TestManager.Log.prototype.println = function(str) { - if (this.pending_) - this.flush(); +lib.TestManager.Log = function(opt_console=console) { + this.save = false; + this.data = ''; + this.prefix_ = ''; + this.prefixStack_ = 0; + + // Capture all the console entry points in case code at runtime calls these + // directly. We want to be able to still see things. + // We also expose the direct API to our callers (e.g. we provide warn()). + this.console_ = opt_console; + ['log', 'debug', 'info', 'warn', 'error'].forEach((level) => { + let msgPrefix = ''; + switch (level) { + case 'debug': + case 'warn': + case 'error': + msgPrefix = level.toUpperCase() + ': '; + break; + } - this.logFunction_(this.prefix_ + str); -}; + const oLog = this.console_[level]; + this[level] = this.console_[level] = (...args) => { + if (this.save) + this.data += this.prefix_ + msgPrefix + args.join(' ') + '\n'; + oLog.apply(this.console_, args); + }; + }); -/** - * Flush any pending log message. - */ -lib.TestManager.Log.prototype.flush = function() { - if (!this.pending_) - return; + // Wrap/bind the group functions. + ['group', 'groupCollapsed'].forEach((group) => { + const oGroup = this.console_[group]; + this[group] = this.console_[group] = (label='') => { + oGroup(label); + if (this.save) + this.data += this.prefix_ + label + '\n'; + this.prefix_ = ' '.repeat(++this.prefixStack_); + }; + }); - this.logFunction_(this.pending_); - this.pending_ = ''; + const oGroupEnd = this.console_.groupEnd; + this.groupEnd = this.console_.groupEnd = () => { + oGroupEnd(); + this.prefix_ = ' '.repeat(--this.prefixStack_); + }; }; /** @@ -3362,10 +3629,8 @@ lib.TestManager.Log.prototype.flush = function() { * * // Sample asynchronous test case. * MyTests.addTest('async-pop-length', function(result, cx) { - * var self = this; - * - * var callback = function() { - * result.assertEQ(self.list.length, self.size - 1); + * var callback = () => { + * result.assertEQ(this.list.length, this.size - 1); * result.pass(); * }; * @@ -3399,7 +3664,8 @@ lib.TestManager.Suite = function(suiteName) { ctor.getTestList = lib.TestManager.Suite.getTestList; ctor.testList_ = []; ctor.testMap_ = {}; - ctor.prototype = { __proto__: lib.TestManager.Suite.prototype }; + ctor.prototype = Object.create(lib.TestManager.Suite.prototype); + ctor.constructor = lib.TestManager.Suite; lib.TestManager.Suite.subclasses.push(ctor); @@ -3535,7 +3801,7 @@ lib.TestManager.Suite.prototype.preamble = function(result, cx) {}; * * Any exception here will abort the remainder of the test run. * - * @param {lib.TestManager.Result} result The result object for the upcoming + * @param {lib.TestManager.Result} result The result object for the finished * test. * @param {Object} cx The context object for a test run. */ @@ -3665,7 +3931,7 @@ lib.TestManager.TestRun = function(testManager, cx) { /** * Number of maximum failures. The test run will stop when this number is - * reached. If 0 or ommitted, the entire set of selected tests is run, even + * reached. If 0 or omitted, the entire set of selected tests is run, even * if some fail. */ this.maxFailures = 0; @@ -3684,7 +3950,7 @@ lib.TestManager.TestRun = function(testManager, cx) { * This value can be passed to select() to indicate that all tests should * be selected. */ -lib.TestManager.TestRun.prototype.ALL_TESTS = new String(''); +lib.TestManager.TestRun.prototype.ALL_TESTS = lib.f.createEnum(''); /** * Add a single test to the test run. @@ -3741,7 +4007,7 @@ lib.TestManager.TestRun.prototype.selectPattern = function(pattern) { } if (!selectCount) { - this.log.println('No tests matched selection criteria: ' + pattern); + this.log.warn('No tests matched selection criteria: ' + pattern); } return selectCount; @@ -3775,9 +4041,9 @@ lib.TestManager.TestRun.prototype.onUncaughtException_ = function( if (this.currentResult.status != this.currentResult.PENDING) when = 'after'; - this.log.println('Uncaught exception ' + when + ' test case: ' + - this.currentResult.test.fullName); - this.log.println(message + ', ' + file + ':' + line); + this.log.error('Uncaught exception ' + when + ' test case: ' + + this.currentResult.test.fullName); + this.log.error(message + ', ' + file + ':' + line); this.currentResult.completeTest_(this.currentResult.FAILED, false); @@ -3808,11 +4074,10 @@ lib.TestManager.TestRun.prototype.onTestRunComplete_ = function( this.duration = (new Date()) - this.startDate; - this.log.popPrefix(); - this.log.println('} ' + this.passes.length + ' passed, ' + - this.failures.length + ' failed, ' + - this.msToSeconds_(this.duration)); - this.log.println(''); + this.log.groupEnd(); + this.log.info(this.passes.length + ' passed, ' + + this.failures.length + ' failed, ' + + this.msToSeconds_(this.duration)); this.summarize(); @@ -3829,17 +4094,19 @@ lib.TestManager.TestRun.prototype.onTestRunComplete_ = function( */ lib.TestManager.TestRun.prototype.onResultComplete = function(result) { try { - result.suite.postamble(); + this.testManager.testPostamble(result, this.cx); + result.suite.postamble(result, this.ctx); } catch (ex) { - this.log.println('Unexpected exception in postamble: ' + - (ex.stack ? ex.stack : ex)); + this.log.error('Unexpected exception in postamble: ' + + (ex.stack ? ex.stack : ex)); this.panic = true; } - this.log.popPrefix(); - this.log.print('} ' + result.status + ', ' + - this.msToSeconds_(result.duration)); - this.log.flush(); + if (result.status != result.PASSED) + this.log.error(result.status); + else if (result.duration > 500) + this.log.warn('Slow test took ' + this.msToSeconds_(result.duration)); + this.log.groupEnd(); if (result.status == result.FAILED) { this.failures.push(result); @@ -3847,9 +4114,10 @@ lib.TestManager.TestRun.prototype.onResultComplete = function(result) { } else if (result.status == result.PASSED) { this.passes.push(result); } else { - this.log.println('Unknown result status: ' + result.test.fullName + ': ' + - result.status); - return this.panic = true; + this.log.error('Unknown result status: ' + result.test.fullName + ': ' + + result.status); + this.panic = true; + return; } this.runNextTest_(); @@ -3876,8 +4144,8 @@ lib.TestManager.TestRun.prototype.onResultComplete = function(result) { */ lib.TestManager.TestRun.prototype.onResultReComplete = function( result, lateStatus) { - this.log.println('Late complete for test: ' + result.test.fullName + ': ' + - lateStatus); + this.log.error('Late complete for test: ' + result.test.fullName + ': ' + + lateStatus); // Consider any late completion a failure, even if it's a double-pass, since // it's a misuse of the testing API. @@ -3892,12 +4160,15 @@ lib.TestManager.TestRun.prototype.onResultReComplete = function( * Run the next test in the queue. */ lib.TestManager.TestRun.prototype.runNextTest_ = function() { - if (this.panic || !this.testQueue_.length) - return this.onTestRunComplete_(); + if (this.panic || !this.testQueue_.length) { + this.onTestRunComplete_(); + return; + } if (this.maxFailures && this.failures.length >= this.maxFailures) { - this.log.println('Maximum failure count reached, aborting test run.'); - return this.onTestRunComplete_(); + this.log.error('Maximum failure count reached, aborting test run.'); + this.onTestRunComplete_(); + return; } // Peek at the top test first. We remove it later just before it's about @@ -3908,30 +4179,31 @@ lib.TestManager.TestRun.prototype.runNextTest_ = function() { try { if (!suite || !(suite instanceof test.suiteClass)) { - this.log.println('Initializing suite: ' + test.suiteClass.suiteName); + if (suite) + this.log.groupEnd(); + this.log.group(test.suiteClass.suiteName); suite = new test.suiteClass(this.testManager, this.cx); } } catch (ex) { // If test suite setup fails we're not even going to try to run the tests. - this.log.println('Exception during setup: ' + (ex.stack ? ex.stack : ex)); + this.log.error('Exception during setup: ' + (ex.stack ? ex.stack : ex)); this.panic = true; this.onTestRunComplete_(); return; } try { - this.log.print('Test: ' + test.fullName + ' {'); - this.log.pushPrefix(' '); + this.log.group(test.testName); this.currentResult = new lib.TestManager.Result(this, suite, test); + this.testManager.testPreamble(this.currentResult, this.cx); suite.preamble(this.currentResult, this.cx); this.testQueue_.shift(); } catch (ex) { - this.log.println('Unexpected exception during test preamble: ' + - (ex.stack ? ex.stack : ex)); - this.log.popPrefix(); - this.log.println('}'); + this.log.error('Unexpected exception during test preamble: ' + + (ex.stack ? ex.stack : ex)); + this.log.groupEnd(); this.panic = true; this.onTestRunComplete_(); @@ -3943,8 +4215,8 @@ lib.TestManager.TestRun.prototype.runNextTest_ = function() { } catch (ex) { // Result.run() should catch test exceptions and turn them into failures. // If we got here, it means there is trouble in the testing framework. - this.log.println('Unexpected exception during test run: ' + - (ex.stack ? ex.stack : ex)); + this.log.error('Unexpected exception during test run: ' + + (ex.stack ? ex.stack : ex)); this.panic = true; } }; @@ -3968,8 +4240,7 @@ lib.TestManager.TestRun.prototype.runNextTest_ = function() { * preamble will cause the test run to abort. */ lib.TestManager.TestRun.prototype.run = function() { - this.log.println('Running ' + this.testQueue_.length + ' test(s) {'); - this.log.pushPrefix(' '); + this.log.info('Running ' + this.testQueue_.length + ' test(s)'); window.onerror = this.onUncaughtException_.bind(this); this.startDate = new Date(); @@ -3990,13 +4261,13 @@ lib.TestManager.TestRun.prototype.msToSeconds_ = function(ms) { lib.TestManager.TestRun.prototype.summarize = function() { if (this.failures.length) { for (var i = 0; i < this.failures.length; i++) { - this.log.println('FAILED: ' + this.failures[i].test.fullName); + this.log.error('FAILED: ' + this.failures[i].test.fullName); } } if (this.testQueue_.length) { - this.log.println('Test run incomplete: ' + this.testQueue_.length + - ' test(s) were not run.'); + this.log.warn('Test run incomplete: ' + this.testQueue_.length + + ' test(s) were not run.'); } }; @@ -4071,14 +4342,12 @@ lib.TestManager.Result.TestComplete = function(result) { lib.TestManager.Result.TestComplete.prototype.toString = function() { return 'lib.TestManager.Result.TestComplete: ' + this.result.test.fullName + ', status: ' + this.result.status; -} +}; /** * Start the test associated with this result. */ lib.TestManager.Result.prototype.run = function() { - var self = this; - this.startDate = new Date(); this.test.run(this); @@ -4169,7 +4438,7 @@ lib.TestManager.Result.prototype.completeTest_ = function(status, opt_throw) { * @param {*} actual The actual measured value. * @param {*} expected The value expected. * @param {string} opt_name An optional name used to identify this - * assertion in the test log. If ommitted it will be the file:line + * assertion in the test log. If omitted it will be the file:line * of the caller. */ lib.TestManager.Result.prototype.assertEQ = function( @@ -4180,7 +4449,7 @@ lib.TestManager.Result.prototype.assertEQ = function( return value; var str = String(value); - var ary = str.split('\n').map(function (e) { return JSON.stringify(e) }); + var ary = str.split('\n').map((e) => JSON.stringify(e)); if (ary.length > 1) { // If the string has newlines, start it off on its own line so that // it's easier to compare against another string with newlines. @@ -4193,6 +4462,11 @@ lib.TestManager.Result.prototype.assertEQ = function( if (actual === expected) return; + // Deal with common object types since JavaScript can't. + if (expected instanceof Array) + if (lib.array.compare(actual, expected)) + return; + var name = opt_name ? '[' + opt_name + ']' : ''; this.fail('assertEQ' + name + ': ' + this.getCallerLocation_(1) + ': ' + @@ -4210,7 +4484,7 @@ lib.TestManager.Result.prototype.assertEQ = function( * * @param {boolean} actual The actual measured value. * @param {string} opt_name An optional name used to identify this - * assertion in the test log. If ommitted it will be the file:line + * assertion in the test log. If omitted it will be the file:line * of the caller. */ lib.TestManager.Result.prototype.assert = function(actual, opt_name) { @@ -4247,7 +4521,7 @@ lib.TestManager.Result.prototype.getCallerLocation_ = function(frameIndex) { * Write a message to the result log. */ lib.TestManager.Result.prototype.println = function(message) { - this.testRun.log.println(message); + this.testRun.log.info(message); }; /** @@ -4282,8 +4556,8 @@ lib.TestManager.Result.prototype.pass = function() { // TODO(davidben): When the string encoding API is implemented, // replace this with the native in-browser implementation. // -// http://wiki.whatwg.org/wiki/StringEncoding -// http://dvcs.w3.org/hg/encoding/raw-file/tip/Overview.html +// https://wiki.whatwg.org/wiki/StringEncoding +// https://encoding.spec.whatwg.org/ /** * A stateful UTF-8 decoder. @@ -4442,7 +4716,7 @@ lib.encodeUTF8 = function(str) { } return ret; }; -// SOURCE FILE: libdot/js/lib_wc.js +// SOURCE FILE: libdot/third_party/wcwidth/lib_wc.js // Copyright (c) 2014 The Chromium OS Authors. All rights reserved. // Use of lib.wc source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -4536,7 +4810,7 @@ lib.encodeUTF8 = function(str) { * - Spacing characters in the East Asian Wide (W) or East Asian Full-width (F) * category as defined in Unicode Technical Report #11 have a column width of * 2. - * - East Asian Ambigous characters are taken into account if + * - East Asian Ambiguous characters are taken into account if * regardCjkAmbiguous flag is enabled. They have a column width of 2. * - All remaining characters (including all printable ISO 8859-1 and WGL4 * characters, Unicode control characters, etc.) have a column width of 1. @@ -4549,7 +4823,7 @@ lib.wc = {}; // Width of a nul character. lib.wc.nulWidth = 0; -// Width of a control charater. +// Width of a control character. lib.wc.controlWidth = 0; // Flag whether to consider East Asian Ambiguous characters. @@ -4559,135 +4833,255 @@ lib.wc.regardCjkAmbiguous = false; lib.wc.cjkAmbiguousWidth = 2; // Sorted list of non-overlapping intervals of non-spacing characters -// generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" +// generated by the `./ranges.py` helper. lib.wc.combining = [ - [ 0x0300, 0x036F ], [ 0x0483, 0x0486 ], [ 0x0488, 0x0489 ], - [ 0x0591, 0x05BD ], [ 0x05BF, 0x05BF ], [ 0x05C1, 0x05C2 ], - [ 0x05C4, 0x05C5 ], [ 0x05C7, 0x05C7 ], [ 0x0600, 0x0603 ], - [ 0x0610, 0x0615 ], [ 0x064B, 0x065E ], [ 0x0670, 0x0670 ], - [ 0x06D6, 0x06E4 ], [ 0x06E7, 0x06E8 ], [ 0x06EA, 0x06ED ], - [ 0x070F, 0x070F ], [ 0x0711, 0x0711 ], [ 0x0730, 0x074A ], - [ 0x07A6, 0x07B0 ], [ 0x07EB, 0x07F3 ], [ 0x0901, 0x0902 ], - [ 0x093C, 0x093C ], [ 0x0941, 0x0948 ], [ 0x094D, 0x094D ], - [ 0x0951, 0x0954 ], [ 0x0962, 0x0963 ], [ 0x0981, 0x0981 ], - [ 0x09BC, 0x09BC ], [ 0x09C1, 0x09C4 ], [ 0x09CD, 0x09CD ], - [ 0x09E2, 0x09E3 ], [ 0x0A01, 0x0A02 ], [ 0x0A3C, 0x0A3C ], - [ 0x0A41, 0x0A42 ], [ 0x0A47, 0x0A48 ], [ 0x0A4B, 0x0A4D ], - [ 0x0A70, 0x0A71 ], [ 0x0A81, 0x0A82 ], [ 0x0ABC, 0x0ABC ], - [ 0x0AC1, 0x0AC5 ], [ 0x0AC7, 0x0AC8 ], [ 0x0ACD, 0x0ACD ], - [ 0x0AE2, 0x0AE3 ], [ 0x0B01, 0x0B01 ], [ 0x0B3C, 0x0B3C ], - [ 0x0B3F, 0x0B3F ], [ 0x0B41, 0x0B43 ], [ 0x0B4D, 0x0B4D ], - [ 0x0B56, 0x0B56 ], [ 0x0B82, 0x0B82 ], [ 0x0BC0, 0x0BC0 ], - [ 0x0BCD, 0x0BCD ], [ 0x0C3E, 0x0C40 ], [ 0x0C46, 0x0C48 ], - [ 0x0C4A, 0x0C4D ], [ 0x0C55, 0x0C56 ], [ 0x0CBC, 0x0CBC ], - [ 0x0CBF, 0x0CBF ], [ 0x0CC6, 0x0CC6 ], [ 0x0CCC, 0x0CCD ], - [ 0x0CE2, 0x0CE3 ], [ 0x0D41, 0x0D43 ], [ 0x0D4D, 0x0D4D ], - [ 0x0DCA, 0x0DCA ], [ 0x0DD2, 0x0DD4 ], [ 0x0DD6, 0x0DD6 ], - [ 0x0E31, 0x0E31 ], [ 0x0E34, 0x0E3A ], [ 0x0E47, 0x0E4E ], - [ 0x0EB1, 0x0EB1 ], [ 0x0EB4, 0x0EB9 ], [ 0x0EBB, 0x0EBC ], - [ 0x0EC8, 0x0ECD ], [ 0x0F18, 0x0F19 ], [ 0x0F35, 0x0F35 ], - [ 0x0F37, 0x0F37 ], [ 0x0F39, 0x0F39 ], [ 0x0F71, 0x0F7E ], - [ 0x0F80, 0x0F84 ], [ 0x0F86, 0x0F87 ], [ 0x0F90, 0x0F97 ], - [ 0x0F99, 0x0FBC ], [ 0x0FC6, 0x0FC6 ], [ 0x102D, 0x1030 ], - [ 0x1032, 0x1032 ], [ 0x1036, 0x1037 ], [ 0x1039, 0x1039 ], - [ 0x1058, 0x1059 ], [ 0x1160, 0x11FF ], [ 0x135F, 0x135F ], - [ 0x1712, 0x1714 ], [ 0x1732, 0x1734 ], [ 0x1752, 0x1753 ], - [ 0x1772, 0x1773 ], [ 0x17B4, 0x17B5 ], [ 0x17B7, 0x17BD ], - [ 0x17C6, 0x17C6 ], [ 0x17C9, 0x17D3 ], [ 0x17DD, 0x17DD ], - [ 0x180B, 0x180D ], [ 0x18A9, 0x18A9 ], [ 0x1920, 0x1922 ], - [ 0x1927, 0x1928 ], [ 0x1932, 0x1932 ], [ 0x1939, 0x193B ], - [ 0x1A17, 0x1A18 ], [ 0x1B00, 0x1B03 ], [ 0x1B34, 0x1B34 ], - [ 0x1B36, 0x1B3A ], [ 0x1B3C, 0x1B3C ], [ 0x1B42, 0x1B42 ], - [ 0x1B6B, 0x1B73 ], [ 0x1DC0, 0x1DCA ], [ 0x1DFE, 0x1DFF ], - [ 0x200B, 0x200F ], [ 0x202A, 0x202E ], [ 0x2060, 0x2063 ], - [ 0x206A, 0x206F ], [ 0x20D0, 0x20EF ], [ 0x302A, 0x302F ], - [ 0x3099, 0x309A ], [ 0xA806, 0xA806 ], [ 0xA80B, 0xA80B ], - [ 0xA825, 0xA826 ], [ 0xFB1E, 0xFB1E ], [ 0xFE00, 0xFE0F ], - [ 0xFE20, 0xFE23 ], [ 0xFEFF, 0xFEFF ], [ 0xFFF9, 0xFFFB ], - [ 0x10A01, 0x10A03 ], [ 0x10A05, 0x10A06 ], [ 0x10A0C, 0x10A0F ], - [ 0x10A38, 0x10A3A ], [ 0x10A3F, 0x10A3F ], [ 0x1D167, 0x1D169 ], - [ 0x1D173, 0x1D182 ], [ 0x1D185, 0x1D18B ], [ 0x1D1AA, 0x1D1AD ], - [ 0x1D242, 0x1D244 ], [ 0xE0001, 0xE0001 ], [ 0xE0020, 0xE007F ], - [ 0xE0100, 0xE01EF ] + [0x00ad, 0x00ad], [0x0300, 0x036f], [0x0483, 0x0489], + [0x0591, 0x05bd], [0x05bf, 0x05bf], [0x05c1, 0x05c2], + [0x05c4, 0x05c5], [0x05c7, 0x05c7], [0x0610, 0x061a], + [0x061c, 0x061c], [0x064b, 0x065f], [0x0670, 0x0670], + [0x06d6, 0x06dc], [0x06df, 0x06e4], [0x06e7, 0x06e8], + [0x06ea, 0x06ed], [0x0711, 0x0711], [0x0730, 0x074a], + [0x07a6, 0x07b0], [0x07eb, 0x07f3], [0x0816, 0x0819], + [0x081b, 0x0823], [0x0825, 0x0827], [0x0829, 0x082d], + [0x0859, 0x085b], [0x08d4, 0x08e1], [0x08e3, 0x0902], + [0x093a, 0x093a], [0x093c, 0x093c], [0x0941, 0x0948], + [0x094d, 0x094d], [0x0951, 0x0957], [0x0962, 0x0963], + [0x0981, 0x0981], [0x09bc, 0x09bc], [0x09c1, 0x09c4], + [0x09cd, 0x09cd], [0x09e2, 0x09e3], [0x0a01, 0x0a02], + [0x0a3c, 0x0a3c], [0x0a41, 0x0a42], [0x0a47, 0x0a48], + [0x0a4b, 0x0a4d], [0x0a51, 0x0a51], [0x0a70, 0x0a71], + [0x0a75, 0x0a75], [0x0a81, 0x0a82], [0x0abc, 0x0abc], + [0x0ac1, 0x0ac5], [0x0ac7, 0x0ac8], [0x0acd, 0x0acd], + [0x0ae2, 0x0ae3], [0x0afa, 0x0aff], [0x0b01, 0x0b01], + [0x0b3c, 0x0b3c], [0x0b3f, 0x0b3f], [0x0b41, 0x0b44], + [0x0b4d, 0x0b4d], [0x0b56, 0x0b56], [0x0b62, 0x0b63], + [0x0b82, 0x0b82], [0x0bc0, 0x0bc0], [0x0bcd, 0x0bcd], + [0x0c00, 0x0c00], [0x0c3e, 0x0c40], [0x0c46, 0x0c48], + [0x0c4a, 0x0c4d], [0x0c55, 0x0c56], [0x0c62, 0x0c63], + [0x0c81, 0x0c81], [0x0cbc, 0x0cbc], [0x0cbf, 0x0cbf], + [0x0cc6, 0x0cc6], [0x0ccc, 0x0ccd], [0x0ce2, 0x0ce3], + [0x0d00, 0x0d01], [0x0d3b, 0x0d3c], [0x0d41, 0x0d44], + [0x0d4d, 0x0d4d], [0x0d62, 0x0d63], [0x0dca, 0x0dca], + [0x0dd2, 0x0dd4], [0x0dd6, 0x0dd6], [0x0e31, 0x0e31], + [0x0e34, 0x0e3a], [0x0e47, 0x0e4e], [0x0eb1, 0x0eb1], + [0x0eb4, 0x0eb9], [0x0ebb, 0x0ebc], [0x0ec8, 0x0ecd], + [0x0f18, 0x0f19], [0x0f35, 0x0f35], [0x0f37, 0x0f37], + [0x0f39, 0x0f39], [0x0f71, 0x0f7e], [0x0f80, 0x0f84], + [0x0f86, 0x0f87], [0x0f8d, 0x0f97], [0x0f99, 0x0fbc], + [0x0fc6, 0x0fc6], [0x102d, 0x1030], [0x1032, 0x1037], + [0x1039, 0x103a], [0x103d, 0x103e], [0x1058, 0x1059], + [0x105e, 0x1060], [0x1071, 0x1074], [0x1082, 0x1082], + [0x1085, 0x1086], [0x108d, 0x108d], [0x109d, 0x109d], + [0x1160, 0x11ff], [0x135d, 0x135f], [0x1712, 0x1714], + [0x1732, 0x1734], [0x1752, 0x1753], [0x1772, 0x1773], + [0x17b4, 0x17b5], [0x17b7, 0x17bd], [0x17c6, 0x17c6], + [0x17c9, 0x17d3], [0x17dd, 0x17dd], [0x180b, 0x180e], + [0x1885, 0x1886], [0x18a9, 0x18a9], [0x1920, 0x1922], + [0x1927, 0x1928], [0x1932, 0x1932], [0x1939, 0x193b], + [0x1a17, 0x1a18], [0x1a1b, 0x1a1b], [0x1a56, 0x1a56], + [0x1a58, 0x1a5e], [0x1a60, 0x1a60], [0x1a62, 0x1a62], + [0x1a65, 0x1a6c], [0x1a73, 0x1a7c], [0x1a7f, 0x1a7f], + [0x1ab0, 0x1abe], [0x1b00, 0x1b03], [0x1b34, 0x1b34], + [0x1b36, 0x1b3a], [0x1b3c, 0x1b3c], [0x1b42, 0x1b42], + [0x1b6b, 0x1b73], [0x1b80, 0x1b81], [0x1ba2, 0x1ba5], + [0x1ba8, 0x1ba9], [0x1bab, 0x1bad], [0x1be6, 0x1be6], + [0x1be8, 0x1be9], [0x1bed, 0x1bed], [0x1bef, 0x1bf1], + [0x1c2c, 0x1c33], [0x1c36, 0x1c37], [0x1cd0, 0x1cd2], + [0x1cd4, 0x1ce0], [0x1ce2, 0x1ce8], [0x1ced, 0x1ced], + [0x1cf4, 0x1cf4], [0x1cf8, 0x1cf9], [0x1dc0, 0x1df9], + [0x1dfb, 0x1dff], [0x200b, 0x200f], [0x202a, 0x202e], + [0x2060, 0x2064], [0x2066, 0x206f], [0x20d0, 0x20f0], + [0x2cef, 0x2cf1], [0x2d7f, 0x2d7f], [0x2de0, 0x2dff], + [0x302a, 0x302d], [0x3099, 0x309a], [0xa66f, 0xa672], + [0xa674, 0xa67d], [0xa69e, 0xa69f], [0xa6f0, 0xa6f1], + [0xa802, 0xa802], [0xa806, 0xa806], [0xa80b, 0xa80b], + [0xa825, 0xa826], [0xa8c4, 0xa8c5], [0xa8e0, 0xa8f1], + [0xa926, 0xa92d], [0xa947, 0xa951], [0xa980, 0xa982], + [0xa9b3, 0xa9b3], [0xa9b6, 0xa9b9], [0xa9bc, 0xa9bc], + [0xa9e5, 0xa9e5], [0xaa29, 0xaa2e], [0xaa31, 0xaa32], + [0xaa35, 0xaa36], [0xaa43, 0xaa43], [0xaa4c, 0xaa4c], + [0xaa7c, 0xaa7c], [0xaab0, 0xaab0], [0xaab2, 0xaab4], + [0xaab7, 0xaab8], [0xaabe, 0xaabf], [0xaac1, 0xaac1], + [0xaaec, 0xaaed], [0xaaf6, 0xaaf6], [0xabe5, 0xabe5], + [0xabe8, 0xabe8], [0xabed, 0xabed], [0xfb1e, 0xfb1e], + [0xfe00, 0xfe0f], [0xfe20, 0xfe2f], [0xfeff, 0xfeff], + [0xfff9, 0xfffb], [0x101fd, 0x101fd], [0x102e0, 0x102e0], + [0x10376, 0x1037a], [0x10a01, 0x10a03], [0x10a05, 0x10a06], + [0x10a0c, 0x10a0f], [0x10a38, 0x10a3a], [0x10a3f, 0x10a3f], + [0x10ae5, 0x10ae6], [0x11001, 0x11001], [0x11038, 0x11046], + [0x1107f, 0x11081], [0x110b3, 0x110b6], [0x110b9, 0x110ba], + [0x11100, 0x11102], [0x11127, 0x1112b], [0x1112d, 0x11134], + [0x11173, 0x11173], [0x11180, 0x11181], [0x111b6, 0x111be], + [0x111ca, 0x111cc], [0x1122f, 0x11231], [0x11234, 0x11234], + [0x11236, 0x11237], [0x1123e, 0x1123e], [0x112df, 0x112df], + [0x112e3, 0x112ea], [0x11300, 0x11301], [0x1133c, 0x1133c], + [0x11340, 0x11340], [0x11366, 0x1136c], [0x11370, 0x11374], + [0x11438, 0x1143f], [0x11442, 0x11444], [0x11446, 0x11446], + [0x114b3, 0x114b8], [0x114ba, 0x114ba], [0x114bf, 0x114c0], + [0x114c2, 0x114c3], [0x115b2, 0x115b5], [0x115bc, 0x115bd], + [0x115bf, 0x115c0], [0x115dc, 0x115dd], [0x11633, 0x1163a], + [0x1163d, 0x1163d], [0x1163f, 0x11640], [0x116ab, 0x116ab], + [0x116ad, 0x116ad], [0x116b0, 0x116b5], [0x116b7, 0x116b7], + [0x1171d, 0x1171f], [0x11722, 0x11725], [0x11727, 0x1172b], + [0x11a01, 0x11a06], [0x11a09, 0x11a0a], [0x11a33, 0x11a38], + [0x11a3b, 0x11a3e], [0x11a47, 0x11a47], [0x11a51, 0x11a56], + [0x11a59, 0x11a5b], [0x11a8a, 0x11a96], [0x11a98, 0x11a99], + [0x11c30, 0x11c36], [0x11c38, 0x11c3d], [0x11c3f, 0x11c3f], + [0x11c92, 0x11ca7], [0x11caa, 0x11cb0], [0x11cb2, 0x11cb3], + [0x11cb5, 0x11cb6], [0x11d31, 0x11d36], [0x11d3a, 0x11d3a], + [0x11d3c, 0x11d3d], [0x11d3f, 0x11d45], [0x11d47, 0x11d47], + [0x16af0, 0x16af4], [0x16b30, 0x16b36], [0x16f8f, 0x16f92], + [0x1bc9d, 0x1bc9e], [0x1bca0, 0x1bca3], [0x1d167, 0x1d169], + [0x1d173, 0x1d182], [0x1d185, 0x1d18b], [0x1d1aa, 0x1d1ad], + [0x1d242, 0x1d244], [0x1da00, 0x1da36], [0x1da3b, 0x1da6c], + [0x1da75, 0x1da75], [0x1da84, 0x1da84], [0x1da9b, 0x1da9f], + [0x1daa1, 0x1daaf], [0x1e000, 0x1e006], [0x1e008, 0x1e018], + [0x1e01b, 0x1e021], [0x1e023, 0x1e024], [0x1e026, 0x1e02a], + [0x1e8d0, 0x1e8d6], [0x1e944, 0x1e94a], [0xe0001, 0xe0001], + [0xe0020, 0xe007f], [0xe0100, 0xe01ef], ]; // Sorted list of non-overlapping intervals of East Asian Ambiguous characters -// generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" +// generated by the `./ranges.py` helper. lib.wc.ambiguous = [ - [ 0x00A1, 0x00A1 ], [ 0x00A4, 0x00A4 ], [ 0x00A7, 0x00A8 ], - [ 0x00AA, 0x00AA ], [ 0x00AE, 0x00AE ], [ 0x00B0, 0x00B4 ], - [ 0x00B6, 0x00BA ], [ 0x00BC, 0x00BF ], [ 0x00C6, 0x00C6 ], - [ 0x00D0, 0x00D0 ], [ 0x00D7, 0x00D8 ], [ 0x00DE, 0x00E1 ], - [ 0x00E6, 0x00E6 ], [ 0x00E8, 0x00EA ], [ 0x00EC, 0x00ED ], - [ 0x00F0, 0x00F0 ], [ 0x00F2, 0x00F3 ], [ 0x00F7, 0x00FA ], - [ 0x00FC, 0x00FC ], [ 0x00FE, 0x00FE ], [ 0x0101, 0x0101 ], - [ 0x0111, 0x0111 ], [ 0x0113, 0x0113 ], [ 0x011B, 0x011B ], - [ 0x0126, 0x0127 ], [ 0x012B, 0x012B ], [ 0x0131, 0x0133 ], - [ 0x0138, 0x0138 ], [ 0x013F, 0x0142 ], [ 0x0144, 0x0144 ], - [ 0x0148, 0x014B ], [ 0x014D, 0x014D ], [ 0x0152, 0x0153 ], - [ 0x0166, 0x0167 ], [ 0x016B, 0x016B ], [ 0x01CE, 0x01CE ], - [ 0x01D0, 0x01D0 ], [ 0x01D2, 0x01D2 ], [ 0x01D4, 0x01D4 ], - [ 0x01D6, 0x01D6 ], [ 0x01D8, 0x01D8 ], [ 0x01DA, 0x01DA ], - [ 0x01DC, 0x01DC ], [ 0x0251, 0x0251 ], [ 0x0261, 0x0261 ], - [ 0x02C4, 0x02C4 ], [ 0x02C7, 0x02C7 ], [ 0x02C9, 0x02CB ], - [ 0x02CD, 0x02CD ], [ 0x02D0, 0x02D0 ], [ 0x02D8, 0x02DB ], - [ 0x02DD, 0x02DD ], [ 0x02DF, 0x02DF ], [ 0x0391, 0x03A1 ], - [ 0x03A3, 0x03A9 ], [ 0x03B1, 0x03C1 ], [ 0x03C3, 0x03C9 ], - [ 0x0401, 0x0401 ], [ 0x0410, 0x044F ], [ 0x0451, 0x0451 ], - [ 0x2010, 0x2010 ], [ 0x2013, 0x2016 ], [ 0x2018, 0x2019 ], - [ 0x201C, 0x201D ], [ 0x2020, 0x2022 ], [ 0x2024, 0x2027 ], - [ 0x2030, 0x2030 ], [ 0x2032, 0x2033 ], [ 0x2035, 0x2035 ], - [ 0x203B, 0x203B ], [ 0x203E, 0x203E ], [ 0x2074, 0x2074 ], - [ 0x207F, 0x207F ], [ 0x2081, 0x2084 ], [ 0x20AC, 0x20AC ], - [ 0x2103, 0x2103 ], [ 0x2105, 0x2105 ], [ 0x2109, 0x2109 ], - [ 0x2113, 0x2113 ], [ 0x2116, 0x2116 ], [ 0x2121, 0x2122 ], - [ 0x2126, 0x2126 ], [ 0x212B, 0x212B ], [ 0x2153, 0x2154 ], - [ 0x215B, 0x215E ], [ 0x2160, 0x216B ], [ 0x2170, 0x2179 ], - [ 0x2190, 0x2199 ], [ 0x21B8, 0x21B9 ], [ 0x21D2, 0x21D2 ], - [ 0x21D4, 0x21D4 ], [ 0x21E7, 0x21E7 ], [ 0x2200, 0x2200 ], - [ 0x2202, 0x2203 ], [ 0x2207, 0x2208 ], [ 0x220B, 0x220B ], - [ 0x220F, 0x220F ], [ 0x2211, 0x2211 ], [ 0x2215, 0x2215 ], - [ 0x221A, 0x221A ], [ 0x221D, 0x2220 ], [ 0x2223, 0x2223 ], - [ 0x2225, 0x2225 ], [ 0x2227, 0x222C ], [ 0x222E, 0x222E ], - [ 0x2234, 0x2237 ], [ 0x223C, 0x223D ], [ 0x2248, 0x2248 ], - [ 0x224C, 0x224C ], [ 0x2252, 0x2252 ], [ 0x2260, 0x2261 ], - [ 0x2264, 0x2267 ], [ 0x226A, 0x226B ], [ 0x226E, 0x226F ], - [ 0x2282, 0x2283 ], [ 0x2286, 0x2287 ], [ 0x2295, 0x2295 ], - [ 0x2299, 0x2299 ], [ 0x22A5, 0x22A5 ], [ 0x22BF, 0x22BF ], - [ 0x2312, 0x2312 ], [ 0x2460, 0x24E9 ], [ 0x24EB, 0x254B ], - [ 0x2550, 0x2573 ], [ 0x2580, 0x258F ], [ 0x2592, 0x2595 ], - [ 0x25A0, 0x25A1 ], [ 0x25A3, 0x25A9 ], [ 0x25B2, 0x25B3 ], - [ 0x25B6, 0x25B7 ], [ 0x25BC, 0x25BD ], [ 0x25C0, 0x25C1 ], - [ 0x25C6, 0x25C8 ], [ 0x25CB, 0x25CB ], [ 0x25CE, 0x25D1 ], - [ 0x25E2, 0x25E5 ], [ 0x25EF, 0x25EF ], [ 0x2605, 0x2606 ], - [ 0x2609, 0x2609 ], [ 0x260E, 0x260F ], [ 0x2614, 0x2615 ], - [ 0x261C, 0x261C ], [ 0x261E, 0x261E ], [ 0x2640, 0x2640 ], - [ 0x2642, 0x2642 ], [ 0x2660, 0x2661 ], [ 0x2663, 0x2665 ], - [ 0x2667, 0x266A ], [ 0x266C, 0x266D ], [ 0x266F, 0x266F ], - [ 0x273D, 0x273D ], [ 0x2776, 0x277F ], [ 0xE000, 0xF8FF ], - [ 0xFFFD, 0xFFFD ], [ 0xF0000, 0xFFFFD ], [ 0x100000, 0x10FFFD ] + [0x00a1, 0x00a1], [0x00a4, 0x00a4], [0x00a7, 0x00a8], + [0x00aa, 0x00aa], [0x00ad, 0x00ae], [0x00b0, 0x00b4], + [0x00b6, 0x00ba], [0x00bc, 0x00bf], [0x00c6, 0x00c6], + [0x00d0, 0x00d0], [0x00d7, 0x00d8], [0x00de, 0x00e1], + [0x00e6, 0x00e6], [0x00e8, 0x00ea], [0x00ec, 0x00ed], + [0x00f0, 0x00f0], [0x00f2, 0x00f3], [0x00f7, 0x00fa], + [0x00fc, 0x00fc], [0x00fe, 0x00fe], [0x0101, 0x0101], + [0x0111, 0x0111], [0x0113, 0x0113], [0x011b, 0x011b], + [0x0126, 0x0127], [0x012b, 0x012b], [0x0131, 0x0133], + [0x0138, 0x0138], [0x013f, 0x0142], [0x0144, 0x0144], + [0x0148, 0x014b], [0x014d, 0x014d], [0x0152, 0x0153], + [0x0166, 0x0167], [0x016b, 0x016b], [0x01ce, 0x01ce], + [0x01d0, 0x01d0], [0x01d2, 0x01d2], [0x01d4, 0x01d4], + [0x01d6, 0x01d6], [0x01d8, 0x01d8], [0x01da, 0x01da], + [0x01dc, 0x01dc], [0x0251, 0x0251], [0x0261, 0x0261], + [0x02c4, 0x02c4], [0x02c7, 0x02c7], [0x02c9, 0x02cb], + [0x02cd, 0x02cd], [0x02d0, 0x02d0], [0x02d8, 0x02db], + [0x02dd, 0x02dd], [0x02df, 0x02df], [0x0300, 0x036f], + [0x0391, 0x03a1], [0x03a3, 0x03a9], [0x03b1, 0x03c1], + [0x03c3, 0x03c9], [0x0401, 0x0401], [0x0410, 0x044f], + [0x0451, 0x0451], [0x1100, 0x115f], [0x2010, 0x2010], + [0x2013, 0x2016], [0x2018, 0x2019], [0x201c, 0x201d], + [0x2020, 0x2022], [0x2024, 0x2027], [0x2030, 0x2030], + [0x2032, 0x2033], [0x2035, 0x2035], [0x203b, 0x203b], + [0x203e, 0x203e], [0x2074, 0x2074], [0x207f, 0x207f], + [0x2081, 0x2084], [0x20ac, 0x20ac], [0x2103, 0x2103], + [0x2105, 0x2105], [0x2109, 0x2109], [0x2113, 0x2113], + [0x2116, 0x2116], [0x2121, 0x2122], [0x2126, 0x2126], + [0x212b, 0x212b], [0x2153, 0x2154], [0x215b, 0x215e], + [0x2160, 0x216b], [0x2170, 0x2179], [0x2189, 0x2189], + [0x2190, 0x2199], [0x21b8, 0x21b9], [0x21d2, 0x21d2], + [0x21d4, 0x21d4], [0x21e7, 0x21e7], [0x2200, 0x2200], + [0x2202, 0x2203], [0x2207, 0x2208], [0x220b, 0x220b], + [0x220f, 0x220f], [0x2211, 0x2211], [0x2215, 0x2215], + [0x221a, 0x221a], [0x221d, 0x2220], [0x2223, 0x2223], + [0x2225, 0x2225], [0x2227, 0x222c], [0x222e, 0x222e], + [0x2234, 0x2237], [0x223c, 0x223d], [0x2248, 0x2248], + [0x224c, 0x224c], [0x2252, 0x2252], [0x2260, 0x2261], + [0x2264, 0x2267], [0x226a, 0x226b], [0x226e, 0x226f], + [0x2282, 0x2283], [0x2286, 0x2287], [0x2295, 0x2295], + [0x2299, 0x2299], [0x22a5, 0x22a5], [0x22bf, 0x22bf], + [0x2312, 0x2312], [0x231a, 0x231b], [0x2329, 0x232a], + [0x23e9, 0x23ec], [0x23f0, 0x23f0], [0x23f3, 0x23f3], + [0x2460, 0x24e9], [0x24eb, 0x254b], [0x2550, 0x2573], + [0x2580, 0x258f], [0x2592, 0x2595], [0x25a0, 0x25a1], + [0x25a3, 0x25a9], [0x25b2, 0x25b3], [0x25b6, 0x25b7], + [0x25bc, 0x25bd], [0x25c0, 0x25c1], [0x25c6, 0x25c8], + [0x25cb, 0x25cb], [0x25ce, 0x25d1], [0x25e2, 0x25e5], + [0x25ef, 0x25ef], [0x25fd, 0x25fe], [0x2605, 0x2606], + [0x2609, 0x2609], [0x260e, 0x260f], [0x2614, 0x2615], + [0x261c, 0x261c], [0x261e, 0x261e], [0x2640, 0x2640], + [0x2642, 0x2642], [0x2648, 0x2653], [0x2660, 0x2661], + [0x2663, 0x2665], [0x2667, 0x266a], [0x266c, 0x266d], + [0x266f, 0x266f], [0x267f, 0x267f], [0x2693, 0x2693], + [0x269e, 0x269f], [0x26a1, 0x26a1], [0x26aa, 0x26ab], + [0x26bd, 0x26bf], [0x26c4, 0x26e1], [0x26e3, 0x26e3], + [0x26e8, 0x26ff], [0x2705, 0x2705], [0x270a, 0x270b], + [0x2728, 0x2728], [0x273d, 0x273d], [0x274c, 0x274c], + [0x274e, 0x274e], [0x2753, 0x2755], [0x2757, 0x2757], + [0x2776, 0x277f], [0x2795, 0x2797], [0x27b0, 0x27b0], + [0x27bf, 0x27bf], [0x2b1b, 0x2b1c], [0x2b50, 0x2b50], + [0x2b55, 0x2b59], [0x2e80, 0x2fdf], [0x2ff0, 0x303e], + [0x3040, 0x4dbf], [0x4e00, 0xa4cf], [0xa960, 0xa97f], + [0xac00, 0xd7a3], [0xe000, 0xfaff], [0xfe00, 0xfe19], + [0xfe30, 0xfe6f], [0xff01, 0xff60], [0xffe0, 0xffe6], + [0xfffd, 0xfffd], [0x16fe0, 0x16fe1], [0x17000, 0x18aff], + [0x1b000, 0x1b12f], [0x1b170, 0x1b2ff], [0x1f004, 0x1f004], + [0x1f0cf, 0x1f0cf], [0x1f100, 0x1f10a], [0x1f110, 0x1f12d], + [0x1f130, 0x1f169], [0x1f170, 0x1f1ac], [0x1f200, 0x1f202], + [0x1f210, 0x1f23b], [0x1f240, 0x1f248], [0x1f250, 0x1f251], + [0x1f260, 0x1f265], [0x1f300, 0x1f320], [0x1f32d, 0x1f335], + [0x1f337, 0x1f37c], [0x1f37e, 0x1f393], [0x1f3a0, 0x1f3ca], + [0x1f3cf, 0x1f3d3], [0x1f3e0, 0x1f3f0], [0x1f3f4, 0x1f3f4], + [0x1f3f8, 0x1f43e], [0x1f440, 0x1f440], [0x1f442, 0x1f4fc], + [0x1f4ff, 0x1f53d], [0x1f54b, 0x1f54e], [0x1f550, 0x1f567], + [0x1f57a, 0x1f57a], [0x1f595, 0x1f596], [0x1f5a4, 0x1f5a4], + [0x1f5fb, 0x1f64f], [0x1f680, 0x1f6c5], [0x1f6cc, 0x1f6cc], + [0x1f6d0, 0x1f6d2], [0x1f6eb, 0x1f6ec], [0x1f6f4, 0x1f6f8], + [0x1f910, 0x1f93e], [0x1f940, 0x1f94c], [0x1f950, 0x1f96b], + [0x1f980, 0x1f997], [0x1f9c0, 0x1f9c0], [0x1f9d0, 0x1f9e6], + [0x20000, 0x2fffd], [0x30000, 0x3fffd], [0xe0100, 0xe01ef], + [0xf0000, 0xffffd], [0x100000, 0x10fffd], +]; + +// Sorted list of non-overlapping intervals of East Asian Unambiguous characters +// generated by the `./ranges.py` helper. +lib.wc.unambiguous = [ + [0x1100, 0x115f], [0x231a, 0x231b], [0x2329, 0x232a], + [0x23e9, 0x23ec], [0x23f0, 0x23f0], [0x23f3, 0x23f3], + [0x25fd, 0x25fe], [0x2614, 0x2615], [0x2648, 0x2653], + [0x267f, 0x267f], [0x2693, 0x2693], [0x26a1, 0x26a1], + [0x26aa, 0x26ab], [0x26bd, 0x26be], [0x26c4, 0x26c5], + [0x26ce, 0x26ce], [0x26d4, 0x26d4], [0x26ea, 0x26ea], + [0x26f2, 0x26f3], [0x26f5, 0x26f5], [0x26fa, 0x26fa], + [0x26fd, 0x26fd], [0x2705, 0x2705], [0x270a, 0x270b], + [0x2728, 0x2728], [0x274c, 0x274c], [0x274e, 0x274e], + [0x2753, 0x2755], [0x2757, 0x2757], [0x2795, 0x2797], + [0x27b0, 0x27b0], [0x27bf, 0x27bf], [0x2b1b, 0x2b1c], + [0x2b50, 0x2b50], [0x2b55, 0x2b55], [0x2e80, 0x2fdf], + [0x2ff0, 0x303e], [0x3040, 0x3247], [0x3250, 0x4dbf], + [0x4e00, 0xa4cf], [0xa960, 0xa97f], [0xac00, 0xd7a3], + [0xf900, 0xfaff], [0xfe10, 0xfe19], [0xfe30, 0xfe6f], + [0xff01, 0xff60], [0xffe0, 0xffe6], [0x16fe0, 0x16fe1], + [0x17000, 0x18aff], [0x1b000, 0x1b12f], [0x1b170, 0x1b2ff], + [0x1f004, 0x1f004], [0x1f0cf, 0x1f0cf], [0x1f18e, 0x1f18e], + [0x1f191, 0x1f19a], [0x1f200, 0x1f202], [0x1f210, 0x1f23b], + [0x1f240, 0x1f248], [0x1f250, 0x1f251], [0x1f260, 0x1f265], + [0x1f300, 0x1f320], [0x1f32d, 0x1f335], [0x1f337, 0x1f37c], + [0x1f37e, 0x1f393], [0x1f3a0, 0x1f3ca], [0x1f3cf, 0x1f3d3], + [0x1f3e0, 0x1f3f0], [0x1f3f4, 0x1f3f4], [0x1f3f8, 0x1f43e], + [0x1f440, 0x1f440], [0x1f442, 0x1f4fc], [0x1f4ff, 0x1f53d], + [0x1f54b, 0x1f54e], [0x1f550, 0x1f567], [0x1f57a, 0x1f57a], + [0x1f595, 0x1f596], [0x1f5a4, 0x1f5a4], [0x1f5fb, 0x1f64f], + [0x1f680, 0x1f6c5], [0x1f6cc, 0x1f6cc], [0x1f6d0, 0x1f6d2], + [0x1f6eb, 0x1f6ec], [0x1f6f4, 0x1f6f8], [0x1f910, 0x1f93e], + [0x1f940, 0x1f94c], [0x1f950, 0x1f96b], [0x1f980, 0x1f997], + [0x1f9c0, 0x1f9c0], [0x1f9d0, 0x1f9e6], [0x20000, 0x2fffd], + [0x30000, 0x3fffd], ]; /** - * Binary search to check if the given unicode character is a space character. - * - * @param {interger} ucs A unicode character code. + * Binary search to check if the given unicode character is in the table. * - * @return {boolean} True if the given character is a space character; false - * otherwise. + * @param {integer} ucs A unicode character code. + * @param {Object} table A sorted list of internals to match against. + * @return {boolean} True if the given character is in the table. */ -lib.wc.isSpace = function(ucs) { - // Auxiliary function for binary search in interval table. - var min = 0, max = lib.wc.combining.length - 1; +lib.wc.binaryTableSearch_ = function(ucs, table) { + var min = 0, max = table.length - 1; var mid; - if (ucs < lib.wc.combining[0][0] || ucs > lib.wc.combining[max][1]) + if (ucs < table[min][0] || ucs > table[max][1]) return false; while (max >= min) { mid = Math.floor((min + max) / 2); - if (ucs > lib.wc.combining[mid][1]) { + if (ucs > table[mid][1]) { min = mid + 1; - } else if (ucs < lib.wc.combining[mid][0]) { + } else if (ucs < table[mid][0]) { max = mid - 1; } else { return true; @@ -4697,33 +5091,29 @@ lib.wc.isSpace = function(ucs) { return false; }; +/** + * Binary search to check if the given unicode character is a space character. + * + * @param {integer} ucs A unicode character code. + * + * @return {boolean} True if the given character is a space character; false + * otherwise. + */ +lib.wc.isSpace = function(ucs) { + return lib.wc.binaryTableSearch_(ucs, lib.wc.combining); +}; + /** * Auxiliary function for checking if the given unicode character is a East * Asian Ambiguous character. * - * @param {interger} ucs A unicode character code. + * @param {integer} ucs A unicode character code. * * @return {boolean} True if the given character is a East Asian Ambiguous * character. */ lib.wc.isCjkAmbiguous = function(ucs) { - var min = 0, max = lib.wc.ambiguous.length - 1; - var mid; - - if (ucs < lib.wc.ambiguous[0][0] || ucs > lib.wc.ambiguous[max][1]) - return false; - while (max >= min) { - mid = Math.floor((min + max) / 2); - if (ucs > lib.wc.ambiguous[mid][1]) { - min = mid + 1; - } else if (ucs < lib.wc.ambiguous[mid][0]) { - max = mid - 1; - } else { - return true; - } - } - - return false; + return lib.wc.binaryTableSearch_(ucs, lib.wc.ambiguous); }; /** @@ -4750,35 +5140,26 @@ lib.wc.charWidth = function(ucs) { * @return {integer} The column width of the given character. */ lib.wc.charWidthDisregardAmbiguous = function(ucs) { + // Optimize for ASCII characters. + if (ucs < 0x7f) { + if (ucs >= 0x20) + return 1; + else if (ucs == 0) + return lib.wc.nulWidth; + else /* if (ucs < 0x20) */ + return lib.wc.controlWidth; + } + // Test for 8-bit control characters. - if (ucs === 0) - return lib.wc.nulWidth; - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) + if (ucs < 0xa0) return lib.wc.controlWidth; - // Optimize for ASCII characters. - if (ucs < 0x7f) - return 1; - // Binary search in table of non-spacing characters. if (lib.wc.isSpace(ucs)) return 0; - // If we arrive here, ucs is not a combining or C0/C1 control character. - return 1 + - (ucs >= 0x1100 && - (ucs <= 0x115f || // Hangul Jamo init. consonants - ucs == 0x2329 || ucs == 0x232a || - (ucs >= 0x2e80 && ucs <= 0xa4cf && - ucs != 0x303f) || // CJK ... Yi - (ucs >= 0xac00 && ucs <= 0xd7a3) || // Hangul Syllables - (ucs >= 0xf900 && ucs <= 0xfaff) || // CJK Compatibility Ideographs - (ucs >= 0xfe10 && ucs <= 0xfe19) || // Vertical forms - (ucs >= 0xfe30 && ucs <= 0xfe6f) || // CJK Compatibility Forms - (ucs >= 0xff00 && ucs <= 0xff60) || // Fullwidth Forms - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2fffd) || - (ucs >= 0x30000 && ucs <= 0x3fffd))); + // Binary search in table of wide characters. + return lib.wc.binaryTableSearch_(ucs, lib.wc.unambiguous) ? 2 : 1; }; /** @@ -4806,11 +5187,13 @@ lib.wc.charWidthRegardAmbiguous = function(ucs) { lib.wc.strWidth = function(str) { var width, rv = 0; - for (var i = 0; i < str.length; i++) { - width = lib.wc.charWidth(str.charCodeAt(i)); + for (var i = 0; i < str.length;) { + var codePoint = str.codePointAt(i); + width = lib.wc.charWidth(codePoint); if (width < 0) return -1; rv += width; + i += (codePoint <= 0xffff) ? 1 : 2; } return rv; @@ -4826,20 +5209,33 @@ lib.wc.strWidth = function(str) { * @return {string} The substring. */ lib.wc.substr = function(str, start, opt_width) { - var startIndex, endIndex, width; - - for (startIndex = 0, width = 0; startIndex < str.length; startIndex++) { - width += lib.wc.charWidth(str.charCodeAt(startIndex)); - if (width > start) - break; + var startIndex = 0; + var endIndex, width; + + // Fun edge case: Normally we associate zero width codepoints (like combining + // characters) with the previous codepoint, so we skip any leading ones while + // including trailing ones. However, if there are zero width codepoints at + // the start of the string, and the substring starts at 0, lets include them + // in the result. This also makes for a simple optimization for a common + // request. + if (start) { + for (width = 0; startIndex < str.length;) { + const codePoint = str.codePointAt(startIndex); + width += lib.wc.charWidth(codePoint); + if (width > start) + break; + startIndex += (codePoint <= 0xffff) ? 1 : 2; + } } if (opt_width != undefined) { - for (endIndex = startIndex, width = 0; - endIndex < str.length && width < opt_width; - width += lib.wc.charWidth(str.charCodeAt(endIndex)), endIndex++); - if (width > opt_width) - endIndex--; + for (endIndex = startIndex, width = 0; endIndex < str.length;) { + const codePoint = str.codePointAt(endIndex); + width += lib.wc.charWidth(codePoint); + if (width > opt_width) + break; + endIndex += (codePoint <= 0xffff) ? 1 : 2; + } return str.substring(startIndex, endIndex); } @@ -4859,12 +5255,12 @@ lib.wc.substring = function(str, start, end) { return lib.wc.substr(str, start, end - start); }; lib.resource.add('libdot/changelog/version', 'text/plain', -'1.9' + +'1.19' + '' ); lib.resource.add('libdot/changelog/date', 'text/plain', -'2014-05-27' + +'2017-10-16' + '' ); @@ -4952,10 +5348,7 @@ lib.registerInit('hterm', function(onInit) { } if (!hterm.defaultStorage) { - var ary = navigator.userAgent.match(/\sChrome\/(\d\d)/); - var version = ary ? parseInt(ary[1]) : -1; - if (window.chrome && chrome.storage && chrome.storage.sync && - version > 21) { + if (window.chrome && chrome.storage && chrome.storage.sync) { hterm.defaultStorage = new lib.Storage.Chrome(chrome.storage.sync); } else { hterm.defaultStorage = new lib.Storage.Local(); @@ -4967,7 +5360,7 @@ lib.registerInit('hterm', function(onInit) { var isPackagedApp = false; if (window.chrome && chrome.runtime && chrome.runtime.getManifest) { var manifest = chrome.runtime.getManifest(); - var isPackagedApp = manifest.app && manifest.app.background; + isPackagedApp = manifest.app && manifest.app.background; } if (isPackagedApp) { @@ -5022,28 +5415,66 @@ hterm.copySelectionToClipboard = function(document) { /** * Paste the system clipboard into the element with focus. * + * Note: In Chrome/Firefox app/extension environments, you'll need the + * "clipboardRead" permission. In other environments, this might always + * fail as the browser frequently blocks access for security reasons. + * * @param {HTMLDocument} The document to paste into. + * @return {boolean} True if the paste succeeded. */ hterm.pasteFromClipboard = function(document) { try { - document.execCommand('paste'); + return document.execCommand('paste'); } catch (firefoxException) { - // Ignore this. FF throws an exception if there was an error, even though - // the spec says just return false. + // Ignore this. FF 40 and older would incorrectly throw an exception if + // there was an error instead of returning false. + return false; } }; /** - * Constructor for a hterm.Size record. - * - * Instances of this class have public read/write members for width and height. + * Create a new notification. * - * @param {integer} width The width of this record. - * @param {integer} height The height of this record. + * @param {Object} params Various parameters for the notification. + * @param {string} params.title The title (defaults to the window's title). + * @param {string} params.body The message body (main text). */ -hterm.Size = function(width, height) { - this.width = width; - this.height = height; +hterm.notify = function(params) { + var def = (curr, fallback) => curr !== undefined ? curr : fallback; + if (params === undefined || params === null) + params = {}; + + // Merge the user's choices with the default settings. We don't take it + // directly in case it was stuffed with excess junk. + var options = { + 'body': params.body, + 'icon': def(params.icon, lib.resource.getDataUrl('hterm/images/icon-96')), + } + + var title = def(params.title, window.document.title); + if (!title) + title = 'hterm'; + title = lib.f.replaceVars(hterm.desktopNotificationTitle, {'title': title}); + + var n = new Notification(title, options); + n.onclick = function() { + window.focus(); + this.close(); + }; + return n; +}; + +/** + * Constructor for a hterm.Size record. + * + * Instances of this class have public read/write members for width and height. + * + * @param {integer} width The width of this record. + * @param {integer} height The height of this record. + */ +hterm.Size = function(width, height) { + this.width = width; + this.height = height; }; /** @@ -5081,7 +5512,7 @@ hterm.Size.prototype.setTo = function(that) { * Test if another hterm.Size instance is equal to this one. * * @param {hterm.Size} that The other hterm.Size instance. - * @return {boolen} True if both instances have the same width/height, false + * @return {boolean} True if both instances have the same width/height, false * otherwise. */ hterm.Size.prototype.equals = function(that) { @@ -5103,7 +5534,7 @@ hterm.Size.prototype.toString = function() { * * Instances of this class have public read/write members for row and column. * - * This class includes an 'overflow' bit which is use to indicate that the an + * This class includes an 'overflow' bit which is use to indicate that an * attempt has been made to move the cursor column passed the end of the * screen. When this happens we leave the cursor column set to the last column * of the screen but set the overflow bit. In this state cursor movement @@ -5160,7 +5591,7 @@ hterm.RowCol.prototype.setTo = function(that) { * Test if another hterm.RowCol instance is equal to this one. * * @param {hterm.RowCol} that The other hterm.RowCol instance. - * @return {boolen} True if both instances have the same row/column, false + * @return {boolean} True if both instances have the same row/column, false * otherwise. */ hterm.RowCol.prototype.equals = function(that) { @@ -5218,14 +5649,23 @@ hterm.Frame = function(terminal, url, opt_options) { * Handle messages from the iframe. */ hterm.Frame.prototype.onMessage_ = function(e) { - if (e.data.name != 'ipc-init-ok') { - console.log('Unknown message from frame:', e.data); - return; + switch (e.data.name) { + case 'ipc-init-ok': + // We get this response after we send them ipc-init and they finish. + this.sendTerminalInfo_(); + return; + case 'terminal-info-ok': + // We get this response after we send them terminal-info and they finish. + // Show the finished frame, and then rebind our message handler to the + // callback below. + this.container_.style.display = 'flex'; + this.messageChannel_.port1.onmessage = this.onMessage.bind(this); + this.onLoad(); + return; + default: + console.log('Unknown message from frame:', e.data); + return; } - - this.sendTerminalInfo_(); - this.messageChannel_.port1.onmessage = this.onMessage.bind(this); - this.onLoad(); }; /** @@ -5245,7 +5685,7 @@ hterm.Frame.prototype.onLoad_ = function() { this.messageChannel_.port1.start(); this.iframe_.contentWindow.postMessage( {name: 'ipc-init', argv: [{messagePort: this.messageChannel_.port2}]}, - [this.messageChannel_.port2], this.url); + this.url, [this.messageChannel_.port2]); }; /** @@ -5341,28 +5781,30 @@ hterm.Frame.prototype.show = function() { var container = this.container_ = document.createElement('div'); container.style.cssText = ( 'position: absolute;' + - 'display: -webkit-flex;' + - '-webkit-flex-direction: column;' + + 'display: none;' + + 'flex-direction: column;' + 'top: 10%;' + 'left: 4%;' + 'width: 90%;' + 'height: 80%;' + + 'min-height: 20%;' + + 'max-height: 80%;' + 'box-shadow: 0 0 2px ' + this.terminal_.getForegroundColor() + ';' + 'border: 2px ' + this.terminal_.getForegroundColor() + ' solid;'); - var header = document.createElement('div'); - header.style.cssText = ( - 'display: -webkit-flex;' + - '-webkit-justify-content: flex-end;' + - 'height: ' + headerHeight + ';' + - 'background-color: ' + this.terminal_.getForegroundColor() + ';' + - 'color: ' + this.terminal_.getBackgroundColor() + ';' + - 'font-size: 16px;' + - 'font-family: ' + this.terminal_.getFontFamily()); - container.appendChild(header); - if (false) { - // No use for the close button. + // No use for the close button, so no use for the window header either. + var header = document.createElement('div'); + header.style.cssText = ( + 'display: flex;' + + 'justify-content: flex-end;' + + 'height: ' + headerHeight + ';' + + 'background-color: ' + this.terminal_.getForegroundColor() + ';' + + 'color: ' + this.terminal_.getBackgroundColor() + ';' + + 'font-size: 16px;' + + 'font-family: ' + this.terminal_.getFontFamily()); + container.appendChild(header); + var button = document.createElement('div'); button.setAttribute('role', 'button'); button.style.cssText = ( @@ -5377,8 +5819,8 @@ hterm.Frame.prototype.show = function() { var iframe = this.iframe_ = document.createElement('iframe'); iframe.onload = this.onLoad_.bind(this); iframe.style.cssText = ( - 'display: -webkit-flex;' + - '-webkit-flex: 1;' + + 'display: flex;' + + 'flex: 1;' + 'width: 100%'); iframe.setAttribute('src', this.url); iframe.setAttribute('seamless', true); @@ -5415,7 +5857,7 @@ hterm.Keyboard = function(terminal) { // The event handlers we are interested in, and their bound callbacks, saved // so they can be uninstalled with removeEventListener, when required. this.handlers_ = [ - ['blur', this.onBlur_.bind(this)], + ['focusout', this.onFocusOut_.bind(this)], ['keydown', this.onKeyDown_.bind(this)], ['keypress', this.onKeyPress_.bind(this)], ['keyup', this.onKeyUp_.bind(this)], @@ -5427,6 +5869,8 @@ hterm.Keyboard = function(terminal) { */ this.keyMap = new hterm.Keyboard.KeyMap(this); + this.bindings = new hterm.Keyboard.Bindings(this); + /** * none: Disable any AltGr related munging. * ctrl-alt: Assume Ctrl+Alt means AltGr. @@ -5538,7 +5982,7 @@ hterm.Keyboard = function(terminal) { * that it's impossible to do meta-backspace. If the user enables this pref, * we use a trick to tell a true DEL keypress from alt-backspace: on * alt-backspace, we will see the alt key go down, then get a DEL keystroke - * that indicates that alt is not pressed. See http://crbug.com/174410 . + * that indicates that alt is not pressed. See https://crbug.com/174410 . */ this.altBackspaceIsMetaBackspace = false; @@ -5572,7 +6016,7 @@ hterm.Keyboard.KeyActions = { * Call preventDefault and stopPropagation for this key event and nothing * else. */ - CANCEL: new String('CANCEL'), + CANCEL: lib.f.createEnum('CANCEL'), /** * This performs the default terminal action for the key. If used in the @@ -5598,13 +6042,13 @@ hterm.Keyboard.KeyActions = { * - If meta is down and configured to send an escape, '\x1b' will be sent * before the normal action is performed. */ - DEFAULT: new String('DEFAULT'), + DEFAULT: lib.f.createEnum('DEFAULT'), /** * Causes the terminal to opt out of handling the key event, instead letting * the browser deal with it. */ - PASS: new String('PASS'), + PASS: lib.f.createEnum('PASS'), /** * Insert the first or second character of the keyCap, based on e.shiftKey. @@ -5614,7 +6058,7 @@ hterm.Keyboard.KeyActions = { * It is useful for a modified key action, where it essentially strips the * modifier while preventing the browser from reacting to the key. */ - STRIP: new String('STRIP') + STRIP: lib.f.createEnum('STRIP') }; /** @@ -5669,14 +6113,16 @@ hterm.Keyboard.prototype.uninstallKeyboard = function() { /** * Handle onTextInput events. * - * We're not actually supposed to get these, but we do on the Mac in the case - * where a third party app sends synthetic keystrokes to Chrome. + * These are generated when using IMEs, Virtual Keyboards (VKs), compose keys, + * Unicode input, etc... */ hterm.Keyboard.prototype.onTextInput_ = function(e) { if (!e.data) return; - e.data.split('').forEach(this.terminal.onVTKeystroke.bind(this.terminal)); + // Just pass the generated buffer straight down. No need for us to split it + // up or otherwise parse it ahead of times. + this.terminal.onVTKeystroke(e.data); }; /** @@ -5689,7 +6135,7 @@ hterm.Keyboard.prototype.onKeyPress_ = function(e) { var lowerKey = key.toLowerCase(); if ((e.ctrlKey || e.metaKey) && (lowerKey == 'c' || lowerKey == 'v')) { // On FF the key press (not key down) event gets fired for copy/paste. - // Let it fall through for the default browser behaviour. + // Let it fall through for the default browser behavior. return; } @@ -5718,20 +6164,20 @@ hterm.Keyboard.prototype.onKeyPress_ = function(e) { }; /** - * Prevent default handling for non-shifted event. + * Prevent default handling for non-ctrl-shifted event. * * When combined with Chrome permission 'app.window.fullscreen.overrideEsc', * and called for both key down and key up events, * the ESC key remains usable within fullscreen Chrome app windows. */ -hterm.Keyboard.prototype.preventChromeAppNonShiftDefault_ = function(e) { +hterm.Keyboard.prototype.preventChromeAppNonCtrlShiftDefault_ = function(e) { if (!window.chrome || !window.chrome.app || !window.chrome.app.window) return; - if (!e.shiftKey) + if (!e.ctrlKey || !e.shiftKey) e.preventDefault(); }; -hterm.Keyboard.prototype.onBlur_ = function(e) { +hterm.Keyboard.prototype.onFocusOut_ = function(e) { this.altKeyPressed = 0; }; @@ -5740,7 +6186,7 @@ hterm.Keyboard.prototype.onKeyUp_ = function(e) { this.altKeyPressed = this.altKeyPressed & ~(1 << (e.location - 1)); if (e.keyCode == 27) - this.preventChromeAppNonShiftDefault_(e); + this.preventChromeAppNonCtrlShiftDefault_(e); }; /** @@ -5751,7 +6197,7 @@ hterm.Keyboard.prototype.onKeyDown_ = function(e) { this.altKeyPressed = this.altKeyPressed | (1 << (e.location - 1)); if (e.keyCode == 27) - this.preventChromeAppNonShiftDefault_(e); + this.preventChromeAppNonCtrlShiftDefault_(e); var keyDef = this.keyMap.keyDefs[e.keyCode]; if (!keyDef) { @@ -5781,7 +6227,7 @@ hterm.Keyboard.prototype.onKeyDown_ = function(e) { } // Note that we use the triple-equals ('===') operator to test equality for - // these constants, in order to distingush usage of the constant from usage + // these constants, in order to distinguish usage of the constant from usage // of a literal string that happens to contain the same bytes. var CANCEL = hterm.Keyboard.KeyActions.CANCEL; var DEFAULT = hterm.Keyboard.KeyActions.DEFAULT; @@ -5832,6 +6278,33 @@ hterm.Keyboard.prototype.onKeyDown_ = function(e) { action = getAction('normal'); } + // If e.maskShiftKey was set (during getAction) it means the shift key is + // already accounted for in the action, and we should not act on it any + // further. This is currently only used for Ctrl-Shift-Tab, which should send + // "CSI Z", not "CSI 1 ; 2 Z". + var shift = !e.maskShiftKey && e.shiftKey; + + var keyDown = { + keyCode: e.keyCode, + shift: e.shiftKey, // not `var shift` from above. + ctrl: control, + alt: alt, + meta: meta + }; + + var binding = this.bindings.getBinding(keyDown); + + if (binding) { + // Clear out the modifier bits so we don't try to munge the sequence + // further. + shift = control = alt = meta = false; + resolvedActionType = 'normal'; + action = binding.action; + + if (typeof action == 'function') + action = action.call(this, this.terminal, keyDown); + } + if (alt && this.altSendsWhat == 'browser-key' && action == DEFAULT) { // When altSendsWhat is 'browser-key', we wait for the keypress event. // In keypress, the browser should have set the event.charCode to the @@ -5860,7 +6333,7 @@ hterm.Keyboard.prototype.onKeyDown_ = function(e) { action = action.apply(this.keyMap, [e, keyDef]); if (action == DEFAULT && keyDef.keyCap.length == 2) - action = keyDef.keyCap.substr((e.shiftKey ? 1 : 0), 1); + action = keyDef.keyCap.substr((shift ? 1 : 0), 1); } e.preventDefault(); @@ -5884,33 +6357,22 @@ hterm.Keyboard.prototype.onKeyDown_ = function(e) { meta = false; } - // Maybe strip the shift modifier too, for the same reason as above. - // This is only used for Ctrl-Shift-Tab, which should send "CSI Z", not - // "CSI 1 ; 2 Z". - var shift = !e.maskShiftKey && e.shiftKey; - - if (action.substr(0, 2) == '\x1b[' && (alt || control || shift)) { + if (action.substr(0, 2) == '\x1b[' && (alt || control || shift || meta)) { // The action is an escape sequence that and it was triggered in the // presence of a keyboard modifier, we may need to alter the action to // include the modifier before sending it. - var mod; - - if (shift && !(alt || control)) { - mod = ';2'; - } else if (alt && !(shift || control)) { - mod = ';3'; - } else if (shift && alt && !control) { - mod = ';4'; - } else if (control && !(shift || alt)) { - mod = ';5'; - } else if (shift && control && !alt) { - mod = ';6'; - } else if (alt && control && !shift) { - mod = ';7'; - } else if (shift && alt && control) { - mod = ';8'; - } + // The math is funky but aligns w/xterm. + let imod = 1; + if (shift) + imod += 1; + if (alt) + imod += 2; + if (control) + imod += 4; + if (meta) + imod += 8; + let mod = ';' + imod; if (action.length == 3) { // Some of the CSI sequences have zero parameters unless modified. @@ -5923,7 +6385,7 @@ hterm.Keyboard.prototype.onKeyDown_ = function(e) { } else { if (action === DEFAULT) { - action = keyDef.keyCap.substr((e.shiftKey ? 1 : 0), 1); + action = keyDef.keyCap.substr((shift ? 1 : 0), 1); if (control) { var unshifted = keyDef.keyCap.substr(0, 1); @@ -5950,6 +6412,182 @@ hterm.Keyboard.prototype.onKeyDown_ = function(e) { this.terminal.onVTKeystroke(action); }; +// SOURCE FILE: hterm/js/hterm_keyboard_bindings.js +// Copyright (c) 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +/** + * A mapping from hterm.Keyboard.KeyPattern to an action. + * + * TODO(rginda): For now this bindings code is only used for user overrides. + * hterm.Keyboard.KeyMap still handles all of the built-in key mappings. + * It'd be nice if we migrated that over to be hterm.Keyboard.Bindings based. + */ +hterm.Keyboard.Bindings = function() { + this.bindings_ = {}; +}; + +/** + * Remove all bindings. + */ +hterm.Keyboard.Bindings.prototype.clear = function () { + this.bindings_ = {}; +}; + +/** + * Add a new binding. + * + * Internal API that assumes parsed objects as inputs. + * See the public addBinding for more details. + * + * @param {hterm.Keyboard.KeyPattern} keyPattern + * @param {string|function|hterm.Keyboard.KeyAction} action + */ +hterm.Keyboard.Bindings.prototype.addBinding_ = function(keyPattern, action) { + var binding = null; + var list = this.bindings_[keyPattern.keyCode]; + if (list) { + for (var i = 0; i < list.length; i++) { + if (list[i].keyPattern.matchKeyPattern(keyPattern)) { + binding = list[i]; + break; + } + } + } + + if (binding) { + binding.action = action; + } else { + binding = {keyPattern: keyPattern, action: action}; + + if (!list) { + this.bindings_[keyPattern.keyCode] = [binding]; + } else { + this.bindings_[keyPattern.keyCode].push(binding); + + list.sort(function(a, b) { + return hterm.Keyboard.KeyPattern.sortCompare( + a.keyPattern, b.keyPattern); + }); + } + } +}; + +/** + * Add a new binding. + * + * If a binding for the keyPattern already exists it will be overridden. + * + * More specific keyPatterns take precedence over those with wildcards. Given + * bindings for "Ctrl-A" and "Ctrl-*-A", and a "Ctrl-A" keydown, the "Ctrl-A" + * binding will match even if "Ctrl-*-A" was created last. + * + * If action is a string, it will be passed through hterm.Parser.parseKeyAction. + * + * For example: + * // Will replace Ctrl-P keystrokes with the string "hiya!". + * addBinding('Ctrl-P', "'hiya!'"); + * // Will cancel the keystroke entirely (make it do nothing). + * addBinding('Alt-D', hterm.Keyboard.KeyActions.CANCEL); + * // Will execute the code and return the action. + * addBinding('Ctrl-T', function() { + * console.log('Got a T!'); + * return hterm.Keyboard.KeyActions.PASS; + * }); + * + * @param {string|hterm.Keyboard.KeyPattern} keyPattern + * @param {string|function|hterm.Keyboard.KeyAction} action + */ +hterm.Keyboard.Bindings.prototype.addBinding = function(key, action) { + // If we're given a hterm.Keyboard.KeyPattern object, pass it down. + if (typeof key != 'string') { + this.addBinding_(key, action); + return; + } + + // Here we treat key as a string. + var p = new hterm.Parser(); + + p.reset(key); + var sequence; + + try { + sequence = p.parseKeySequence(); + } catch (ex) { + console.error(ex); + return; + } + + if (!p.isComplete()) { + console.error(p.error('Expected end of sequence: ' + sequence)); + return; + } + + // If action is a string, parse it. Otherwise assume it's callable. + if (typeof action == 'string') { + p.reset(action); + try { + action = p.parseKeyAction(); + } catch (ex) { + console.error(ex); + return; + } + } + + if (!p.isComplete()) { + console.error(p.error('Expected end of sequence: ' + sequence)); + return; + } + + this.addBinding_(new hterm.Keyboard.KeyPattern(sequence), action); +}; + +/** + * Add multiple bindings at a time using a map of {string: string, ...} + * + * This uses hterm.Parser to parse the maps key into KeyPatterns, and the + * map values into {string|function|KeyAction}. + * + * For example: + * { + * // Will replace Ctrl-P keystrokes with the string "hiya!". + * 'Ctrl-P': "'hiya!'", + * // Will cancel the keystroke entirely (make it do nothing). + * 'Alt-D': hterm.Keyboard.KeyActions.CANCEL, + * } + * + * @param {Object} map + */ +hterm.Keyboard.Bindings.prototype.addBindings = function(map) { + for (var key in map) { + this.addBinding(key, map[key]); + } +}; + +/** + * Return the binding that is the best match for the given keyDown record, + * or null if there is no match. + * + * @param {Object} keyDown An object with a keyCode property and zero or + * more boolean properties representing key modifiers. These property names + * must match those defined in hterm.Keyboard.KeyPattern.modifiers. + */ +hterm.Keyboard.Bindings.prototype.getBinding = function(keyDown) { + var list = this.bindings_[keyDown.keyCode]; + if (!list) + return null; + + for (var i = 0; i < list.length; i++) { + var binding = list[i]; + if (binding.keyPattern.matchKeyDown(keyDown)) + return binding; + } + + return null; +}; // SOURCE FILE: hterm/js/hterm_keyboard_keymap.js // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -6027,7 +6665,7 @@ hterm.Keyboard.KeyMap.prototype.addKeyDef = function(keyCode, def) { }; /** - * Add mutiple key definitions in a single call. + * Add multiple key definitions in a single call. * * This function takes the key definitions as variable argument list. Each * argument is the key definition specified as an array. @@ -6051,13 +6689,6 @@ hterm.Keyboard.KeyMap.prototype.addKeyDefs = function(var_args) { } }; -/** - * Inherit from hterm.Keyboard.KeyMap, as defined in keyboard.js. - */ -hterm.Keyboard.KeyMap.prototype = { - __proto__: hterm.Keyboard.KeyMap.prototype -}; - /** * Set up the default state for this keymap. */ @@ -6272,8 +6903,8 @@ hterm.Keyboard.KeyMap.prototype.reset = function() { // Arrow keys. When unmodified they respect the application cursor state, // otherwise they always send the CSI codes. - [38, '[UP]', ac(CSI + 'A', SS3 + 'A'), DEFAULT, DEFAULT, DEFAULT], - [40, '[DOWN]', ac(CSI + 'B', SS3 + 'B'), DEFAULT, DEFAULT, DEFAULT], + [38, '[UP]', c('onKeyArrowUp_'), DEFAULT, DEFAULT, DEFAULT], + [40, '[DOWN]', c('onKeyArrowDown_'), DEFAULT, DEFAULT, DEFAULT], [39, '[RIGHT]', ac(CSI + 'C', SS3 + 'C'), DEFAULT, DEFAULT, DEFAULT], [37, '[LEFT]', ac(CSI + 'D', SS3 + 'D'), DEFAULT, DEFAULT, DEFAULT], @@ -6293,8 +6924,8 @@ hterm.Keyboard.KeyMap.prototype.reset = function() { [103, '[KP7]', DEFAULT, DEFAULT, DEFAULT, DEFAULT], [104, '[KP8]', DEFAULT, DEFAULT, DEFAULT, DEFAULT], [105, '[KP9]', DEFAULT, DEFAULT, DEFAULT, DEFAULT], - [107, '[KP+]', DEFAULT, DEFAULT, DEFAULT, DEFAULT], - [109, '[KP-]', DEFAULT, DEFAULT, DEFAULT, DEFAULT], + [107, '[KP+]', DEFAULT, c('onPlusMinusZero_'), DEFAULT, c('onPlusMinusZero_')], + [109, '[KP-]', DEFAULT, c('onPlusMinusZero_'), DEFAULT, c('onPlusMinusZero_')], [106, '[KP*]', DEFAULT, DEFAULT, DEFAULT, DEFAULT], [111, '[KP/]', DEFAULT, DEFAULT, DEFAULT, DEFAULT], [110, '[KP.]', DEFAULT, DEFAULT, DEFAULT, DEFAULT], @@ -6395,6 +7026,32 @@ hterm.Keyboard.KeyMap.prototype.onKeyPageDown_ = function(e) { return hterm.Keyboard.KeyActions.CANCEL; }; +/** + * Either scroll the scrollback buffer or send a key sequence. + */ +hterm.Keyboard.KeyMap.prototype.onKeyArrowUp_ = function(e) { + if (!this.keyboard.applicationCursor && e.shiftKey) { + this.keyboard.terminal.scrollLineUp(); + return hterm.Keyboard.KeyActions.CANCEL; + } + + return (e.shiftKey || e.ctrlKey || e.altKey || e.metaKey || + !this.keyboard.applicationCursor) ? '\x1b[A' : '\x1bOA'; +}; + +/** + * Either scroll the scrollback buffer or send a key sequence. + */ +hterm.Keyboard.KeyMap.prototype.onKeyArrowDown_ = function(e) { + if (!this.keyboard.applicationCursor && e.shiftKey) { + this.keyboard.terminal.scrollLineDown(); + return hterm.Keyboard.KeyActions.CANCEL; + } + + return (e.shiftKey || e.ctrlKey || e.altKey || e.metaKey || + !this.keyboard.applicationCursor) ? '\x1b[B' : '\x1bOB'; +}; + /** * Clear the primary/alternate screens and the scrollback buffer. */ @@ -6465,8 +7122,6 @@ hterm.Keyboard.KeyMap.prototype.onCtrlC_ = function(e, keyDef) { if (this.keyboard.terminal.clearSelectionAfterCopy) { setTimeout(selection.collapseToEnd.bind(selection), 50); } - if (this.keyboard.terminal.prefs_.get('enable-clipboard-notice')) - setTimeout(this.keyboard.terminal.showOverlay.bind(this.keyboard.terminal, hterm.notifyCopyMessage, 500), 200); return hterm.Keyboard.KeyActions.PASS; } @@ -6501,17 +7156,24 @@ hterm.Keyboard.KeyMap.prototype.onCtrlN_ = function(e, keyDef) { }; /** - * Either send a ^V or allow the browser to interpret the keystroke as a paste - * command. + * Either send a ^V or issue a paste command. * * The default behavior is to paste if the user presses Ctrl-Shift-V, and send * a ^V if the user presses Ctrl-V. This can be flipped with the * 'ctrl-v-paste' preference. + * */ hterm.Keyboard.KeyMap.prototype.onCtrlV_ = function(e, keyDef) { if ((!e.shiftKey && this.keyboard.ctrlVPaste) || (e.shiftKey && !this.keyboard.ctrlVPaste)) { - return hterm.Keyboard.KeyActions.PASS; + // We try to do the pasting ourselves as not all browsers/OSs bind Ctrl-V to + // pasting. Notably, on macOS, Ctrl-V/Ctrl-Shift-V do nothing. + // However, this might run into web restrictions, so if it fails, we still + // fallback to the letting the native behavior (hopefully) save us. + if (this.keyboard.terminal.paste()) + return hterm.Keyboard.KeyActions.CANCEL; + else + return hterm.Keyboard.KeyActions.PASS; } return '\x16'; @@ -6608,7 +7270,7 @@ hterm.Keyboard.KeyMap.prototype.onPlusMinusZero_ = function(e, keyDef) { } else { var size = this.keyboard.terminal.getFontSize(); - if (cap == '-') { + if (cap == '-' || keyDef.keyCap == '[KP-]') { size -= 1; } else { size += 1; @@ -6619,6 +7281,104 @@ hterm.Keyboard.KeyMap.prototype.onPlusMinusZero_ = function(e, keyDef) { return hterm.Keyboard.KeyActions.CANCEL; }; +// SOURCE FILE: hterm/js/hterm_keyboard_keypattern.js +// Copyright (c) 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +/** + * A record of modifier bits and keycode used to define a key binding. + * + * The modifier names are enumerated in the static KeyPattern.modifiers + * property below. Each modifier can be true, false, or "*". True means + * the modifier key must be present, false means it must not, and "*" means + * it doesn't matter. + */ +hterm.Keyboard.KeyPattern = function(spec) { + this.wildcardCount = 0; + this.keyCode = spec.keyCode; + + hterm.Keyboard.KeyPattern.modifiers.forEach(function(mod) { + this[mod] = spec[mod] || false; + if (this[mod] == '*') + this.wildcardCount++; + }.bind(this)); +}; + +/** + * Valid modifier names. + */ +hterm.Keyboard.KeyPattern.modifiers = [ + 'shift', 'ctrl', 'alt', 'meta' +]; + +/** + * A compare callback for Array.prototype.sort(). + * + * The bindings code wants to be sure to search through the strictest key + * patterns first, so that loosely defined patterns have a lower priority than + * exact patterns. + * + * @param {hterm.Keyboard.KeyPattern} a + * @param {hterm.Keyboard.KeyPattern} b + */ +hterm.Keyboard.KeyPattern.sortCompare = function(a, b) { + if (a.wildcardCount < b.wildcardCount) + return -1; + + if (a.wildcardCount > b.wildcardCount) + return 1; + + return 0; +}; + +/** + * Private method used to match this key pattern against other key patterns + * or key down events. + * + * @param {Object} The object to match. + * @param {boolean} True if we should ignore wildcards. Useful when you want + * to perform and exact match against another key pattern. + */ +hterm.Keyboard.KeyPattern.prototype.match_ = function(obj, exactMatch) { + if (this.keyCode != obj.keyCode) + return false; + + var rv = true; + + hterm.Keyboard.KeyPattern.modifiers.forEach(function(mod) { + var modValue = (mod in obj) ? obj[mod] : false; + if (!rv || (!exactMatch && this[mod] == '*') || this[mod] == modValue) + return; + + rv = false; + }.bind(this)); + + return rv; +}; + +/** + * Return true if the given keyDown object is a match for this key pattern. + * + * @param {Object} keyDown An object with a keyCode property and zero or + * more boolean properties representing key modifiers. These property names + * must match those defined in hterm.Keyboard.KeyPattern.modifiers. + */ +hterm.Keyboard.KeyPattern.prototype.matchKeyDown = function(keyDown) { + return this.match_(keyDown, false); +}; + +/** + * Return true if the given hterm.Keyboard.KeyPattern is exactly the same as + * this one. + * + * @param {hterm.Keyboard.KeyPattern} + */ +hterm.Keyboard.KeyPattern.prototype.matchKeyPattern = function(keyPattern) { + return this.match_(keyPattern, true); +}; // SOURCE FILE: hterm/js/hterm_options.js // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -6641,7 +7401,7 @@ hterm.Keyboard.KeyMap.prototype.onPlusMinusZero_ = function(e, keyDef) { * constructor. * * The defaults are as defined in http://www.vt100.net/docs/vt510-rm/DECSTR - * except that we enable autowrap (wraparound) by defaut since that seems to + * except that we enable autowrap (wraparound) by default since that seems to * be what xterm does. * * @param {hterm.Options=} opt_copy Optional instance to copy. @@ -6661,406 +7421,1076 @@ hterm.Options = function(opt_copy) { this.reverseVideo = opt_copy ? opt_copy.reverseVideo : false; this.bracketedPaste = opt_copy ? opt_copy.bracketedPaste : false; }; -// SOURCE FILE: hterm/js/hterm_preference_manager.js -// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +// SOURCE FILE: hterm/js/hterm_parser.js +// Copyright (c) 2015 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. 'use strict'; -lib.rtdep('lib.f', 'lib.Storage'); +lib.rtdep('hterm.Keyboard.KeyActions'); /** - * PreferenceManager subclass managing global NaSSH preferences. - * - * This is currently just an ordered list of known connection profiles. + * @constructor + * Parses the key definition syntax used for user keyboard customizations. */ -hterm.PreferenceManager = function(profileId) { - lib.PreferenceManager.call(this, hterm.defaultStorage, - '/hterm/profiles/' + profileId); - var defs = hterm.PreferenceManager.defaultPreferences; - Object.keys(defs).forEach(function(key) { - this.definePreference(key, defs[key]); - }.bind(this)); -}; - -hterm.PreferenceManager.defaultPreferences = { +hterm.Parser = function() { /** - * Select an AltGr detection hack^Wheuristic. - * - * null: Autodetect based on navigator.language: - * 'en-us' => 'none', else => 'right-alt' - * 'none': Disable any AltGr related munging. - * 'ctrl-alt': Assume Ctrl+Alt means AltGr. - * 'left-alt': Assume left Alt means AltGr. - * 'right-alt': Assume right Alt means AltGr. + * @type {string} The source string. */ - 'alt-gr-mode': null, + this.source = ''; /** - * If set, undoes the Chrome OS Alt-Backspace->DEL remap, so that - * alt-backspace indeed is alt-backspace. + * @type {number} The current position. */ - 'alt-backspace-is-meta-backspace': false, + this.pos = 0; /** - * Set whether the alt key acts as a meta key or as a distinct alt key. + * @type {string?} The character at the current position. */ - 'alt-is-meta': false, + this.ch = null; +}; - /** - * Controls how the alt key is handled. - * - * escape....... Send an ESC prefix. - * 8-bit........ Add 128 to the unshifted character as in xterm. - * browser-key.. Wait for the keypress event and see what the browser says. - * (This won't work well on platforms where the browser - * performs a default action for some alt sequences.) - */ - 'alt-sends-what': 'escape', +hterm.Parser.prototype.error = function(message) { + return new Error('Parse error at ' + this.pos + ': ' + message); +}; - /** - * Terminal bell sound. Empty string for no audible bell. - */ - 'audible-bell-sound': 'lib-resource:hterm/audio/bell', +hterm.Parser.prototype.isComplete = function() { + return this.pos == this.source.length; +}; - /** - * If true, terminal bells in the background will create a Web - * Notification. http://www.w3.org/TR/notifications/ - * - * Displaying notifications requires permission from the user. When this - * option is set to true, hterm will attempt to ask the user for permission - * if necessary. Note browsers may not show this permission request if it - * did not originate from a user action. - * - * Chrome extensions with the "notfications" permission have permission to - * display notifications. - */ - 'desktop-notification-bell': false, +hterm.Parser.prototype.reset = function(source, opt_pos) { + this.source = source; + this.pos = opt_pos || 0; + this.ch = source.substr(0, 1); +}; - /** - * The background color for text with no other color attributes. - */ - 'background-color': 'rgb(16, 16, 16)', +/** + * Parse a key sequence. + * + * A key sequence is zero or more of the key modifiers defined in + * hterm.Parser.identifiers.modifierKeys followed by a key code. Key + * codes can be an integer or an identifier from + * hterm.Parser.identifiers.keyCodes. Modifiers and keyCodes should be joined + * by the dash character. + * + * An asterisk "*" can be used to indicate that the unspecified modifiers + * are optional. + * + * For example: + * A: Matches only an unmodified "A" character. + * 65: Same as above. + * 0x41: Same as above. + * Ctrl-A: Matches only Ctrl-A. + * Ctrl-65: Same as above. + * Ctrl-0x41: Same as above. + * Ctrl-Shift-A: Matches only Ctrl-Shift-A. + * Ctrl-*-A: Matches Ctrl-A, as well as any other key sequence that includes + * at least the Ctrl and A keys. + * + * @return {Object} An object with shift, ctrl, alt, meta, keyCode + * properties. + */ +hterm.Parser.prototype.parseKeySequence = function() { + var rv = { + keyCode: null + }; - /** - * The background image. - */ - 'background-image': '', + for (var k in hterm.Parser.identifiers.modifierKeys) { + rv[hterm.Parser.identifiers.modifierKeys[k]] = false; + } - /** - * The background image size, - * - * Defaults to none. - */ - 'background-size': '', + while (this.pos < this.source.length) { + this.skipSpace(); - /** - * The background image position, - * - * Defaults to none. - */ - 'background-position': '', + var token = this.parseToken(); + if (token.type == 'integer') { + rv.keyCode = token.value; - /** - * If true, the backspace should send BS ('\x08', aka ^H). Otherwise - * the backspace key should send '\x7f'. - */ - 'backspace-sends-backspace': false, + } else if (token.type == 'identifier') { + var ucValue = token.value.toUpperCase(); + if (ucValue in hterm.Parser.identifiers.modifierKeys && + hterm.Parser.identifiers.modifierKeys.hasOwnProperty(ucValue)) { + var mod = hterm.Parser.identifiers.modifierKeys[ucValue]; + if (rv[mod] && rv[mod] != '*') + throw this.error('Duplicate modifier: ' + token.value); + rv[mod] = true; - /** - * Character map overrides. - * - * This is specified as an object. It is a sparse array, where each property - * is the character set code and the value is an object that is a sparse array - * itself. In that sparse array, each property is the received character and - * the value is the displayed character. - * - * For example: - * {"0":{"+":"\u2192",",":"\u2190","-":"\u2191",".":"\u2193","0":"\u2588"}} - */ - 'character-map-overrides': null, + } else if (ucValue in hterm.Parser.identifiers.keyCodes && + hterm.Parser.identifiers.keyCodes.hasOwnProperty(ucValue)) { + rv.keyCode = hterm.Parser.identifiers.keyCodes[ucValue]; - /** - * Whether or not to close the window when the command exits. - */ - 'close-on-exit': true, + } else { + throw this.error('Unknown key: ' + token.value); + } - /** - * Whether or not to blink the cursor by default. - */ - 'cursor-blink': false, + } else if (token.type == 'symbol') { + if (token.value == '*') { + for (var id in hterm.Parser.identifiers.modifierKeys) { + var p = hterm.Parser.identifiers.modifierKeys[id]; + if (!rv[p]) + rv[p] = '*'; + } + } else { + throw this.error('Unexpected symbol: ' + token.value); + } + } else { + throw this.error('Expected integer or identifier'); + } - /** - * The cursor blink rate in milliseconds. - * - * A two element array, the first of which is how long the cursor should be - * on, second is how long it should be off. - */ - 'cursor-blink-cycle': [1000, 500], + this.skipSpace(); - /** - * The color of the visible cursor. - */ - 'cursor-color': 'rgba(255, 0, 0, 0.5)', + if (this.ch != '-') + break; - /** - * Override colors in the default palette. - * - * This can be specified as an array or an object. If specified as an - * object it is assumed to be a sparse array, where each property - * is a numeric index into the color palette. - * - * Values can be specified as css almost any css color value. This - * includes #RGB, #RRGGBB, rgb(...), rgba(...), and any color names - * that are also part of the stock X11 rgb.txt file. - * - * You can use 'null' to specify that the default value should be not - * be changed. This is useful for skipping a small number of indicies - * when the value is specified as an array. - */ - 'color-palette-overrides': null, + if (rv.keyCode != null) + throw this.error('Extra definition after target key'); - /** - * Automatically copy mouse selection to the clipboard. - */ - 'copy-on-select': true, + this.advance(1); + } - /** - * Whether to use the default window copy behaviour. - */ - 'use-default-window-copy': false, + if (rv.keyCode == null) + throw this.error('Missing target key'); - /** - * Whether to clear the selection after copying. - */ - 'clear-selection-after-copy': true, + return rv; +}; - /** - * If true, Ctrl-Plus/Minus/Zero controls zoom. - * If false, Ctrl-Shift-Plus/Minus/Zero controls zoom, Ctrl-Minus sends ^_, - * Ctrl-Plus/Zero do nothing. - */ - 'ctrl-plus-minus-zero-zoom': true, +hterm.Parser.prototype.parseKeyAction = function() { + this.skipSpace(); - /** - * Ctrl+C copies if true, send ^C to host if false. - * Ctrl+Shift+C sends ^C to host if true, copies if false. - */ - 'ctrl-c-copy': false, + var token = this.parseToken(); - /** - * Ctrl+V pastes if true, send ^V to host if false. - * Ctrl+Shift+V sends ^V to host if true, pastes if false. - */ - 'ctrl-v-paste': false, + if (token.type == 'string') + return token.value; - /** - * Set whether East Asian Ambiguous characters have two column width. - */ - 'east-asian-ambiguous-as-two-column': false, + if (token.type == 'identifier') { + if (token.value in hterm.Parser.identifiers.actions && + hterm.Parser.identifiers.actions.hasOwnProperty(token.value)) + return hterm.Parser.identifiers.actions[token.value]; - /** - * True to enable 8-bit control characters, false to ignore them. - * - * We'll respect the two-byte versions of these control characters - * regardless of this setting. - */ - 'enable-8-bit-control': false, + throw this.error('Unknown key action: ' + token.value); + } - /** - * True if we should use bold weight font for text with the bold/bright - * attribute. False to use the normal weight font. Null to autodetect. - */ - 'enable-bold': null, + throw this.error('Expected string or identifier'); - /** - * True if we should use bright colors (8-15 on a 16 color palette) - * for any text with the bold attribute. False otherwise. - */ - 'enable-bold-as-bright': true, +}; - /** - * Allow the host to write directly to the system clipboard. - */ - 'enable-clipboard-notice': true, +hterm.Parser.prototype.peekString = function() { + return this.ch == '\'' || this.ch == '"'; +}; - /** - * Allow the host to write directly to the system clipboard. - */ - 'enable-clipboard-write': true, +hterm.Parser.prototype.peekIdentifier = function() { + return this.ch.match(/[a-z_]/i); +}; - /** - * Respect the host's attempt to change the cursor blink status using - * DEC Private Mode 12. - */ - 'enable-dec12': false, +hterm.Parser.prototype.peekInteger = function() { + return this.ch.match(/[0-9]/); +}; - /** - * The default environment variables. - */ - 'environment': {'TERM': 'xterm-256color'}, +hterm.Parser.prototype.parseToken = function() { + if (this.ch == '*') { + var rv = {type: 'symbol', value: this.ch}; + this.advance(1); + return rv; + } - /** - * Default font family for the terminal text. - */ - 'font-family': ('"DejaVu Sans Mono", "Everson Mono", ' + - 'FreeMono, "Menlo", "Terminal", ' + - 'monospace'), + if (this.peekIdentifier()) + return {type: 'identifier', value: this.parseIdentifier()}; - /** - * The default font size in pixels. - */ - 'font-size': 15, + if (this.peekString()) + return {type: 'string', value: this.parseString()}; - /** - * Anti-aliasing. - */ - 'font-smoothing': 'antialiased', + if (this.peekInteger()) + return {type: 'integer', value: this.parseInteger()}; - /** - * The foreground color for text with no other color attributes. - */ - 'foreground-color': 'rgb(240, 240, 240)', - /** - * If true, home/end will control the terminal scrollbar and shift home/end - * will send the VT keycodes. If false then home/end sends VT codes and - * shift home/end scrolls. - */ - 'home-keys-scroll': false, + throw this.error('Unexpected token'); +}; - /** - * Max length of a DCS, OSC, PM, or APS sequence before we give up and - * ignore the code. - */ - 'max-string-sequence': 100000, +hterm.Parser.prototype.parseIdentifier = function() { + if (!this.peekIdentifier()) + throw this.error('Expected identifier'); - /** - * If true, convert media keys to their Fkey equivalent. If false, let - * Chrome handle the keys. - */ - 'media-keys-are-fkeys': false, + return this.parsePattern(/[a-z0-9_]+/ig); +}; - /** - * Set whether the meta key sends a leading escape or not. - */ - 'meta-sends-escape': true, +hterm.Parser.prototype.parseInteger = function() { + var base = 10; - /** - * Mouse paste button, or null to autodetect. - * - * For autodetect, we'll try to enable middle button paste for non-X11 - * platforms. - * - * On X11 we move it to button 3, but that'll probably be a context menu - * in the future. - */ - 'mouse-paste-button': null, + if (this.ch == '0' && this.pos < this.source.length - 1 && + this.source.substr(this.pos + 1, 1) == 'x') { + return parseInt(this.parsePattern(/0x[0-9a-f]+/gi)); + } - /** - * If true, page up/down will control the terminal scrollbar and shift - * page up/down will send the VT keycodes. If false then page up/down - * sends VT codes and shift page up/down scrolls. - */ - 'page-keys-scroll': false, + return parseInt(this.parsePattern(/\d+/g)); +}; - /** - * Set whether we should pass Alt-1..9 to the browser. - * - * This is handy when running hterm in a browser tab, so that you don't lose - * Chrome's "switch to tab" keyboard accelerators. When not running in a - * tab it's better to send these keys to the host so they can be used in - * vim or emacs. - * - * If true, Alt-1..9 will be handled by the browser. If false, Alt-1..9 - * will be sent to the host. If null, autodetect based on browser platform - * and window type. - */ - 'pass-alt-number': null, +/** + * Parse a single or double quoted string. + * + * The current position should point at the initial quote character. Single + * quoted strings will be treated literally, double quoted will process escapes. + * + * TODO(rginda): Variable interpolation. + * + * @param {ParseState} parseState + * @param {string} quote A single or double-quote character. + * @return {string} + */ +hterm.Parser.prototype.parseString = function() { + var result = ''; - /** - * Set whether we should pass Ctrl-1..9 to the browser. - * - * This is handy when running hterm in a browser tab, so that you don't lose - * Chrome's "switch to tab" keyboard accelerators. When not running in a - * tab it's better to send these keys to the host so they can be used in - * vim or emacs. - * - * If true, Ctrl-1..9 will be handled by the browser. If false, Ctrl-1..9 - * will be sent to the host. If null, autodetect based on browser platform - * and window type. - */ - 'pass-ctrl-number': null, + var quote = this.ch; + if (quote != '"' && quote != '\'') + throw this.error('String expected'); + + this.advance(1); + + var re = new RegExp('[\\\\' + quote + ']', 'g'); + + while (this.pos < this.source.length) { + re.lastIndex = this.pos; + if (!re.exec(this.source)) + throw this.error('Unterminated string literal'); + + result += this.source.substring(this.pos, re.lastIndex - 1); + + this.advance(re.lastIndex - this.pos - 1); + + if (quote == '"' && this.ch == '\\') { + this.advance(1); + result += this.parseEscape(); + continue; + } + + if (quote == '\'' && this.ch == '\\') { + result += this.ch; + this.advance(1); + continue; + } + + if (this.ch == quote) { + this.advance(1); + return result; + } + } + + throw this.error('Unterminated string literal'); +}; + + +/** + * Parse an escape code from the current position (which should point to + * the first character AFTER the leading backslash.) + * + * @return {string} + */ +hterm.Parser.prototype.parseEscape = function() { + var map = { + '"': '"', + '\'': '\'', + '\\': '\\', + 'a': '\x07', + 'b': '\x08', + 'e': '\x1b', + 'f': '\x0c', + 'n': '\x0a', + 'r': '\x0d', + 't': '\x09', + 'v': '\x0b', + 'x': function() { + var value = this.parsePattern(/[a-z0-9]{2}/ig); + return String.fromCharCode(parseInt(value, 16)); + }, + 'u': function() { + var value = this.parsePattern(/[a-z0-9]{4}/ig); + return String.fromCharCode(parseInt(value, 16)); + } + }; + + if (!(this.ch in map && map.hasOwnProperty(this.ch))) + throw this.error('Unknown escape: ' + this.ch); + + var value = map[this.ch]; + this.advance(1); + + if (typeof value == 'function') + value = value.call(this); + + return value; +}; + +/** + * Parse the given pattern starting from the current position. + * + * @param {RegExp} pattern A pattern representing the characters to span. MUST + * include the "global" RegExp flag. + * @return {string} + */ +hterm.Parser.prototype.parsePattern = function(pattern) { + if (!pattern.global) + throw this.error('Internal error: Span patterns must be global'); + + pattern.lastIndex = this.pos; + var ary = pattern.exec(this.source); + if (!ary || pattern.lastIndex - ary[0].length != this.pos) + throw this.error('Expected match for: ' + pattern); + + this.pos = pattern.lastIndex - 1; + this.advance(1); + + return ary[0]; +}; + + +/** + * Advance the current position. + * + * @param {number} count + */ +hterm.Parser.prototype.advance = function(count) { + this.pos += count; + this.ch = this.source.substr(this.pos, 1); +}; + +/** + * @param {string=} opt_expect A list of valid non-whitespace characters to + * terminate on. + * @return {void} + */ +hterm.Parser.prototype.skipSpace = function(opt_expect) { + if (!/\s/.test(this.ch)) + return; + + var re = /\s+/gm; + re.lastIndex = this.pos; + + var source = this.source; + if (re.exec(source)) + this.pos = re.lastIndex; + + this.ch = this.source.substr(this.pos, 1); + + if (opt_expect) { + if (this.ch.indexOf(opt_expect) == -1) { + throw this.error('Expected one of ' + opt_expect + ', found: ' + + this.ch); + } + } +}; +// SOURCE FILE: hterm/js/hterm_parser_identifiers.js +// Copyright (c) 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +/** + * Collections of identifier for hterm.Parser. + */ +hterm.Parser.identifiers = {}; + +/** + * Modifier key names used when defining key sequences. + * + * These are upper case so we can normalize the user input and be forgiving. + * "CTRL-A" and "Ctrl-A" and "ctrl-a" are all accepted. + * + * Note: Names here cannot overlap with hterm.Parser.identifiers.keyCodes. + */ +hterm.Parser.identifiers.modifierKeys = { + SHIFT: 'shift', + CTRL: 'ctrl', + // Common alias. + CONTROL: 'ctrl', + ALT: 'alt', + META: 'meta' +}; + +/** + * Key codes useful when defining key sequences. + * + * Punctuation is mostly left out of this list because they can move around + * based on keyboard locale and browser. + * + * In a key sequence like "Ctrl-ESC", the ESC comes from this list of + * identifiers. It is equivalent to "Ctrl-27" and "Ctrl-0x1b". + * + * These are upper case so we can normalize the user input and be forgiving. + * "Ctrl-ESC" and "Ctrl-Esc" an "Ctrl-esc" are all accepted. + * + * We also include common aliases for the same key. "Esc" and "Escape" are the + * same key. + * + * Note: Names here cannot overlap with hterm.Parser.identifiers.modifierKeys. + */ +hterm.Parser.identifiers.keyCodes = { + // Top row. + ESCAPE: 27, + ESC: 27, + F1: 112, + F2: 113, + F3: 114, + F4: 115, + F5: 116, + F6: 117, + F7: 118, + F8: 119, + F9: 120, + F10: 121, + F11: 122, + F12: 123, + + // Row two. + ONE: 49, + TWO: 50, + THREE: 51, + FOUR: 52, + FIVE: 53, + SIX: 54, + SEVEN: 55, + EIGHT: 56, + NINE: 57, + ZERO: 48, + BACKSPACE: 8, + BKSP: 8, + BS: 8, + + // Row three. + TAB: 9, + Q: 81, + W: 87, + E: 69, + R: 82, + T: 84, + Y: 89, + U: 85, + I: 73, + O: 79, + P: 80, + + // Row four. + CAPS_LOCK: 20, + CAPSLOCK: 20, + CAPS: 20, + A: 65, + S: 83, + D: 68, + F: 70, + G: 71, + H: 72, + J: 74, + K: 75, + L: 76, + // We map enter and return together even though enter should really be 10 + // because most people don't know or care about the history here. Plus, + // most keyboards/programs map them together already. If they really want + // to bind them differently, they can also use the numeric value. + ENTER: 13, + ENT: 13, + RETURN: 13, + RET: 13, + + // Row five. + Z: 90, + X: 88, + C: 67, + V: 86, + B: 66, + N: 78, + M: 77, + + // Etc. + SPACE: 32, + SP: 32, + PRINT_SCREEN: 42, + PRTSC: 42, + SCROLL_LOCK: 145, + SCRLK: 145, + BREAK: 19, + BRK: 19, + INSERT: 45, + INS: 45, + HOME: 36, + PAGE_UP: 33, + PGUP: 33, + DELETE: 46, + DEL: 46, + END: 35, + PAGE_DOWN: 34, + PGDOWN: 34, + PGDN: 34, + UP: 38, + DOWN: 40, + RIGHT: 39, + LEFT: 37, + NUMLOCK: 144, + + // Keypad + KP0: 96, + KP1: 97, + KP2: 98, + KP3: 99, + KP4: 100, + KP5: 101, + KP6: 102, + KP7: 103, + KP8: 104, + KP9: 105, + KP_PLUS: 107, + KP_ADD: 107, + KP_MINUS: 109, + KP_SUBTRACT: 109, + KP_STAR: 106, + KP_MULTIPLY: 106, + KP_DIVIDE: 111, + KP_DECIMAL: 110, + KP_PERIOD: 110, + + // Chrome OS media keys + NAVIGATE_BACK: 166, + NAVIGATE_FORWARD: 167, + RELOAD: 168, + FULL_SCREEN: 183, + WINDOW_OVERVIEW: 182, + BRIGHTNESS_UP: 216, + BRIGHTNESS_DOWN: 217 +}; + +/** + * Identifiers for use in key actions. + */ +hterm.Parser.identifiers.actions = { /** - * Set whether we should pass Meta-1..9 to the browser. - * - * This is handy when running hterm in a browser tab, so that you don't lose - * Chrome's "switch to tab" keyboard accelerators. When not running in a - * tab it's better to send these keys to the host so they can be used in - * vim or emacs. - * - * If true, Meta-1..9 will be handled by the browser. If false, Meta-1..9 - * will be sent to the host. If null, autodetect based on browser platform - * and window type. + * Prevent the browser and operating system from handling the event. */ - 'pass-meta-number': null, + CANCEL: hterm.Keyboard.KeyActions.CANCEL, /** - * Set whether meta-V gets passed to host. + * Wait for a "keypress" event, send the keypress charCode to the host. */ - 'pass-meta-v': true, + DEFAULT: hterm.Keyboard.KeyActions.DEFAULT, /** - * Set the expected encoding for data received from the host. - * - * Valid values are 'utf-8' and 'raw'. + * Let the browser or operating system handle the key. */ - 'receive-encoding': 'utf-8', + PASS: hterm.Keyboard.KeyActions.PASS, /** - * If true, scroll to the bottom on any keystroke. + * Scroll the terminal one page up. */ - 'scroll-on-keystroke': true, + scrollPageUp: function(terminal) { + terminal.scrollPageUp(); + return hterm.Keyboard.KeyActions.CANCEL; + }, /** - * If true, scroll to the bottom on terminal output. + * Scroll the terminal one page down. */ - 'scroll-on-output': false, + scrollPageDown: function(terminal) { + terminal.scrollPageDown(); + return hterm.Keyboard.KeyActions.CANCEL; + }, /** - * The vertical scrollbar mode. + * Scroll the terminal to the top. */ - 'scrollbar-visible': true, + scrollToTop: function(terminal) { + terminal.scrollEnd(); + return hterm.Keyboard.KeyActions.CANCEL; + }, /** - * The multiplier for the pixel delta in mousewheel event caused by the scroll - * wheel. Alters how fast the page scrolls. + * Scroll the terminal to the bottom. */ - 'scroll-wheel-move-multiplier': 1, + scrollToBottom: function(terminal) { + terminal.scrollEnd(); + return hterm.Keyboard.KeyActions.CANCEL; + }, /** - * Set the encoding for data sent to host. - * - * Valid values are 'utf-8' and 'raw'. + * Clear the terminal and scrollback buffer. */ - 'send-encoding': 'utf-8', + clearScrollback: function(terminal) { + terminal.wipeContents(); + return hterm.Keyboard.KeyActions.CANCEL; + } +}; +// SOURCE FILE: hterm/js/hterm_preference_manager.js +// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +lib.rtdep('lib.f', 'lib.Storage'); + +/** + * PreferenceManager subclass managing global NaSSH preferences. + * + * This is currently just an ordered list of known connection profiles. + */ +hterm.PreferenceManager = function(profileId) { + lib.PreferenceManager.call(this, hterm.defaultStorage, + '/hterm/profiles/' + profileId); + var defs = hterm.PreferenceManager.defaultPreferences; + Object.keys(defs).forEach(function(key) { + this.definePreference(key, defs[key][1]); + }.bind(this)); +}; - /** - * Shift + Insert pastes if true, sent to host if false. - */ - 'shift-insert-paste': true, +hterm.PreferenceManager.categories = {}; +hterm.PreferenceManager.categories.Keyboard = 'Keyboard'; +hterm.PreferenceManager.categories.Appearance = 'Appearance'; +hterm.PreferenceManager.categories.CopyPaste = 'CopyPaste'; +hterm.PreferenceManager.categories.Sounds = 'Sounds'; +hterm.PreferenceManager.categories.Scrolling = 'Scrolling'; +hterm.PreferenceManager.categories.Encoding = 'Encoding'; +hterm.PreferenceManager.categories.Miscellaneous = 'Miscellaneous'; + +/** + * List of categories, ordered by display order (top to bottom) + */ +hterm.PreferenceManager.categoryDefinitions = [ + { id: hterm.PreferenceManager.categories.Appearance, + text: 'Appearance (fonts, colors, images)'}, + { id: hterm.PreferenceManager.categories.CopyPaste, + text: 'Copy & Paste'}, + { id: hterm.PreferenceManager.categories.Encoding, + text: 'Encoding'}, + { id: hterm.PreferenceManager.categories.Keyboard, + text: 'Keyboard'}, + { id: hterm.PreferenceManager.categories.Scrolling, + text: 'Scrolling'}, + { id: hterm.PreferenceManager.categories.Sounds, + text: 'Sounds'}, + { id: hterm.PreferenceManager.categories.Miscellaneous, + text: 'Misc.'} +]; - /** - * User stylesheet to include in the terminal document. - */ - 'user-css': '' -}; -hterm.PreferenceManager.prototype = { - __proto__: lib.PreferenceManager.prototype -}; +hterm.PreferenceManager.defaultPreferences = { + 'alt-gr-mode': + [hterm.PreferenceManager.categories.Keyboard, null, + [null, 'none', 'ctrl-alt', 'left-alt', 'right-alt'], + 'Select an AltGr detection hack^Wheuristic.\n' + + '\n' + + '\'null\': Autodetect based on navigator.language:\n' + + ' \'en-us\' => \'none\', else => \'right-alt\'\n' + + '\'none\': Disable any AltGr related munging.\n' + + '\'ctrl-alt\': Assume Ctrl+Alt means AltGr.\n' + + '\'left-alt\': Assume left Alt means AltGr.\n' + + '\'right-alt\': Assume right Alt means AltGr.\n'], + + 'alt-backspace-is-meta-backspace': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'If set, undoes the Chrome OS Alt-Backspace->DEL remap, so that ' + + 'alt-backspace indeed is alt-backspace.'], + + 'alt-is-meta': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'Set whether the alt key acts as a meta key or as a distinct alt key.'], + + 'alt-sends-what': + [hterm.PreferenceManager.categories.Keyboard, 'escape', + ['escape', '8-bit', 'browser-key'], + 'Controls how the alt key is handled.\n' + + '\n' + + ' escape....... Send an ESC prefix.\n' + + ' 8-bit........ Add 128 to the unshifted character as in xterm.\n' + + ' browser-key.. Wait for the keypress event and see what the browser \n' + + ' says. (This won\'t work well on platforms where the \n' + + ' browser performs a default action for some alt sequences.)' + ], + + 'audible-bell-sound': + [hterm.PreferenceManager.categories.Sounds, 'lib-resource:hterm/audio/bell', + 'url', + 'URL of the terminal bell sound. Empty string for no audible bell.'], + + 'desktop-notification-bell': + [hterm.PreferenceManager.categories.Sounds, false, 'bool', + 'If true, terminal bells in the background will create a Web ' + + 'Notification. https://www.w3.org/TR/notifications/\n' + + '\n'+ + 'Displaying notifications requires permission from the user. When this ' + + 'option is set to true, hterm will attempt to ask the user for permission ' + + 'if necessary. Note browsers may not show this permission request if it ' + + 'did not originate from a user action.\n' + + '\n' + + 'Chrome extensions with the "notifications" permission have permission to ' + + 'display notifications.'], + + 'background-color': + [hterm.PreferenceManager.categories.Appearance, 'rgb(16, 16, 16)', 'color', + 'The background color for text with no other color attributes.'], + + 'background-image': + [hterm.PreferenceManager.categories.Appearance, '', 'string', + 'CSS value of the background image. Empty string for no image.\n' + + '\n' + + 'For example:\n' + + ' url(https://goo.gl/anedTK)\n' + + ' linear-gradient(top bottom, blue, red)'], + + 'background-size': + [hterm.PreferenceManager.categories.Appearance, '', 'string', + 'CSS value of the background image size. Defaults to none.'], + + 'background-position': + [hterm.PreferenceManager.categories.Appearance, '', 'string', + 'CSS value of the background image position.\n' + + '\n' + + 'For example:\n' + + ' 10% 10%\n' + + ' center'], + + 'backspace-sends-backspace': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'If true, the backspace should send BS (\'\\x08\', aka ^H). Otherwise ' + + 'the backspace key should send \'\\x7f\'.'], + + 'character-map-overrides': + [hterm.PreferenceManager.categories.Appearance, null, 'value', + 'This is specified as an object. It is a sparse array, where each ' + + 'property is the character set code and the value is an object that is ' + + 'a sparse array itself. In that sparse array, each property is the ' + + 'received character and the value is the displayed character.\n' + + '\n' + + 'For example:\n' + + ' {"0":{"+":"\\u2192",",":"\\u2190","-":"\\u2191",".":"\\u2193", ' + + '"0":"\\u2588"}}' + ], + + 'close-on-exit': + [hterm.PreferenceManager.categories.Miscellaneous, true, 'bool', + 'Whether or not to close the window when the command exits.'], + + 'cursor-blink': + [hterm.PreferenceManager.categories.Appearance, false, 'bool', + 'Whether or not to blink the cursor by default.'], + + 'cursor-blink-cycle': + [hterm.PreferenceManager.categories.Appearance, [1000, 500], 'value', + 'The cursor blink rate in milliseconds.\n' + + '\n' + + 'A two element array, the first of which is how long the cursor should be ' + + 'on, second is how long it should be off.'], + + 'cursor-color': + [hterm.PreferenceManager.categories.Appearance, 'rgba(255, 0, 0, 0.5)', + 'color', + 'The color of the visible cursor.'], + + 'color-palette-overrides': + [hterm.PreferenceManager.categories.Appearance, null, 'value', + 'Override colors in the default palette.\n' + + '\n' + + 'This can be specified as an array or an object. If specified as an ' + + 'object it is assumed to be a sparse array, where each property ' + + 'is a numeric index into the color palette.\n' + + '\n' + + 'Values can be specified as almost any css color value. This ' + + 'includes #RGB, #RRGGBB, rgb(...), rgba(...), and any color names ' + + 'that are also part of the stock X11 rgb.txt file.\n' + + '\n' + + 'You can use \'null\' to specify that the default value should be not ' + + 'be changed. This is useful for skipping a small number of indices ' + + 'when the value is specified as an array.'], + + 'copy-on-select': + [hterm.PreferenceManager.categories.CopyPaste, true, 'bool', + 'Automatically copy mouse selection to the clipboard.'], + + 'use-default-window-copy': + [hterm.PreferenceManager.categories.CopyPaste, false, 'bool', + 'Whether to use the default window copy behavior'], + + 'clear-selection-after-copy': + [hterm.PreferenceManager.categories.CopyPaste, true, 'bool', + 'Whether to clear the selection after copying.'], + + 'ctrl-plus-minus-zero-zoom': + [hterm.PreferenceManager.categories.Keyboard, true, 'bool', + 'If true, Ctrl-Plus/Minus/Zero controls zoom.\n' + + 'If false, Ctrl-Shift-Plus/Minus/Zero controls zoom, Ctrl-Minus sends ^_, ' + + 'Ctrl-Plus/Zero do nothing.'], + + 'ctrl-c-copy': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'Ctrl+C copies if true, send ^C to host if false.\n' + + 'Ctrl+Shift+C sends ^C to host if true, copies if false.'], + + 'ctrl-v-paste': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'Ctrl+V pastes if true, send ^V to host if false.\n' + + 'Ctrl+Shift+V sends ^V to host if true, pastes if false.'], + + 'east-asian-ambiguous-as-two-column': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'Set whether East Asian Ambiguous characters have two column width.'], + + 'enable-8-bit-control': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'True to enable 8-bit control characters, false to ignore them.\n' + + '\n' + + 'We\'ll respect the two-byte versions of these control characters ' + + 'regardless of this setting.'], + + 'enable-bold': + [hterm.PreferenceManager.categories.Appearance, null, 'tristate', + 'True if we should use bold weight font for text with the bold/bright ' + + 'attribute. False to use the normal weight font. Null to autodetect.'], + + 'enable-bold-as-bright': + [hterm.PreferenceManager.categories.Appearance, true, 'bool', + 'True if we should use bright colors (8-15 on a 16 color palette) ' + + 'for any text with the bold attribute. False otherwise.'], + + 'enable-blink': + [hterm.PreferenceManager.categories.Appearance, true, 'bool', + 'True if we should respect the blink attribute. False to ignore it. '], + + 'enable-clipboard-notice': + [hterm.PreferenceManager.categories.CopyPaste, true, 'bool', + 'Show a message in the terminal when the host writes to the clipboard.'], + + 'enable-clipboard-write': + [hterm.PreferenceManager.categories.CopyPaste, true, 'bool', + 'Allow the host to write directly to the system clipboard.'], + + 'enable-dec12': + [hterm.PreferenceManager.categories.Miscellaneous, false, 'bool', + 'Respect the host\'s attempt to change the cursor blink status using ' + + 'DEC Private Mode 12.'], + + 'environment': + [hterm.PreferenceManager.categories.Miscellaneous, {'TERM': 'xterm-256color'}, + 'value', + 'The default environment variables, as an object.'], + + 'font-family': + [hterm.PreferenceManager.categories.Appearance, + '"DejaVu Sans Mono", "Everson Mono", FreeMono, "Menlo", "Terminal", ' + + 'monospace', 'string', + 'Default font family for the terminal text.'], + + 'font-size': + [hterm.PreferenceManager.categories.Appearance, 15, 'int', + 'The default font size in pixels.'], + + 'font-smoothing': + [hterm.PreferenceManager.categories.Appearance, 'antialiased', 'string', + 'CSS font-smoothing property.'], + + 'foreground-color': + [hterm.PreferenceManager.categories.Appearance, 'rgb(240, 240, 240)', 'color', + 'The foreground color for text with no other color attributes.'], + + 'home-keys-scroll': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'If true, home/end will control the terminal scrollbar and shift home/end ' + + 'will send the VT keycodes. If false then home/end sends VT codes and ' + + 'shift home/end scrolls.'], + + 'keybindings': + [hterm.PreferenceManager.categories.Keyboard, null, 'value', + 'A map of key sequence to key actions. Key sequences include zero or ' + + 'more modifier keys followed by a key code. Key codes can be decimal or ' + + 'hexadecimal numbers, or a key identifier. Key actions can be specified ' + + 'a string to send to the host, or an action identifier. For a full ' + + 'explanation of the format, see https://goo.gl/LWRndr.\n' + + '\n' + + 'Sample keybindings:\n' + + '{\n' + + ' "Ctrl-Alt-K": "clearScrollback",\n' + + ' "Ctrl-Shift-L": "PASS",\n' + + ' "Ctrl-H": "\'HELLO\\n\'"\n' + + '}'], + + 'max-string-sequence': + [hterm.PreferenceManager.categories.Encoding, 100000, 'int', + 'Max length of a DCS, OSC, PM, or APS sequence before we give up and ' + + 'ignore the code.'], + + 'media-keys-are-fkeys': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'If true, convert media keys to their Fkey equivalent. If false, let ' + + 'the browser handle the keys.'], + + 'meta-sends-escape': + [hterm.PreferenceManager.categories.Keyboard, true, 'bool', + 'Set whether the meta key sends a leading escape or not.'], + + 'mouse-right-click-paste': + [hterm.PreferenceManager.categories.CopyPaste, true, 'bool', + 'Paste on right mouse button clicks.\n' + + '\n' + + 'This option is activate independent of the "mouse-paste-button" ' + + 'setting.\n' + + '\n' + + 'Note: This will handle left & right handed mice correctly.'], + + 'mouse-paste-button': + [hterm.PreferenceManager.categories.CopyPaste, null, + [null, 0, 1, 2, 3, 4, 5, 6], + 'Mouse paste button, or null to autodetect.\n' + + '\n' + + 'For autodetect, we\'ll use the middle mouse button for non-X11 ' + + 'platforms (including Chrome OS). On X11, we\'ll use the right mouse ' + + 'button (since the native window manager should paste via the middle ' + + 'mouse button).\n' + + '\n' + + '0 == left (primary) button.\n' + + '1 == middle (auxiliary) button.\n' + + '2 == right (secondary) button.\n' + + '\n' + + 'This option is activate independent of the "mouse-right-click-paste" ' + + 'setting.\n' + + '\n' + + 'Note: This will handle left & right handed mice correctly.'], + + 'word-break-match-left': + [hterm.PreferenceManager.categories.CopyPaste, + '[^\\s\\[\\](){}<>"\'\\^!@#$%&*,;:`]', 'string', + 'Regular expression to halt matching to the left (start) of a selection.\n' + + '\n' + + 'Normally this is a character class to reject specific characters.\n' + + 'We allow "~" and "." by default as paths frequently start with those.'], + + 'word-break-match-right': + [hterm.PreferenceManager.categories.CopyPaste, + '[^\\s\\[\\](){}<>"\'\\^!@#$%&*,;:~.`]', 'string', + 'Regular expression to halt matching to the right (end) of a selection.\n' + + '\n' + + 'Normally this is a character class to reject specific characters.'], + + 'word-break-match-middle': + [hterm.PreferenceManager.categories.CopyPaste, + '[^\\s\\[\\](){}<>"\'\\^]*', 'string', + 'Regular expression to match all the characters in the middle.\n' + + '\n' + + 'Normally this is a character class to reject specific characters.\n' + + '\n' + + 'Used to expand the selection surrounding the starting point.'], + + 'page-keys-scroll': + [hterm.PreferenceManager.categories.Keyboard, false, 'bool', + 'If true, page up/down will control the terminal scrollbar and shift ' + + 'page up/down will send the VT keycodes. If false then page up/down ' + + 'sends VT codes and shift page up/down scrolls.'], + + 'pass-alt-number': + [hterm.PreferenceManager.categories.Keyboard, null, 'tristate', + 'Set whether we should pass Alt-1..9 to the browser.\n' + + '\n' + + 'This is handy when running hterm in a browser tab, so that you don\'t ' + + 'lose Chrome\'s "switch to tab" keyboard accelerators. When not running ' + + 'in a tab it\'s better to send these keys to the host so they can be ' + + 'used in vim or emacs.\n' + + '\n' + + 'If true, Alt-1..9 will be handled by the browser. If false, Alt-1..9 ' + + 'will be sent to the host. If null, autodetect based on browser platform ' + + 'and window type.'], + + 'pass-ctrl-number': + [hterm.PreferenceManager.categories.Keyboard, null, 'tristate', + 'Set whether we should pass Ctrl-1..9 to the browser.\n' + + '\n' + + 'This is handy when running hterm in a browser tab, so that you don\'t ' + + 'lose Chrome\'s "switch to tab" keyboard accelerators. When not running ' + + 'in a tab it\'s better to send these keys to the host so they can be ' + + 'used in vim or emacs.\n' + + '\n' + + 'If true, Ctrl-1..9 will be handled by the browser. If false, Ctrl-1..9 ' + + 'will be sent to the host. If null, autodetect based on browser platform ' + + 'and window type.'], + + 'pass-meta-number': + [hterm.PreferenceManager.categories.Keyboard, null, 'tristate', + 'Set whether we should pass Meta-1..9 to the browser.\n' + + '\n' + + 'This is handy when running hterm in a browser tab, so that you don\'t ' + + 'lose Chrome\'s "switch to tab" keyboard accelerators. When not running ' + + 'in a tab it\'s better to send these keys to the host so they can be ' + + 'used in vim or emacs.\n' + + '\n' + + 'If true, Meta-1..9 will be handled by the browser. If false, Meta-1..9 ' + + 'will be sent to the host. If null, autodetect based on browser platform ' + + 'and window type.'], + + 'pass-meta-v': + [hterm.PreferenceManager.categories.Keyboard, true, 'bool', + 'Set whether meta-V gets passed to host.'], + + 'receive-encoding': + [hterm.PreferenceManager.categories.Encoding, 'utf-8', ['utf-8', 'raw'], + 'Set the expected encoding for data received from the host.\n' + + '\n' + + 'Valid values are \'utf-8\' and \'raw\'.'], + + 'scroll-on-keystroke': + [hterm.PreferenceManager.categories.Scrolling, true, 'bool', + 'If true, scroll to the bottom on any keystroke.'], + + 'scroll-on-output': + [hterm.PreferenceManager.categories.Scrolling, false, 'bool', + 'If true, scroll to the bottom on terminal output.'], + + 'scrollbar-visible': + [hterm.PreferenceManager.categories.Scrolling, true, 'bool', + 'The vertical scrollbar mode.'], + + 'scroll-wheel-may-send-arrow-keys': + [hterm.PreferenceManager.categories.Scrolling, false, 'bool', + 'When using the alternative screen buffer, and DECCKM (Application Cursor ' + + 'Keys) is active, mouse wheel scroll events will emulate arrow keys.\n' + + '\n' + + 'It can be temporarily disabled by holding the shift key.\n' + + '\n' + + 'This frequently comes up when using pagers (less) or reading man pages ' + + 'or text editors (vi/nano) or using screen/tmux.'], + + 'scroll-wheel-move-multiplier': + [hterm.PreferenceManager.categories.Scrolling, 1, 'int', + 'The multiplier for the pixel delta in wheel events caused by the ' + + 'scroll wheel. Alters how fast the page scrolls.'], + + 'send-encoding': + [hterm.PreferenceManager.categories.Encoding, 'utf-8', ['utf-8', 'raw'], + 'Set the encoding for data sent to host.'], + + 'terminal-encoding': + [hterm.PreferenceManager.categories.Encoding, 'iso-2022', + ['iso-2022', 'utf-8', 'utf-8-locked'], + 'The default terminal encoding (DOCS).\n' + + '\n' + + 'ISO-2022 enables character map translations (like graphics maps).\n' + + 'UTF-8 disables support for those.\n' + + '\n' + + 'The locked variant means the encoding cannot be changed at runtime ' + + 'via terminal escape sequences.\n' + + '\n' + + 'You should stick with UTF-8 unless you notice broken rendering with ' + + 'legacy applications.'], + + 'shift-insert-paste': + [hterm.PreferenceManager.categories.Keyboard, true, 'bool', + 'Shift + Insert pastes if true, sent to host if false.'], + + 'user-css': + [hterm.PreferenceManager.categories.Appearance, '', 'url', + 'URL of user stylesheet to include in the terminal document.'], + + 'user-css-text': + [hterm.PreferenceManager.categories.Appearance, '', 'multiline-string', + 'Custom CSS text for styling the terminal.'], +}; + +hterm.PreferenceManager.prototype = + Object.create(lib.PreferenceManager.prototype); +hterm.PreferenceManager.constructor = hterm.PreferenceManager; // SOURCE FILE: hterm/js/hterm_pubsub.js // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -7234,6 +8664,11 @@ hterm.Screen = function(opt_columnCount) { // The offset in column width into cursorNode_ where the cursor is positioned. this.cursorOffset_ = null; + + // Regexes for expanding word selections. + this.wordBreakMatchLeft = null; + this.wordBreakMatchRight = null; + this.wordBreakMatchMiddle = null; }; /** @@ -7298,7 +8733,7 @@ hterm.Screen.prototype.shiftRows = function(count) { /** * Insert a row at the top of the screen. * - * @param {HTMLElement} The row to insert. + * @param {HTMLElement} row The row to insert. */ hterm.Screen.prototype.unshiftRow = function(row) { this.rowsArray.splice(0, 0, row); @@ -7307,7 +8742,7 @@ hterm.Screen.prototype.unshiftRow = function(row) { /** * Insert rows at the top of the screen. * - * @param {Array.} The rows to insert. + * @param {Array.} rows The rows to insert. */ hterm.Screen.prototype.unshiftRows = function(rows) { this.rowsArray.unshift.apply(this.rowsArray, rows); @@ -7335,7 +8770,7 @@ hterm.Screen.prototype.popRows = function(count) { /** * Insert a row at the bottom of the screen. * - * @param {HTMLElement} The row to insert. + * @param {HTMLElement} row The row to insert. */ hterm.Screen.prototype.pushRow = function(row) { this.rowsArray.push(row); @@ -7344,25 +8779,27 @@ hterm.Screen.prototype.pushRow = function(row) { /** * Insert rows at the bottom of the screen. * - * @param {Array.} The rows to insert. + * @param {Array.} rows The rows to insert. */ hterm.Screen.prototype.pushRows = function(rows) { rows.push.apply(this.rowsArray, rows); }; /** - * Insert a row at the specified column of the screen. + * Insert a row at the specified row of the screen. * - * @param {HTMLElement} The row to insert. + * @param {integer} index The index to insert the row. + * @param {HTMLElement} row The row to insert. */ hterm.Screen.prototype.insertRow = function(index, row) { this.rowsArray.splice(index, 0, row); }; /** - * Insert rows at the specified column of the screen. + * Insert rows at the specified row of the screen. * - * @param {Array.} The rows to insert. + * @param {integer} index The index to insert the rows. + * @param {Array.} rows The rows to insert. */ hterm.Screen.prototype.insertRows = function(index, rows) { for (var i = 0; i < rows.length; i++) { @@ -7371,8 +8808,9 @@ hterm.Screen.prototype.insertRows = function(index, rows) { }; /** - * Remove a last row from the specified column of the screen and return it. + * Remove a row from the screen and return it. * + * @param {integer} index The index of the row to remove. * @return {HTMLElement} The selected row. */ hterm.Screen.prototype.removeRow = function(index) { @@ -7382,6 +8820,7 @@ hterm.Screen.prototype.removeRow = function(index) { /** * Remove rows from the bottom of the screen and return them as an array. * + * @param {integer} index The index to start removing rows. * @param {integer} count The number of rows to remove. * @return {Array.} The selected rows. */ @@ -7422,8 +8861,8 @@ hterm.Screen.prototype.clearCursorRow = function() { text = lib.f.getWhitespace(this.columnCount_); } - // We shouldn't honour inverse colors when clearing an area, to match - // xterm's back color erase behaviour. + // We shouldn't honor inverse colors when clearing an area, to match + // xterm's back color erase behavior. var inverse = this.textAttributes.inverse; this.textAttributes.inverse = false; this.textAttributes.syncColors(); @@ -7535,7 +8974,7 @@ hterm.Screen.prototype.syncSelectionCaret = function(selection) { * * For example: * Given the DOM fragment '
Hello World
', call splitNode_ - * passing the span and an offset of 6. This would modifiy the fragment to + * passing the span and an offset of 6. This would modify the fragment to * become: '
Hello World
'. If the span * had any attributes they would have been copied to the new span as well. * @@ -7618,7 +9057,7 @@ hterm.Screen.prototype.maybeClipCurrentRow = function() { * It is also up to the caller to properly maintain the line overflow state * using hterm.Screen..commitLineOverflow(). */ -hterm.Screen.prototype.insertString = function(str) { +hterm.Screen.prototype.insertString = function(str, wcwidth=undefined) { var cursorNode = this.cursorNode_; var cursorNodeText = cursorNode.textContent; @@ -7626,11 +9065,12 @@ hterm.Screen.prototype.insertString = function(str) { // We may alter the width of the string by prepending some missing // whitespaces, so we need to record the string width ahead of time. - var strWidth = lib.wc.strWidth(str); + if (wcwidth === undefined) + wcwidth = lib.wc.strWidth(str); // No matter what, before this function exits the cursor column will have // moved this much. - this.cursorPosition.column += strWidth; + this.cursorPosition.column += wcwidth; // Local cache of the cursor offset. var offset = this.cursorOffset_; @@ -7652,12 +9092,14 @@ hterm.Screen.prototype.insertString = function(str) { this.textAttributes.strikethrough || this.textAttributes.background || this.textAttributes.wcNode || + !this.textAttributes.asciiNode || this.textAttributes.tileData != null)) { // Best case scenario, we can just pretend the spaces were part of the // original string. str = ws + str; - } else if (cursorNode.nodeType == 3 || + } else if (cursorNode.nodeType == Node.TEXT_NODE || !(cursorNode.wcNode || + !cursorNode.asciiNode || cursorNode.tileNode || cursorNode.style.textDecoration || cursorNode.style.backgroundColor)) { @@ -7688,7 +9130,7 @@ hterm.Screen.prototype.insertString = function(str) { str + hterm.TextAttributes.nodeSubstr(cursorNode, offset); } - this.cursorOffset_ += strWidth; + this.cursorOffset_ += wcwidth; return; } @@ -7710,7 +9152,7 @@ hterm.Screen.prototype.insertString = function(str) { var newNode = this.textAttributes.createContainer(str); this.cursorRowNode_.insertBefore(newNode, cursorNode); this.cursorNode_ = newNode; - this.cursorOffset_ = strWidth; + this.cursorOffset_ = wcwidth; return; } @@ -7740,7 +9182,7 @@ hterm.Screen.prototype.insertString = function(str) { var newNode = this.textAttributes.createContainer(str); this.cursorRowNode_.insertBefore(newNode, cursorNode.nextSibling); this.cursorNode_ = newNode; - this.cursorOffset_ = strWidth; + this.cursorOffset_ = wcwidth; }; /** @@ -7752,22 +9194,24 @@ hterm.Screen.prototype.insertString = function(str) { * It is also up to the caller to properly maintain the line overflow state * using hterm.Screen..commitLineOverflow(). */ -hterm.Screen.prototype.overwriteString = function(str) { +hterm.Screen.prototype.overwriteString = function(str, wcwidth=undefined) { var maxLength = this.columnCount_ - this.cursorPosition.column; if (!maxLength) return [str]; - var width = lib.wc.strWidth(str); + if (wcwidth === undefined) + wcwidth = lib.wc.strWidth(str); + if (this.textAttributes.matchesContainer(this.cursorNode_) && this.cursorNode_.textContent.substr(this.cursorOffset_) == str) { // This overwrite would be a no-op, just move the cursor and return. - this.cursorOffset_ += width; - this.cursorPosition.column += width; + this.cursorOffset_ += wcwidth; + this.cursorPosition.column += wcwidth; return; } - this.deleteChars(Math.min(width, maxLength)); - this.insertString(str); + this.deleteChars(Math.min(wcwidth, maxLength)); + this.insertString(str, wcwidth); }; /** @@ -7793,21 +9237,34 @@ hterm.Screen.prototype.deleteChars = function(count) { var startLength, endLength; while (node && count) { + // Sanity check so we don't loop forever, but we don't also go quietly. + if (count < 0) { + console.error(`Deleting ${rv} chars went negative: ${count}`); + break; + } + startLength = hterm.TextAttributes.nodeWidth(node); node.textContent = hterm.TextAttributes.nodeSubstr(node, 0, offset) + hterm.TextAttributes.nodeSubstr(node, offset + count); endLength = hterm.TextAttributes.nodeWidth(node); - count -= startLength - endLength; - if (offset < startLength && endLength && startLength == endLength) { + + // Deal with splitting wide characters. There are two ways: we could delete + // the first column or the second column. In both cases, we delete the wide + // character and replace one of the columns with a space (since the other + // was deleted). If there are more chars to delete, the next loop will pick + // up the slack. + if (node.wcNode && offset < startLength && + ((endLength && startLength == endLength) || (!endLength && offset == 1))) { // No characters were deleted when there should be. We're probably trying // to delete one column width from a wide character node. We remove the // wide character node here and replace it with a single space. var spaceNode = this.textAttributes.createContainer(' '); - node.parentNode.insertBefore(spaceNode, node.nextSibling); + node.parentNode.insertBefore(spaceNode, offset ? node : node.nextSibling); node.textContent = ''; endLength = 0; count -= 1; - } + } else + count -= startLength - endLength; var nextNode = node.nextSibling; if (endLength == 0 && node != this.cursorNode_) { @@ -7818,7 +9275,8 @@ hterm.Screen.prototype.deleteChars = function(count) { } // Remove this.cursorNode_ if it is an empty non-text node. - if (this.cursorNode_.nodeType != 3 && !this.cursorNode_.textContent) { + if (this.cursorNode_.nodeType != Node.TEXT_NODE && + !this.cursorNode_.textContent) { var cursorNode = this.cursorNode_; if (cursorNode.previousSibling) { this.cursorNode_ = cursorNode.previousSibling; @@ -7928,6 +9386,10 @@ hterm.Screen.prototype.getPositionWithOverflow_ = function(row, node, offset) { **/ hterm.Screen.prototype.getPositionWithinRow_ = function(row, node, offset) { if (node.parentNode != row) { + // If we traversed to the top node, then there's nothing to find here. + if (node.parentNode == null) + return -1; + return this.getPositionWithinRow_(node.parentNode, node, offset) + this.getPositionWithinRow_(row, node.parentNode, 0); } @@ -8034,10 +9496,10 @@ hterm.Screen.prototype.expandSelection = function(selection) { if (endPosition == -1) return; - // Matches can start with '~' or '.', since paths frequently do. - var leftMatch = '[^\\s\\[\\](){}<>"\'\\^!@#$%&*,;:`]'; - var rightMatch = '[^\\s\\[\\](){}<>"\'\\^!@#$%&*,;:~.`]'; - var insideMatch = '[^\\s\\[\\](){}<>"\'\\^]*'; + // Use the user configurable match settings. + var leftMatch = this.wordBreakMatchLeft; + var rightMatch = this.wordBreakMatchRight; + var insideMatch = this.wordBreakMatchMiddle; //Move start to the left. var rowText = this.getLineText_(row); @@ -8128,18 +9590,19 @@ hterm.ScrollPort = function(rowProvider) { // syncScrollHeight(). this.lastRowCount_ = 0; - // The scroll wheel pixel delta multiplier to increase/descrease - // the scroll speed of mouse wheel events. See: http://goo.gl/sXelnq + // The scroll wheel pixel delta multiplier to increase/decrease + // the scroll speed of mouse wheel events. See: https://goo.gl/sXelnq this.scrollWheelMultiplier_ = 1; + // The last touch events we saw to support touch based scrolling. Indexed + // by touch identifier since we can have more than one touch active. + this.lastTouch_ = {}; + /** * True if the last scroll caused the scrollport to show the final row. */ this.isScrolledEnd = true; - // The css rule that we use to control the height of a row. - this.xrowCssRule_ = null; - /** * A guess at the current scrollbar width, fixed in resize(). */ @@ -8358,29 +9821,56 @@ hterm.ScrollPort.prototype.decorate = function(div) { 'height: 100%;' + 'width: 100%;' + 'overflow: hidden;' + + 'cursor: var(--hterm-mouse-cursor-style);' + '-webkit-user-select: none;' + '-moz-user-select: none;'); + if (this.DEBUG_) { + // When we're debugging we add padding to the body so that the offscreen + // elements are visible. + this.document_.body.style.paddingTop = + this.document_.body.style.paddingBottom = + 'calc(var(--hterm-charsize-height) * 3)'; + } + var style = doc.createElement('style'); - style.textContent = 'x-row {}'; + style.textContent = ( + 'x-row {' + + ' display: block;' + + ' height: var(--hterm-charsize-height);' + + ' line-height: var(--hterm-charsize-height);' + + '}'); doc.head.appendChild(style); - this.xrowCssRule_ = doc.styleSheets[0].cssRules[0]; - this.xrowCssRule_.style.display = 'block'; - this.userCssLink_ = doc.createElement('link'); this.userCssLink_.setAttribute('rel', 'stylesheet'); + this.userCssText_ = doc.createElement('style'); + doc.head.appendChild(this.userCssText_); + // TODO(rginda): Sorry, this 'screen_' isn't the same thing as hterm.Screen // from screen.js. I need to pick a better name for one of them to avoid // the collision. + // We make this field editable even though we don't actually allow anything + // to be edited here so that Chrome will do the right thing with virtual + // keyboards and IMEs. But make sure we turn off all the input helper logic + // that doesn't make sense here, and might inadvertently mung or save input. + // Some of these attributes are standard while others are browser specific, + // but should be safely ignored by other browsers. this.screen_ = doc.createElement('x-screen'); + this.screen_.setAttribute('contenteditable', 'true'); + this.screen_.setAttribute('spellcheck', 'false'); + this.screen_.setAttribute('autocomplete', 'off'); + this.screen_.setAttribute('autocorrect', 'off'); + this.screen_.setAttribute('autocaptalize', 'none'); this.screen_.setAttribute('role', 'textbox'); this.screen_.setAttribute('tabindex', '-1'); this.screen_.style.cssText = ( + 'caret-color: transparent;' + 'display: block;' + 'font-family: monospace;' + 'font-size: 15px;' + + 'font-variant-ligatures: none;' + 'height: 100%;' + 'overflow-y: scroll; overflow-x: hidden;' + 'white-space: pre;' + @@ -8390,16 +9880,20 @@ hterm.ScrollPort.prototype.decorate = function(div) { doc.body.appendChild(this.screen_); this.screen_.addEventListener('scroll', this.onScroll_.bind(this)); - this.screen_.addEventListener('mousewheel', this.onScrollWheel_.bind(this)); - this.screen_.addEventListener( - 'DOMMouseScroll', this.onScrollWheel_.bind(this)); + this.screen_.addEventListener('wheel', this.onScrollWheel_.bind(this)); + this.screen_.addEventListener('touchstart', this.onTouch_.bind(this)); + this.screen_.addEventListener('touchmove', this.onTouch_.bind(this)); + this.screen_.addEventListener('touchend', this.onTouch_.bind(this)); + this.screen_.addEventListener('touchcancel', this.onTouch_.bind(this)); this.screen_.addEventListener('copy', this.onCopy_.bind(this)); this.screen_.addEventListener('paste', this.onPaste_.bind(this)); + this.screen_.addEventListener('drop', this.onDragAndDrop_.bind(this)); doc.body.addEventListener('keydown', this.onBodyKeyDown_.bind(this)); // This is the main container for the fixed rows. this.rowNodes_ = doc.createElement('div'); + this.rowNodes_.id = 'hterm:row-nodes'; this.rowNodes_.style.cssText = ( 'display: block;' + 'position: fixed;' + @@ -8413,6 +9907,7 @@ hterm.ScrollPort.prototype.decorate = function(div) { this.topSelectBag_.style.cssText = ( 'display: block;' + 'overflow: hidden;' + + 'height: var(--hterm-charsize-height);' + 'white-space: pre;'); this.bottomSelectBag_ = this.topSelectBag_.cloneNode(); @@ -8421,10 +9916,12 @@ hterm.ScrollPort.prototype.decorate = function(div) { // only used to hold rows that are part of the selection but are currently // scrolled off the top or bottom of the visible range. this.topFold_ = doc.createElement('x-fold'); + this.topFold_.id = 'hterm:top-fold-for-row-selection'; this.topFold_.style.cssText = 'display: block;'; this.rowNodes_.appendChild(this.topFold_); this.bottomFold_ = this.topFold_.cloneNode(); + this.bottomFold_.id = 'hterm:bottom-fold-for-row-selection'; this.rowNodes_.appendChild(this.bottomFold_); // This hidden div accounts for the vertical space that would be consumed by @@ -8437,6 +9934,7 @@ hterm.ScrollPort.prototype.decorate = function(div) { // select and scroll at the same time). Without this, the selection gets // out of whack. this.scrollArea_ = doc.createElement('div'); + this.scrollArea_.id = 'hterm:scrollarea'; this.scrollArea_.style.cssText = 'visibility: hidden'; this.screen_.appendChild(this.scrollArea_); @@ -8444,9 +9942,11 @@ hterm.ScrollPort.prototype.decorate = function(div) { // placed in the outermost document for currentScale to be correct. // TODO(rginda): This means that hterm nested in an iframe will not correctly // detect browser zoom level. We should come up with a better solution. - this.svg_ = this.div_.ownerDocument.createElementNS( - 'http://www.w3.org/2000/svg', 'svg'); - this.svg_.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); + // Note: This must be http:// else Chrome cannot create the element correctly. + var xmlns = 'http://www.w3.org/2000/svg'; + this.svg_ = this.div_.ownerDocument.createElementNS(xmlns, 'svg'); + this.svg_.id = 'hterm:zoom-detector'; + this.svg_.setAttribute('xmlns', xmlns); this.svg_.setAttribute('version', '1.1'); this.svg_.style.cssText = ( 'position: absolute;' + @@ -8458,6 +9958,7 @@ hterm.ScrollPort.prototype.decorate = function(div) { // We send focus to this element just before a paste happens, so we can // capture the pasted text and forward it on to someone who cares. this.pasteTarget_ = doc.createElement('textarea'); + this.pasteTarget_.id = 'hterm:ctrl-v-paste-target'; this.pasteTarget_.setAttribute('tabindex', '-1'); this.pasteTarget_.style.cssText = ( 'position: absolute;' + @@ -8504,7 +10005,7 @@ hterm.ScrollPort.prototype.getFontFamily = function() { * Defaults to null, meaning no custom css is loaded. Set it back to null or * the empty string to remove a previously applied custom css. */ -hterm.ScrollPort.prototype.setUserCss = function(url) { +hterm.ScrollPort.prototype.setUserCssUrl = function(url) { if (url) { this.userCssLink_.setAttribute('href', url); @@ -8515,6 +10016,10 @@ hterm.ScrollPort.prototype.setUserCss = function(url) { } }; +hterm.ScrollPort.prototype.setUserCssText = function(text) { + this.userCssText_.textContent = text; +}; + hterm.ScrollPort.prototype.focus = function() { this.iframe_.focus(); this.screen_.focus(); @@ -8679,8 +10184,14 @@ hterm.ScrollPort.prototype.getFontSize = function() { * @return {hterm.Size} A new hterm.Size object. */ hterm.ScrollPort.prototype.measureCharacterSize = function(opt_weight) { + // Number of lines used to average the height of a single character. + var numberOfLines = 100; + // Number of chars per line used to average the width of a single character. + var lineLength = 100; + if (!this.ruler_) { this.ruler_ = this.document_.createElement('div'); + this.ruler_.id = 'hterm:ruler-character-size'; this.ruler_.style.cssText = ( 'position: absolute;' + 'top: 0;' + @@ -8692,14 +10203,13 @@ hterm.ScrollPort.prototype.measureCharacterSize = function(opt_weight) { // We need to put the text in a span to make the size calculation // work properly in Firefox this.rulerSpan_ = this.document_.createElement('span'); - this.rulerSpan_.textContent = ('XXXXXXXXXXXXXXXXXXXX' + - 'XXXXXXXXXXXXXXXXXXXX' + - 'XXXXXXXXXXXXXXXXXXXX' + - 'XXXXXXXXXXXXXXXXXXXX' + - 'XXXXXXXXXXXXXXXXXXXX'); + this.rulerSpan_.id = 'hterm:ruler-span-workaround'; + this.rulerSpan_.innerHTML = + ('X'.repeat(lineLength) + '\r').repeat(numberOfLines); this.ruler_.appendChild(this.rulerSpan_); this.rulerBaseline_ = this.document_.createElement('span'); + this.rulerSpan_.id = 'hterm:ruler-baseline'; // We want to collapse it on the baseline this.rulerBaseline_.style.fontSize = '0px'; this.rulerBaseline_.textContent = 'X'; @@ -8710,8 +10220,8 @@ hterm.ScrollPort.prototype.measureCharacterSize = function(opt_weight) { this.rowNodes_.appendChild(this.ruler_); var rulerSize = hterm.getClientSize(this.rulerSpan_); - var size = new hterm.Size(rulerSize.width / this.ruler_.textContent.length, - rulerSize.height); + var size = new hterm.Size(rulerSize.width / lineLength, + rulerSize.height / numberOfLines); this.ruler_.appendChild(this.rulerBaseline_); size.baseline = this.rulerBaseline_.offsetTop; @@ -8735,20 +10245,7 @@ hterm.ScrollPort.prototype.measureCharacterSize = function(opt_weight) { hterm.ScrollPort.prototype.syncCharacterSize = function() { this.characterSize = this.measureCharacterSize(); - var lineHeight = this.characterSize.height + 'px'; - this.xrowCssRule_.style.height = lineHeight; - this.topSelectBag_.style.height = lineHeight; - this.bottomSelectBag_.style.height = lineHeight; - this.resize(); - - if (this.DEBUG_) { - // When we're debugging we add padding to the body so that the offscreen - // elements are visible. - this.document_.body.style.paddingTop = - this.document_.body.style.paddingBottom = - 3 * this.characterSize.height + 'px'; - } }; /** @@ -9244,8 +10741,7 @@ hterm.ScrollPort.prototype.scrollRowToBottom = function(rowIndex) { * returns the row that *should* be at the top. */ hterm.ScrollPort.prototype.getTopRowIndex = function() { - return lib.f.smartFloorDivide( - this.screen_.scrollTop, this.characterSize.height); + return Math.round(this.screen_.scrollTop / this.characterSize.height); }; /** @@ -9303,11 +10799,8 @@ hterm.ScrollPort.prototype.onScrollWheel_ = function(e) { if (e.defaultPrevented) return; - // In FF, the event is DOMMouseScroll and puts the scroll pixel delta in the - // 'detail' field of the event. It also flips the mapping of which direction - // a negative number means in the scroll. - var delta = e.type == 'DOMMouseScroll' ? (-1 * e.detail) : e.wheelDeltaY; - delta *= this.scrollWheelMultiplier_; + // Figure out how far this event wants us to scroll. + var delta = this.scrollWheelDelta(e); var top = this.screen_.scrollTop - delta; if (top < 0) @@ -9328,6 +10821,110 @@ hterm.ScrollPort.prototype.onScrollWheel_ = function(e) { } }; +/** + * Calculate how far a wheel event should scroll. + * + * @param {WheelEvent} e The mouse wheel event to process. + * @return {number} How far (in pixels) to scroll. + */ +hterm.ScrollPort.prototype.scrollWheelDelta = function(e) { + var delta; + + switch (e.deltaMode) { + case WheelEvent.DOM_DELTA_PIXEL: + delta = e.deltaY * this.scrollWheelMultiplier_; + break; + case WheelEvent.DOM_DELTA_LINE: + delta = e.deltaY * this.characterSize.height; + break; + case WheelEvent.DOM_DELTA_PAGE: + delta = e.deltaY * this.characterSize.height * this.screen_.getHeight(); + break; + } + + // The sign is inverted from what we would expect. + return delta * -1; +}; + + +/** + * Clients can override this if they want to hear touch events. + * + * Clients may call event.preventDefault() if they want to keep the scrollport + * from also handling the events. + */ +hterm.ScrollPort.prototype.onTouch = function(e) {}; + +/** + * Handler for touch events. + */ +hterm.ScrollPort.prototype.onTouch_ = function(e) { + this.onTouch(e); + + if (e.defaultPrevented) + return; + + // Extract the fields from the Touch event that we need. If we saved the + // event directly, it has references to other objects (like x-row) that + // might stick around for a long time. This way we only have small objects + // in our lastTouch_ state. + var scrubTouch = function(t) { + return { + id: t.identifier, + y: t.clientY, + x: t.clientX, + }; + }; + + var i, touch; + switch (e.type) { + case 'touchstart': + // Save the current set of touches. + for (i = 0; i < e.changedTouches.length; ++i) { + touch = scrubTouch(e.changedTouches[i]); + this.lastTouch_[touch.id] = touch; + } + break; + + case 'touchcancel': + case 'touchend': + // Throw away existing touches that we're finished with. + for (i = 0; i < e.changedTouches.length; ++i) + delete this.lastTouch_[e.changedTouches[i].identifier]; + break; + + case 'touchmove': + // Walk all of the touches in this one event and merge all of their + // changes into one delta. This lets multiple fingers scroll faster. + var delta = 0; + for (i = 0; i < e.changedTouches.length; ++i) { + touch = scrubTouch(e.changedTouches[i]); + delta += (this.lastTouch_[touch.id].y - touch.y); + this.lastTouch_[touch.id] = touch; + } + + // Invert to match the touchscreen scrolling direction of browser windows. + delta *= -1; + + var top = this.screen_.scrollTop - delta; + if (top < 0) + top = 0; + + var scrollMax = this.getScrollMax_(); + if (top > scrollMax) + top = scrollMax; + + if (top != this.screen_.scrollTop) { + // Moving scrollTop causes a scroll event, which triggers the redraw. + this.screen_.scrollTop = top; + } + break; + } + + // To disable gestures or anything else interfering with our scrolling. + e.preventDefault(); +}; + /** * Handler for resize events. * @@ -9337,7 +10934,6 @@ hterm.ScrollPort.prototype.onScrollWheel_ = function(e) { hterm.ScrollPort.prototype.onResize_ = function(e) { // Re-measure, since onResize also happens for browser zoom changes. this.syncCharacterSize(); - this.resize(); }; /** @@ -9426,6 +11022,8 @@ hterm.ScrollPort.prototype.onBodyKeyDown_ = function(e) { /** * Handle a paste event on the the ScrollPort's screen element. + * + * TODO: Handle ClipboardData.files transfers. https://crbug.com/433581. */ hterm.ScrollPort.prototype.onPaste_ = function(e) { this.pasteTarget_.focus(); @@ -9446,6 +11044,43 @@ hterm.ScrollPort.prototype.handlePasteTargetTextInput_ = function(e) { e.stopPropagation(); }; +/** + * Handle a drop event on the the ScrollPort's screen element. + * + * By default we try to copy in the structured format (HTML/whatever). + * The shift key can select plain text though. + * + * TODO: Handle DataTransfer.files transfers. https://crbug.com/433581. + * + * @param {DragEvent} e The drag event that fired us. + */ +hterm.ScrollPort.prototype.onDragAndDrop_ = function(e) { + e.preventDefault(); + + let data; + let format; + + // If the shift key isn't active, try to find a text source (but not plain + // text). e.g. text/html is OK. + if (!e.shiftKey) { + e.dataTransfer.types.forEach((t) => { + if (!format && t != 'text/plain' && t.startsWith('text/')) + format = t; + }); + + // If we found a non-plain text source, try it out first. + if (format) + data = e.dataTransfer.getData(format); + } + + // If we haven't loaded anything useful, fall back to plain text. + if (!data) + data = e.dataTransfer.getData('text/plain'); + + if (data) + this.publish('paste', {text: data}); +}; + /** * Set the vertical scrollbar mode of the ScrollPort. */ @@ -9560,13 +11195,14 @@ hterm.Terminal = function(opt_profileId) { this.foregroundColor_ = null; this.scrollOnOutput_ = null; this.scrollOnKeystroke_ = null; + this.scrollWheelArrowKeys_ = null; - // True if we should send mouse events to the vt, false if we want them - // to manage the local text selection. - this.reportMouseEvents_ = false; + // True if we should override mouse event reporting to allow local selection. + this.defeatMouseReports_ = false; // Terminal bell sound. this.bellAudio_ = this.document_.createElement('audio'); + this.bellAudio_.id = 'hterm:bell-audio'; this.bellAudio_.setAttribute('preload', 'auto'); // All terminal bell notifications that have been generated (not necessarily @@ -9588,7 +11224,7 @@ hterm.Terminal = function(opt_profileId) { // The VT escape sequence interpreter. this.vt = new hterm.VT(this); - // The keyboard hander. + // The keyboard handler. this.keyboard = new hterm.Keyboard(this); // General IO interface that can be given to third parties without exposing @@ -9599,9 +11235,10 @@ hterm.Terminal = function(opt_profileId) { this.enableMouseDragScroll = true; this.copyOnSelect = null; + this.mouseRightClickPaste = null; this.mousePasteButton = null; - // Whether to use the default window copy behaviour. + // Whether to use the default window copy behavior. this.useDefaultWindowCopy = false; this.clearSelectionAfterCopy = true; @@ -9609,8 +11246,10 @@ hterm.Terminal = function(opt_profileId) { this.realizeSize_(80, 24); this.setDefaultTabStops(); + this.reportFocus = false; + this.setProfile(opt_profileId || 'default', - function() { this.onTerminalReady() }.bind(this)); + function() { this.onTerminalReady(); }.bind(this)); }; /** @@ -9642,7 +11281,7 @@ hterm.Terminal.prototype.tabWidth = 8; * This will load the terminal preferences for the given profile name and * associate subsequent preference changes with the new preference profile. * - * @param {string} newName The name of the preference profile. Forward slash + * @param {string} profileId The name of the preference profile. Forward slash * characters will be removed from the name. * @param {function} opt_callback Optional callback to invoke when the profile * transition is complete. @@ -9747,13 +11386,8 @@ hterm.Terminal.prototype.setProfile = function(profileId, opt_callback) { return; } - for (var code in v) { - var glmap = hterm.VT.CharacterMap.maps[code].glmap; - for (var received in v[code]) { - glmap[received] = v[code][received]; - } - hterm.VT.CharacterMap.maps[code].reset(glmap); - } + terminal.vt.characterMaps.reset(); + terminal.vt.characterMaps.setOverrides(v); }, 'cursor-blink': function(v) { @@ -9802,7 +11436,7 @@ hterm.Terminal.prototype.setProfile = function(profileId, opt_callback) { } } - terminal.primaryScreen_.textAttributes.resetColorPalette() + terminal.primaryScreen_.textAttributes.resetColorPalette(); terminal.alternateScreen_.textAttributes.resetColorPalette(); }, @@ -9848,6 +11482,10 @@ hterm.Terminal.prototype.setProfile = function(profileId, opt_callback) { terminal.alternateScreen_.textAttributes.enableBoldAsBright = !!v; }, + 'enable-blink': function(v) { + terminal.syncBlinkState(); + }, + 'enable-clipboard-write': function(v) { terminal.vt.enableClipboardWrite = !!v; }, @@ -9876,6 +11514,24 @@ hterm.Terminal.prototype.setProfile = function(profileId, opt_callback) { terminal.keyboard.homeKeysScroll = v; }, + 'keybindings': function(v) { + terminal.keyboard.bindings.clear(); + + if (!v) + return; + + if (!(v instanceof Object)) { + console.error('Error in keybindings preference: Expected object'); + return; + } + + try { + terminal.keyboard.bindings.addBindings(v); + } catch (ex) { + console.error('Error in keybindings preference: ' + ex); + } + }, + 'max-string-sequence': function(v) { terminal.vt.maxStringSequence = v; }, @@ -9888,6 +11544,10 @@ hterm.Terminal.prototype.setProfile = function(profileId, opt_callback) { terminal.keyboard.metaSendsEscape = v; }, + 'mouse-right-click-paste': function(v) { + terminal.mouseRightClickPaste = v; + }, + 'mouse-paste-button': function(v) { terminal.syncMousePasteButton(); }, @@ -9957,6 +11617,10 @@ hterm.Terminal.prototype.setProfile = function(profileId, opt_callback) { terminal.setScrollbarVisible(v); }, + 'scroll-wheel-may-send-arrow-keys': function(v) { + terminal.scrollWheelArrowKeys_ = v; + }, + 'scroll-wheel-move-multiplier': function(v) { terminal.setScrollWheelMoveMultipler(v); }, @@ -9974,9 +11638,32 @@ hterm.Terminal.prototype.setProfile = function(profileId, opt_callback) { terminal.keyboard.shiftInsertPaste = v; }, + 'terminal-encoding': function(v) { + terminal.vt.setEncoding(v); + }, + 'user-css': function(v) { - terminal.scrollPort_.setUserCss(v); - } + terminal.scrollPort_.setUserCssUrl(v); + }, + + 'user-css-text': function(v) { + terminal.scrollPort_.setUserCssText(v); + }, + + 'word-break-match-left': function(v) { + terminal.primaryScreen_.wordBreakMatchLeft = v; + terminal.alternateScreen_.wordBreakMatchLeft = v; + }, + + 'word-break-match-right': function(v) { + terminal.primaryScreen_.wordBreakMatchRight = v; + terminal.alternateScreen_.wordBreakMatchRight = v; + }, + + 'word-break-match-middle': function(v) { + terminal.primaryScreen_.wordBreakMatchMiddle = v; + terminal.alternateScreen_.wordBreakMatchMiddle = v; + }, }); this.prefs_.readStorage(function() { @@ -9990,6 +11677,8 @@ hterm.Terminal.prototype.setProfile = function(profileId, opt_callback) { /** * Returns the preferences manager used for configuring this terminal. + * + * @return {hterm.PreferenceManager} */ hterm.Terminal.prototype.getPrefs = function() { return this.prefs_; @@ -9997,6 +11686,8 @@ hterm.Terminal.prototype.getPrefs = function() { /** * Enable or disable bracketed paste mode. + * + * @param {boolean} state The value to set. */ hterm.Terminal.prototype.setBracketedPaste = function(state) { this.options_.bracketedPaste = state; @@ -10007,6 +11698,8 @@ hterm.Terminal.prototype.setBracketedPaste = function(state) { * * If you want this setting to persist, set it through prefs_, rather than * with this method. + * + * @param {string} color The color to set. */ hterm.Terminal.prototype.setCursorColor = function(color) { this.cursorColor_ = color; @@ -10016,6 +11709,7 @@ hterm.Terminal.prototype.setCursorColor = function(color) { /** * Return the current cursor color as a string. + * @return {string} */ hterm.Terminal.prototype.getCursorColor = function() { return this.cursorColor_; @@ -10023,6 +11717,8 @@ hterm.Terminal.prototype.getCursorColor = function() { /** * Enable or disable mouse based text selection in the terminal. + * + * @param {boolean} state The value to set. */ hterm.Terminal.prototype.setSelectionEnabled = function(state) { this.enableMouseDragScroll = state; @@ -10033,6 +11729,8 @@ hterm.Terminal.prototype.setSelectionEnabled = function(state) { * * If you want this setting to persist, set it through prefs_, rather than * with this method. + * + * @param {string} color The color to set. */ hterm.Terminal.prototype.setBackgroundColor = function(color) { this.backgroundColor_ = lib.colors.normalizeCSS(color); @@ -10048,6 +11746,8 @@ hterm.Terminal.prototype.setBackgroundColor = function(color) { * * Intended for use by other classes, so we don't have to expose the entire * prefs_ object. + * + * @return {string} */ hterm.Terminal.prototype.getBackgroundColor = function() { return this.backgroundColor_; @@ -10058,6 +11758,8 @@ hterm.Terminal.prototype.getBackgroundColor = function() { * * If you want this setting to persist, set it through prefs_, rather than * with this method. + * + * @param {string} color The color to set. */ hterm.Terminal.prototype.setForegroundColor = function(color) { this.foregroundColor_ = lib.colors.normalizeCSS(color); @@ -10073,6 +11775,8 @@ hterm.Terminal.prototype.setForegroundColor = function(color) { * * Intended for use by other classes, so we don't have to expose the entire * prefs_ object. + * + * @return {string} */ hterm.Terminal.prototype.getForegroundColor = function() { return this.foregroundColor_; @@ -10109,6 +11813,8 @@ hterm.Terminal.prototype.runCommandClass = function(commandClass, argString) { /** * Returns true if the current screen is the primary screen, false otherwise. + * + * @return {boolean} */ hterm.Terminal.prototype.isPrimaryScreen = function() { return this.screen_ == this.primaryScreen_; @@ -10131,6 +11837,21 @@ hterm.Terminal.prototype.uninstallKeyboard = function() { this.keyboard.installKeyboard(null); } +/** + * Set a CSS variable. + * + * Normally this is used to set variables in the hterm namespace. + * + * @param {string} name The variable to set. + * @param {string} value The value to assign to the variable. + * @param {string?} opt_prefix The variable namespace/prefix to use. + */ +hterm.Terminal.prototype.setCssVar = function(name, value, + opt_prefix='--hterm-') { + this.document_.documentElement.style.setProperty( + `${opt_prefix}${name}`, value); +}; + /** * Set the font size for this terminal. * @@ -10145,14 +11866,15 @@ hterm.Terminal.prototype.setFontSize = function(px) { px = this.prefs_.get('font-size'); this.scrollPort_.setFontSize(px); - if (this.wcCssRule_) { - this.wcCssRule_.style.width = this.scrollPort_.characterSize.width * 2 + - 'px'; - } + this.setCssVar('charsize-width', this.scrollPort_.characterSize.width + 'px'); + this.setCssVar('charsize-height', + this.scrollPort_.characterSize.height + 'px'); }; /** * Get the current font size. + * + * @return {number} */ hterm.Terminal.prototype.getFontSize = function() { return this.scrollPort_.getFontSize(); @@ -10160,6 +11882,8 @@ hterm.Terminal.prototype.getFontSize = function() { /** * Get the current font family. + * + * @return {string} */ hterm.Terminal.prototype.getFontFamily = function() { return this.scrollPort_.getFontFamily(); @@ -10186,10 +11910,10 @@ hterm.Terminal.prototype.syncMousePasteButton = function() { } var ary = navigator.userAgent.match(/\(X11;\s+(\S+)/); - if (!ary || ary[2] == 'CrOS') { - this.mousePasteButton = 2; + if (!ary || ary[1] == 'CrOS') { + this.mousePasteButton = 1; // Middle mouse button. } else { - this.mousePasteButton = 3; + this.mousePasteButton = 2; // Right mouse button. } }; @@ -10219,6 +11943,24 @@ hterm.Terminal.prototype.syncBoldSafeState = function() { this.alternateScreen_.textAttributes.enableBold = isBoldSafe; }; +/** + * Enable or disable blink based on the enable-blink pref. + */ +hterm.Terminal.prototype.syncBlinkState = function() { + this.setCssVar('node-duration', + this.prefs_.get('enable-blink') ? '0.7s' : '0'); +}; + +/** + * Set the mouse cursor style based on the current terminal mode. + */ +hterm.Terminal.prototype.syncMouseStyle = function() { + this.setCssVar('mouse-cursor-style', + this.vt.mouseReport == this.vt.MOUSE_REPORT_DISABLED ? + 'var(--hterm-mouse-cursor-text)' : + 'var(--hterm-mouse-cursor-pointer)'); +}; + /** * Return a copy of the current cursor position. * @@ -10228,10 +11970,20 @@ hterm.Terminal.prototype.saveCursor = function() { return this.screen_.cursorPosition.clone(); }; +/** + * Return the current text attributes. + * + * @return {string} + */ hterm.Terminal.prototype.getTextAttributes = function() { return this.screen_.textAttributes; }; +/** + * Set the text attributes. + * + * @param {string} textAttributes The attributes to set. + */ hterm.Terminal.prototype.setTextAttributes = function(textAttributes) { this.screen_.textAttributes = textAttributes; }; @@ -10247,6 +11999,8 @@ hterm.Terminal.prototype.getZoomFactor = function() { /** * Change the title of this terminal's window. + * + * @param {string} title The title to set. */ hterm.Terminal.prototype.setWindowTitle = function(title) { window.document.title = title; @@ -10276,6 +12030,8 @@ hterm.Terminal.prototype.clearCursorOverflow = function() { /** * Sets the cursor shape + * + * @param {string} shape The shape to set. */ hterm.Terminal.prototype.setCursorShape = function(shape) { this.cursorShape_ = shape; @@ -10284,6 +12040,8 @@ hterm.Terminal.prototype.setCursorShape = function(shape) { /** * Get the cursor shape + * + * @return {string} */ hterm.Terminal.prototype.getCursorShape = function() { return this.cursorShape_; @@ -10291,6 +12049,8 @@ hterm.Terminal.prototype.getCursorShape = function() { /** * Set the width of the terminal, resizing the UI to match. + * + * @param {number} columnCount */ hterm.Terminal.prototype.setWidth = function(columnCount) { if (columnCount == null) { @@ -10307,6 +12067,8 @@ hterm.Terminal.prototype.setWidth = function(columnCount) { /** * Set the height of the terminal, resizing the UI to match. + * + * @param {number} rowCount The height in rows. */ hterm.Terminal.prototype.setHeight = function(rowCount) { if (rowCount == null) { @@ -10323,6 +12085,8 @@ hterm.Terminal.prototype.setHeight = function(rowCount) { /** * Deal with terminal size changes. * + * @param {number} columnCount The number of columns. + * @param {number} rowCount The number of rows. */ hterm.Terminal.prototype.realizeSize_ = function(columnCount, rowCount) { if (columnCount != this.screenSize.width) @@ -10345,6 +12109,8 @@ hterm.Terminal.prototype.realizeSize_ = function(columnCount, rowCount) { * * Relying on the browser to send us an async resize event means we may not be * in the correct state yet when the next escape sequence hits. + * + * @param {number} columnCount The number of columns. */ hterm.Terminal.prototype.realizeWidth_ = function(columnCount) { if (columnCount <= 0) @@ -10380,6 +12146,8 @@ hterm.Terminal.prototype.realizeWidth_ = function(columnCount) { * * Relying on the browser to send us an async resize event means we may not be * in the correct state yet when the next escape sequence hits. + * + * @param {number} rowCount The number of rows. */ hterm.Terminal.prototype.realizeHeight_ = function(rowCount) { if (rowCount <= 0) @@ -10464,6 +12232,22 @@ hterm.Terminal.prototype.scrollPageDown = function() { this.scrollPort_.scrollRowToTop(i + this.screenSize.height - 1); }; +/** + * Scroll the terminal one line up relative to the current position. + */ +hterm.Terminal.prototype.scrollLineUp = function() { + var i = this.scrollPort_.getTopRowIndex(); + this.scrollPort_.scrollRowToTop(i - 1); +}; + +/** + * Scroll the terminal one line down relative to the current position. + */ +hterm.Terminal.prototype.scrollLineDown = function() { + var i = this.scrollPort_.getTopRowIndex(); + this.scrollPort_.scrollRowToTop(i + 1); +}; + /** * Clear primary screen, secondary screen, and the scrollback buffer. */ @@ -10569,7 +12353,7 @@ hterm.Terminal.prototype.backwardTabStop = function() { /** * Set a tab stop at the given column. * - * @param {int} column Zero based column. + * @param {integer} column Zero based column. */ hterm.Terminal.prototype.setTabStop = function(column) { for (var i = this.tabStops_.length - 1; i >= 0; i--) { @@ -10618,7 +12402,7 @@ hterm.Terminal.prototype.clearAllTabStops = function() { * This does not clear the existing tab stops first, use clearAllTabStops * for that. * - * @param {int} opt_start Optional starting zero based starting column, useful + * @param {integer} opt_start Optional starting zero based starting column, useful * for filling out missing tab stops when the terminal is resized. */ hterm.Terminal.prototype.setDefaultTabStops = function(opt_start) { @@ -10658,7 +12442,8 @@ hterm.Terminal.prototype.decorate = function(div) { this.scrollPort_.setBackgroundSize(this.prefs_.get('background-size')); this.scrollPort_.setBackgroundPosition( this.prefs_.get('background-position')); - this.scrollPort_.setUserCss(this.prefs_.get('user-css')); + this.scrollPort_.setUserCssUrl(this.prefs_.get('user-css')); + this.scrollPort_.setUserCssText(this.prefs_.get('user-css-text')); this.div_.focus = this.focus.bind(this); @@ -10671,7 +12456,7 @@ hterm.Terminal.prototype.decorate = function(div) { this.document_ = this.scrollPort_.getDocument(); - this.document_.body.oncontextmenu = function() { return false }; + this.document_.body.oncontextmenu = function() { return false; }; var onMouse = this.onMouse_.bind(this); var screenNode = this.scrollPort_.getScreenNode(); @@ -10702,22 +12487,43 @@ hterm.Terminal.prototype.decorate = function(div) { '.wc-node {' + ' display: inline-block;' + ' text-align: center;' + - ' width: ' + this.scrollPort_.characterSize.width * 2 + 'px;' + + ' width: calc(var(--hterm-charsize-width) * 2);' + + ' line-height: var(--hterm-charsize-height);' + + '}' + + ':root {' + + ' --hterm-charsize-width: ' + this.scrollPort_.characterSize.width + 'px;' + + ' --hterm-charsize-height: ' + this.scrollPort_.characterSize.height + 'px;' + + // Default position hides the cursor for when the window is initializing. + ' --hterm-cursor-offset-col: -1;' + + ' --hterm-cursor-offset-row: -1;' + + ' --hterm-blink-node-duration: 0.7s;' + + ' --hterm-mouse-cursor-text: text;' + + ' --hterm-mouse-cursor-pointer: default;' + + ' --hterm-mouse-cursor-style: var(--hterm-mouse-cursor-text);' + + '}' + + '@keyframes blink {' + + ' from { opacity: 1.0; }' + + ' to { opacity: 0.0; }' + + '}' + + '.blink-node {' + + ' animation-name: blink;' + + ' animation-duration: var(--hterm-blink-node-duration);' + + ' animation-iteration-count: infinite;' + + ' animation-timing-function: ease-in-out;' + + ' animation-direction: alternate;' + '}'); this.document_.head.appendChild(style); - var styleSheets = this.document_.styleSheets; - var cssRules = styleSheets[styleSheets.length - 1].cssRules; - this.wcCssRule_ = cssRules[cssRules.length - 1]; - this.cursorNode_ = this.document_.createElement('div'); + this.cursorNode_.id = 'hterm:terminal-cursor'; this.cursorNode_.className = 'cursor-node'; this.cursorNode_.style.cssText = ('position: absolute;' + - 'top: -99px;' + + 'left: calc(var(--hterm-charsize-width) * var(--hterm-cursor-offset-col));' + + 'top: calc(var(--hterm-charsize-height) * var(--hterm-cursor-offset-row));' + 'display: block;' + - 'width: ' + this.scrollPort_.characterSize.width + 'px;' + - 'height: ' + this.scrollPort_.characterSize.height + 'px;' + + 'width: var(--hterm-charsize-width);' + + 'height: var(--hterm-charsize-height);' + '-webkit-transition: opacity, background-color 100ms linear;' + '-moz-transition: opacity, background-color 100ms linear;'); @@ -10735,6 +12541,7 @@ hterm.Terminal.prototype.decorate = function(div) { // // It's a hack, but it's the cleanest way I could find. this.scrollBlockerNode_ = this.document_.createElement('div'); + this.scrollBlockerNode_.id = 'hterm:mouse-drag-scroll-blocker'; this.scrollBlockerNode_.style.cssText = ('position: absolute;' + 'top: -99px;' + @@ -10743,7 +12550,6 @@ hterm.Terminal.prototype.decorate = function(div) { 'height: 10px;'); this.document_.body.appendChild(this.scrollBlockerNode_); - var onMouse = this.onMouse_.bind(this); this.scrollPort_.onScrollWheel = onMouse; ['mousedown', 'mouseup', 'mousemove', 'click', 'dblclick', ].forEach(function(event) { @@ -10764,6 +12570,8 @@ hterm.Terminal.prototype.decorate = function(div) { /** * Return the HTML document that contains the terminal DOM nodes. + * + * @return {HTMLDocument} */ hterm.Terminal.prototype.getDocument = function() { return this.document_; @@ -10787,7 +12595,7 @@ hterm.Terminal.prototype.focus = function() { * * @param {integer} index The zero-based row index, measured relative to the * start of the scrollback buffer. On-screen rows will always have the - * largest indicies. + * largest indices. * @return {HTMLElement} The 'x-row' element containing for the requested row. */ hterm.Terminal.prototype.getRowNode = function(index) { @@ -10807,7 +12615,7 @@ hterm.Terminal.prototype.getRowNode = function(index) { * * @param {integer} start The zero-based row index to start from, measured * relative to the start of the scrollback buffer. On-screen rows will - * always have the largest indicies. + * always have the largest indices. * @param {integer} end The zero-based row index to end on, measured * relative to the start of the scrollback buffer. * @return {string} A single string containing the text value of the range of @@ -10834,7 +12642,7 @@ hterm.Terminal.prototype.getRowsText = function(start, end) { * * @param {integer} index The zero-based row index to return, measured * relative to the start of the scrollback buffer. On-screen rows will - * always have the largest indicies. + * always have the largest indices. * @return {string} A string containing the text value of the selected row. */ hterm.Terminal.prototype.getRowText = function(index) { @@ -10869,6 +12677,8 @@ hterm.Terminal.prototype.getRowCount = function() { * be using moveRows() in cases where they would matter. * * The cursor will be positioned at column 0 of the first inserted line. + * + * @param {number} count The number of rows to created. */ hterm.Terminal.prototype.appendRows_ = function(count) { var cursorRow = this.screen_.rowsArray.length; @@ -10903,6 +12713,10 @@ hterm.Terminal.prototype.appendRows_ = function(count) { * In this case, the blank lines scrolled into the scroll region are made of * the nodes we scrolled off. These have their rowIndex properties carefully * renumbered so as not to confuse the ScrollPort. + * + * @param {number} fromIndex The start index. + * @param {number} count The number of rows to move. + * @param {number} toIndex The destination index. */ hterm.Terminal.prototype.moveRows_ = function(fromIndex, count, toIndex) { var ary = this.screen_.removeRows(fromIndex, count); @@ -10924,10 +12738,14 @@ hterm.Terminal.prototype.moveRows_ = function(fromIndex, count, toIndex) { /** * Renumber the rowIndex property of the given range of rows. * - * The start and end indicies are relative to the screen, not the scrollback. + * The start and end indices are relative to the screen, not the scrollback. * Rows in the scrollback buffer cannot be renumbered. Since they are not * addressable (you can't delete them, scroll them, etc), you should have * no need to renumber scrollback rows. + * + * @param {number} start The start index. + * @param {number} end The end index. + * @param {hterm.Screen} opt_screen The screen to renumber. */ hterm.Terminal.prototype.renumberRows_ = function(start, end, opt_screen) { var screen = opt_screen || this.screen_; @@ -10954,6 +12772,10 @@ hterm.Terminal.prototype.print = function(str) { var startOffset = 0; var strWidth = lib.wc.strWidth(str); + // Fun edge case: If the string only contains zero width codepoints (like + // combining characters), we make sure to iterate at least once below. + if (strWidth == 0 && str) + strWidth = 1; while (startOffset < strWidth) { if (this.options_.wraparound && this.screen_.cursorPosition.overflow) { @@ -10983,15 +12805,16 @@ hterm.Terminal.prototype.print = function(str) { var tokens = hterm.TextAttributes.splitWidecharString(substr); for (var i = 0; i < tokens.length; i++) { - if (tokens[i].wcNode) - this.screen_.textAttributes.wcNode = true; + this.screen_.textAttributes.wcNode = tokens[i].wcNode; + this.screen_.textAttributes.asciiNode = tokens[i].asciiNode; if (this.options_.insertMode) { - this.screen_.insertString(tokens[i].str); + this.screen_.insertString(tokens[i].str, tokens[i].wcStrWidth); } else { - this.screen_.overwriteString(tokens[i].str); + this.screen_.overwriteString(tokens[i].str, tokens[i].wcStrWidth); } this.screen_.textAttributes.wcNode = false; + this.screen_.textAttributes.asciiNode = true; } this.screen_.maybeClipCurrentRow(); @@ -11053,7 +12876,7 @@ hterm.Terminal.prototype.getVTScrollTop = function() { * restrict scrolling to some higher row. It is used for some VT cursor * positioning and scrolling commands. * - * @return {integer} The bottommost row in the terminal's scroll region. + * @return {integer} The bottom most row in the terminal's scroll region. */ hterm.Terminal.prototype.getVTScrollBottom = function() { if (this.vtScrollBottom_ != null) @@ -11146,7 +12969,8 @@ hterm.Terminal.prototype.reverseLineFeed = function() { hterm.Terminal.prototype.eraseToLeft = function() { var cursor = this.saveCursor(); this.setCursorColumn(0); - this.screen_.overwriteString(lib.f.getWhitespace(cursor.column + 1)); + const count = cursor.column + 1; + this.screen_.overwriteString(lib.f.getWhitespace(count), count); this.restoreCursor(cursor); }; @@ -11164,6 +12988,8 @@ hterm.Terminal.prototype.eraseToLeft = function() { * eraseToRight is ignored in the presence of a cursor overflow. This deviates * from xterm, but agrees with gnome-terminal and konsole, xfce4-terminal. See * crbug.com/232390 for details. + * + * @param {number} opt_count The number of characters to erase. */ hterm.Terminal.prototype.eraseToRight = function(opt_count) { if (this.screen_.cursorPosition.overflow) @@ -11184,7 +13010,7 @@ hterm.Terminal.prototype.eraseToRight = function(opt_count) { } var cursor = this.saveCursor(); - this.screen_.overwriteString(lib.f.getWhitespace(count)); + this.screen_.overwriteString(lib.f.getWhitespace(count), count); this.restoreCursor(cursor); this.clearCursorOverflow(); }; @@ -11256,7 +13082,7 @@ hterm.Terminal.prototype.fill = function(ch) { for (var row = 0; row < this.screenSize.height; row++) { for (var col = 0; col < this.screenSize.width; col++) { this.setAbsoluteCursorPosition(row, col); - this.screen_.overwriteString(ch); + this.screen_.overwriteString(ch, 1); } } @@ -11335,6 +13161,8 @@ hterm.Terminal.prototype.insertLines = function(count) { * * New rows are added to the bottom of scroll region to take their place. New * rows are strictly there to take up space and have no content or style. + * + * @param {number} count The number of lines to delete. */ hterm.Terminal.prototype.deleteLines = function(count) { var cursor = this.saveCursor(); @@ -11362,12 +13190,14 @@ hterm.Terminal.prototype.deleteLines = function(count) { * Inserts the given number of spaces at the current cursor position. * * The cursor position is not changed. + * + * @param {number} count The number of spaces to insert. */ hterm.Terminal.prototype.insertSpace = function(count) { var cursor = this.saveCursor(); var ws = lib.f.getWhitespace(count || 1); - this.screen_.insertString(ws); + this.screen_.insertString(ws, ws.length); this.screen_.maybeClipCurrentRow(); this.restoreCursor(cursor); @@ -11454,6 +13284,12 @@ hterm.Terminal.prototype.setCursorPosition = function(row, column) { } }; +/** + * Move the cursor relative to its current position. + * + * @param {number} row + * @param {number} column + */ hterm.Terminal.prototype.setRelativeCursorPosition = function(row, column) { var scrollTop = this.getVTScrollTop(); row = lib.f.clamp(row + scrollTop, scrollTop, this.getVTScrollBottom()); @@ -11461,6 +13297,12 @@ hterm.Terminal.prototype.setRelativeCursorPosition = function(row, column) { this.screen_.setCursorPosition(row, column); }; +/** + * Move the cursor to the specified position. + * + * @param {number} row + * @param {number} column + */ hterm.Terminal.prototype.setAbsoluteCursorPosition = function(row, column) { row = lib.f.clamp(row, 0, this.screenSize.height - 1); column = lib.f.clamp(column, 0, this.screenSize.width - 1); @@ -11502,7 +13344,7 @@ hterm.Terminal.prototype.setAbsoluteCursorRow = function(row) { * * @return {integer} The zero-based cursor row. */ -hterm.Terminal.prototype.getCursorRow = function(row) { +hterm.Terminal.prototype.getCursorRow = function() { return this.screen_.cursorPosition.row; }; @@ -11638,6 +13480,8 @@ hterm.Terminal.prototype.cursorRight = function(count) { * TODO(rginda): Test xterm to see if reverse is respected for text that has * been drawn with attributes that happen to coincide with the default * 'no-attribute' colors. My guess is probably not. + * + * @param {boolean} state The state to set. */ hterm.Terminal.prototype.setReverseVideo = function(state) { this.options_.reverseVideo = state; @@ -11661,7 +13505,7 @@ hterm.Terminal.prototype.ringBell = function() { var self = this; setTimeout(function() { - self.cursorNode_.style.backgroundColor = self.prefs_.get('cursor-color'); + self.restyleCursor_(); }, 200); // bellSquelchTimeout_ affects both audio and notification bells. @@ -11678,9 +13522,7 @@ hterm.Terminal.prototype.ringBell = function() { } if (this.desktopNotificationBell_ && !this.document_.hasFocus()) { - var n = new Notification( - lib.f.replaceVars(hterm.desktopNotificationTitle, - {'title': window.document.title || 'hterm'})); + var n = hterm.notify(); this.bellNotificationList_.push(n); // TODO: Should we try to raise the window here? n.onclick = function() { self.closeBellNotifications_(); }; @@ -11724,6 +13566,8 @@ hterm.Terminal.prototype.setInsertMode = function(state) { * If auto carriage return is on then a formfeed character is interpreted * as a newline, otherwise it's the same as a linefeed. The difference boils * down to whether or not the cursor column is reset. + * + * @param {boolean} state The state to set. */ hterm.Terminal.prototype.setAutoCarriageReturn = function(state) { this.options_.autoCarriageReturn = state; @@ -11872,7 +13716,7 @@ hterm.Terminal.prototype.syncCursorPosition_ = function() { if (cursorRowIndex > bottomRowIndex) { // Cursor is scrolled off screen, move it outside of the visible area. - this.cursorNode_.style.top = -this.scrollPort_.characterSize.height + 'px'; + this.setCssVar('cursor-offset-row', '-1'); return; } @@ -11882,16 +13726,18 @@ hterm.Terminal.prototype.syncCursorPosition_ = function() { this.cursorNode_.style.display = ''; } - - this.cursorNode_.style.top = this.scrollPort_.visibleRowTopMargin + - this.scrollPort_.characterSize.height * (cursorRowIndex - topRowIndex) + - 'px'; - this.cursorNode_.style.left = this.scrollPort_.characterSize.width * - this.screen_.cursorPosition.column + 'px'; + // Position the cursor using CSS variable math. If we do the math in JS, + // the float math will end up being more precise than the CSS which will + // cause the cursor tracking to be off. + this.setCssVar( + 'cursor-offset-row', + `${cursorRowIndex - topRowIndex} + ` + + `${this.scrollPort_.visibleRowTopMargin}px`); + this.setCssVar('cursor-offset-col', this.screen_.cursorPosition.column); this.cursorNode_.setAttribute('title', - '(' + this.screen_.cursorPosition.row + - ', ' + this.screen_.cursorPosition.column + + '(' + this.screen_.cursorPosition.column + + ', ' + this.screen_.cursorPosition.row + ')'); // Update the caret for a11y purposes. @@ -11914,11 +13760,9 @@ hterm.Terminal.prototype.restyleCursor_ = function() { var style = this.cursorNode_.style; - style.width = this.scrollPort_.characterSize.width + 'px'; - switch (shape) { case hterm.Terminal.cursorShape.BEAM: - style.height = this.scrollPort_.characterSize.height + 'px'; + style.height = 'var(--hterm-charsize-height)'; style.backgroundColor = 'transparent'; style.borderBottomStyle = null; style.borderLeftStyle = 'solid'; @@ -11933,7 +13777,7 @@ hterm.Terminal.prototype.restyleCursor_ = function() { break; default: - style.height = this.scrollPort_.characterSize.height + 'px'; + style.height = 'var(--hterm-charsize-height)'; style.backgroundColor = this.cursorColor_; style.borderBottomStyle = null; style.borderLeftStyle = null; @@ -11972,6 +13816,7 @@ hterm.Terminal.prototype.showZoomWarning_ = function(state) { return; this.zoomWarningNode_ = this.document_.createElement('div'); + this.zoomWarningNode_.id = 'hterm:zoom-warning'; this.zoomWarningNode_.style.cssText = ( 'color: black;' + 'background-color: #ff2222;' + @@ -11986,6 +13831,10 @@ hterm.Terminal.prototype.showZoomWarning_ = function(state) { '-webkit-user-select: none;' + '-moz-text-size-adjust: none;' + '-moz-user-select: none;'); + + this.zoomWarningNode_.addEventListener('click', function(e) { + this.parentNode.removeChild(this); + }); } this.zoomWarningNode_.textContent = lib.MessageManager.replaceReferences( @@ -12056,42 +13905,53 @@ hterm.Terminal.prototype.showOverlay = function(msg, opt_timeout) { this.overlayNode_.style.left = (divSize.width - overlaySize.width - this.scrollPort_.currentScrollbarWidthPx) / 2 + 'px'; - var self = this; - if (this.overlayTimeout_) clearTimeout(this.overlayTimeout_); if (opt_timeout === null) return; - this.overlayTimeout_ = setTimeout(function() { - self.overlayNode_.style.opacity = '0'; - self.overlayTimeout_ = setTimeout(function() { - if (self.overlayNode_.parentNode) - self.overlayNode_.parentNode.removeChild(self.overlayNode_); - self.overlayTimeout_ = null; - self.overlayNode_.style.opacity = '0.75'; - }, 200); - }, opt_timeout || 1500); + this.overlayTimeout_ = setTimeout(() => { + this.overlayNode_.style.opacity = '0'; + this.overlayTimeout_ = setTimeout(() => this.hideOverlay(), 200); + }, opt_timeout || 1500); +}; + +/** + * Hide the terminal overlay immediately. + * + * Useful when we show an overlay for an event with an unknown end time. + */ +hterm.Terminal.prototype.hideOverlay = function() { + if (this.overlayTimeout_) + clearTimeout(this.overlayTimeout_); + this.overlayTimeout_ = null; + + if (this.overlayNode_.parentNode) + this.overlayNode_.parentNode.removeChild(this.overlayNode_); + this.overlayNode_.style.opacity = '0.75'; }; /** * Paste from the system clipboard to the terminal. */ hterm.Terminal.prototype.paste = function() { - hterm.pasteFromClipboard(this.document_); + return hterm.pasteFromClipboard(this.document_); }; /** * Copy a string to the system clipboard. * * Note: If there is a selected range in the terminal, it'll be cleared. + * + * @param {string} str The string to copy. */ hterm.Terminal.prototype.copyStringToClipboard = function(str) { if (this.prefs_.get('enable-clipboard-notice')) setTimeout(this.showOverlay.bind(this, hterm.notifyCopyMessage, 500), 200); var copySource = this.document_.createElement('pre'); + copySource.id = 'hterm:copy-to-clipboard-source'; copySource.textContent = str; copySource.style.cssText = ( '-webkit-user-select: text;' + @@ -12121,6 +13981,11 @@ hterm.Terminal.prototype.copyStringToClipboard = function(str) { copySource.parentNode.removeChild(copySource); }; +/** + * Returns the selected text, or null if no text is selected. + * + * @return {string|null} + */ hterm.Terminal.prototype.getSelectionText = function() { var selection = this.scrollPort_.selection; selection.sync(); @@ -12152,7 +14017,7 @@ hterm.Terminal.prototype.getSelectionText = function() { // End offset measures from the end of the line. var endOffset = (hterm.TextAttributes.nodeWidth(selection.endNode) - selection.endOffset); - var node = selection.endNode; + node = selection.endNode; if (node.nodeName != 'X-ROW') { // If the selection doesn't end on an x-row node, then it must be @@ -12189,17 +14054,70 @@ hterm.Terminal.prototype.overlaySize = function() { this.showOverlay(this.screenSize.width + 'x' + this.screenSize.height); }; -/** - * Invoked by hterm.Terminal.Keyboard when a VT keystroke is detected. - * - * @param {string} string The VT string representing the keystroke, in UTF-16. - */ -hterm.Terminal.prototype.onVTKeystroke = function(string) { - if (this.scrollOnKeystroke_) - this.scrollPort_.scrollRowToBottom(this.getRowCount()); +/** + * Invoked by hterm.Terminal.Keyboard when a VT keystroke is detected. + * + * @param {string} string The VT string representing the keystroke, in UTF-16. + */ +hterm.Terminal.prototype.onVTKeystroke = function(string) { + if (this.scrollOnKeystroke_) + this.scrollPort_.scrollRowToBottom(this.getRowCount()); + + this.io.onVTKeystroke(this.keyboard.encode(string)); +}; + +/** + * Launches url in a new tab. + * + * @param {string} url URL to launch in a new tab. + */ +hterm.Terminal.prototype.openUrl = function(url) { + if (window.chrome && window.chrome.browser) { + // For Chrome v2 apps, we need to use this API to properly open windows. + chrome.browser.openTab({'url': url}); + } else { + var win = window.open(url, '_blank'); + win.focus(); + } +} + +/** + * Open the selected url. + */ +hterm.Terminal.prototype.openSelectedUrl_ = function() { + var str = this.getSelectionText(); + + // If there is no selection, try and expand wherever they clicked. + if (str == null) { + this.screen_.expandSelection(this.document_.getSelection()); + str = this.getSelectionText(); + + // If clicking in empty space, return. + if (str == null) + return; + } + + // Make sure URL is valid before opening. + if (str.length > 2048 || str.search(/[\s\[\](){}<>"'\\^`]/) >= 0) + return; + + // If the URI isn't anchored, it'll open relative to the extension. + // We have no way of knowing the correct schema, so assume http. + if (str.search('^[a-zA-Z][a-zA-Z0-9+.-]*://') < 0) { + // We have to whitelist a few protocols that lack authorities and thus + // never use the //. Like mailto. + switch (str.split(':', 1)[0]) { + case 'mailto': + break; + default: + str = 'http://' + str; + break; + } + } + + this.openUrl(str); +} - this.io.onVTKeystroke(this.keyboard.encode(string)); -}; /** * Add the terminalRow and terminalColumn properties to mouse events and @@ -12207,6 +14125,8 @@ hterm.Terminal.prototype.onVTKeystroke = function(string) { * * The terminalRow and terminalColumn properties contain the (row, column) * coordinates for the mouse event. + * + * @param {Event} e The mouse event to handle. */ hterm.Terminal.prototype.onMouse_ = function(e) { if (e.processedByTerminalHandler_) { @@ -12220,6 +14140,9 @@ hterm.Terminal.prototype.onMouse_ = function(e) { return; } + var reportMouseEvents = (!this.defeatMouseReports_ && + this.vt.mouseReport != this.vt.MOUSE_REPORT_DISABLED); + e.processedByTerminalHandler_ = true; // One based row/column stored on the mouse event. @@ -12233,8 +14156,7 @@ hterm.Terminal.prototype.onMouse_ = function(e) { return; } - if (this.options_.cursorVisible && - this.vt.mouseReport == this.vt.MOUSE_REPORT_DISABLED) { + if (this.options_.cursorVisible && !reportMouseEvents) { // If the cursor is visible and we're not sending mouse events to the // host app, then we want to hide the terminal cursor when the mouse // cursor is over top. This keeps the terminal cursor from interfering @@ -12248,32 +14170,47 @@ hterm.Terminal.prototype.onMouse_ = function(e) { } if (e.type == 'mousedown') { - if (e.altKey || this.vt.mouseReport == this.vt.MOUSE_REPORT_DISABLED) { + if (e.altKey || !reportMouseEvents) { // If VT mouse reporting is disabled, or has been defeated with // alt-mousedown, then the mouse will act on the local selection. - this.reportMouseEvents_ = false; + this.defeatMouseReports_ = true; this.setSelectionEnabled(true); } else { // Otherwise we defer ownership of the mouse to the VT. - this.reportMouseEvents_ = true; + this.defeatMouseReports_ = false; this.document_.getSelection().collapseToEnd(); this.setSelectionEnabled(false); e.preventDefault(); } } - if (!this.reportMouseEvents_) { - if (e.type == 'dblclick') { + if (!reportMouseEvents) { + if (e.type == 'dblclick' && this.copyOnSelect) { this.screen_.expandSelection(this.document_.getSelection()); - hterm.copySelectionToClipboard(this.document_); + this.copySelectionToClipboard(this.document_); + } + + if (e.type == 'click' && !e.shiftKey && (e.ctrlKey || e.metaKey)) { + // Debounce this event with the dblclick event. If you try to doubleclick + // a URL to open it, Chrome will fire click then dblclick, but we won't + // have expanded the selection text at the first click event. + clearTimeout(this.timeouts_.openUrl); + this.timeouts_.openUrl = setTimeout(this.openSelectedUrl_.bind(this), + 500); + return; } - if (e.type == 'mousedown' && e.which == this.mousePasteButton) - this.paste(); + if (e.type == 'mousedown') { + if ((this.mouseRightClickPaste && e.button == 2 /* right button */) || + e.button == this.mousePasteButton) { + if (!this.paste()) + console.warn('Could not paste manually due to web restrictions'); + } + } - if (e.type == 'mouseup' && e.which == 1 && this.copyOnSelect && + if (e.type == 'mouseup' && e.button == 0 && this.copyOnSelect && !this.document_.getSelection().isCollapsed) { - hterm.copySelectionToClipboard(this.document_); + this.copySelectionToClipboard(this.document_); } if ((e.type == 'mousemove' || e.type == 'mouseup') && @@ -12283,6 +14220,20 @@ hterm.Terminal.prototype.onMouse_ = function(e) { this.scrollBlockerNode_.style.top = '-99px'; } + // Emulate arrow key presses via scroll wheel events. + if (this.scrollWheelArrowKeys_ && !e.shiftKey && + this.keyboard.applicationCursor && !this.isPrimaryScreen()) { + if (e.type == 'wheel') { + var delta = this.scrollPort_.scrollWheelDelta(e); + var lines = lib.f.smartFloorDivide( + Math.abs(delta), this.scrollPort_.characterSize.height); + + var data = '\x1bO' + (delta < 0 ? 'B' : 'A'); + this.io.sendString(data.repeat(lines)); + + e.preventDefault(); + } + } } else /* if (this.reportMouseEvents) */ { if (!this.scrollBlockerNode_.engaged) { if (e.type == 'mousedown') { @@ -12306,8 +14257,7 @@ hterm.Terminal.prototype.onMouse_ = function(e) { // Restore this on mouseup in case it was temporarily defeated with a // alt-mousedown. Only do this when the selection is empty so that // we don't immediately kill the users selection. - this.reportMouseEvents_ = (this.vt.mouseReport != - this.vt.MOUSE_REPORT_DISABLED); + this.defeatMouseReports_ = false; } }; @@ -12316,15 +14266,24 @@ hterm.Terminal.prototype.onMouse_ = function(e) { * * The event parameter will be a normal DOM mouse click event with additional * 'terminalRow' and 'terminalColumn' properties. + * + * @param {Event} e The mouse event to handle. */ hterm.Terminal.prototype.onMouse = function(e) { }; /** * React when focus changes. + * + * @param {boolean} focused True if focused, false otherwise. */ hterm.Terminal.prototype.onFocusChange_ = function(focused) { this.cursorNode_.setAttribute('focus', focused); this.restyleCursor_(); + + if (this.reportFocus) { + this.io.sendString(focused === true ? '\x1b[I' : '\x1b[O') + } + if (focused === true) this.closeBellNotifications_(); }; @@ -12338,6 +14297,8 @@ hterm.Terminal.prototype.onScroll_ = function() { /** * React when text is pasted into the scrollPort. + * + * @param {Event} e The DOM paste event to handle. */ hterm.Terminal.prototype.onPaste_ = function(e) { var data = e.text.replace(/\n/mg, '\r'); @@ -12350,6 +14311,8 @@ hterm.Terminal.prototype.onPaste_ = function(e) { /** * React when the user tries to copy from the scrollPort. + * + * @param {Event} e The DOM copy event. */ hterm.Terminal.prototype.onCopy_ = function(e) { if (!this.useDefaultWindowCopy) { @@ -12368,14 +14331,16 @@ hterm.Terminal.prototype.onCopy_ = function(e) { */ hterm.Terminal.prototype.onResize_ = function() { var columnCount = Math.floor(this.scrollPort_.getScreenWidth() / - this.scrollPort_.characterSize.width); + this.scrollPort_.characterSize.width) || 0; var rowCount = lib.f.smartFloorDivide(this.scrollPort_.getScreenHeight(), - this.scrollPort_.characterSize.height); + this.scrollPort_.characterSize.height) || 0; if (columnCount <= 0 || rowCount <= 0) { // We avoid these situations since they happen sometimes when the terminal // gets removed from the document or during the initial load, and we can't // deal with that. + // This can also happen if called before the scrollPort calculates the + // character size, meaning we dived by 0 above and default to 0 values. return; } @@ -12431,11 +14396,11 @@ hterm.Terminal.prototype.setScrollbarVisible = function(state) { /** * Set the scroll wheel move multiplier. This will affect how fast the page - * scrolls on mousewheel events. + * scrolls on wheel events. * * Defaults to 1. * - * @param {number} multiplier. + * @param {number} multiplier The multiplier to set. */ hterm.Terminal.prototype.setScrollWheelMoveMultipler = function(multiplier) { this.scrollPort_.setScrollWheelMoveMultipler(multiplier); @@ -12485,6 +14450,9 @@ hterm.Terminal.IO = function(terminal) { // The IO object to restore on IO.pop(). this.previousIO_ = null; + + // Any data this object accumulated while not active. + this.buffered_ = ''; }; /** @@ -12504,6 +14472,15 @@ hterm.Terminal.IO.prototype.showOverlay = function(message, opt_timeout) { this.terminal_.showOverlay(message, opt_timeout); }; +/** + * Hide the current overlay immediately. + * + * Useful when we show an overlay for an event with an unknown end time. + */ +hterm.Terminal.IO.prototype.hideOverlay = function() { + this.terminal_.hideOverlay(); +}; + /** * Open an frame in the current terminal window, pointed to the specified * url. @@ -12549,9 +14526,25 @@ hterm.Terminal.IO.prototype.push = function() { /** * Restore the Terminal's previous IO object. + * + * We'll flush out any queued data. */ hterm.Terminal.IO.prototype.pop = function() { this.terminal_.io = this.previousIO_; + this.previousIO_.flush(); +}; + +/** + * Flush accumulated data. + * + * If we're not the active IO, the connected process might still be writing + * data to us, but we won't be displaying it. Flush any buffered data now. + */ +hterm.Terminal.IO.prototype.flush = function() { + if (this.buffered_) { + this.terminal_.interpret(this.buffered_); + this.buffered_ = ''; + } }; /** @@ -12610,8 +14603,13 @@ hterm.Terminal.IO.prototype.onTerminalResize = function(width, height) { * @param {string} string The UTF-8 encoded string to print. */ hterm.Terminal.IO.prototype.writeUTF8 = function(string) { - if (this.terminal_.io != this) - throw 'Attempt to print from inactive IO object.'; + // If another process has the foreground IO, buffer new data sent to this IO + // (since it's in the background). When we're made the foreground IO again, + // we'll flush everything. + if (this.terminal_.io != this) { + this.buffered_ += string; + return; + } this.terminal_.interpret(string); }; @@ -12622,10 +14620,7 @@ hterm.Terminal.IO.prototype.writeUTF8 = function(string) { * @param {string} string The UTF-8 encoded string to print. */ hterm.Terminal.IO.prototype.writelnUTF8 = function(string) { - if (this.terminal_.io != this) - throw 'Attempt to print from inactive IO object.'; - - this.terminal_.interpret(string + '\r\n'); + this.writeUTF8(string + '\r\n'); }; /** @@ -12687,6 +14682,9 @@ hterm.TextAttributes = function(document) { this.defaultForeground = 'rgb(255, 255, 255)'; this.defaultBackground = 'rgb(0, 0, 0)'; + // Any attributes added here that do not default to falsey (e.g. undefined or + // null) require a bit more care. createContainer has to always attach the + // attribute so matchesContainer can work correctly. this.bold = false; this.faint = false; this.italic = false; @@ -12696,6 +14694,7 @@ hterm.TextAttributes = function(document) { this.inverse = false; this.invisible = false; this.wcNode = false; + this.asciiNode = true; this.tileData = null; this.colorPalette = null; @@ -12720,7 +14719,7 @@ hterm.TextAttributes.prototype.enableBoldAsBright = true; /** * A sentinel constant meaning "whatever the default color is in this context". */ -hterm.TextAttributes.prototype.DEFAULT_COLOR = new String(''); +hterm.TextAttributes.prototype.DEFAULT_COLOR = lib.f.createEnum(''); /** * A constant string used to specify that source color is context default. @@ -12779,6 +14778,7 @@ hterm.TextAttributes.prototype.reset = function() { this.inverse = false; this.invisible = false; this.wcNode = false; + this.asciiNode = true; }; /** @@ -12806,6 +14806,7 @@ hterm.TextAttributes.prototype.isDefault = function() { !this.inverse && !this.invisible && !this.wcNode && + this.asciiNode && this.tileData == null); }; @@ -12825,11 +14826,17 @@ hterm.TextAttributes.prototype.isDefault = function() { * attributes. */ hterm.TextAttributes.prototype.createContainer = function(opt_textContent) { - if (this.isDefault()) - return this.document_.createTextNode(opt_textContent); + if (this.isDefault()) { + // Only attach attributes where we need an explicit default for the + // matchContainer logic below. + const node = this.document_.createTextNode(opt_textContent); + node.asciiNode = true; + return node; + } var span = this.document_.createElement('span'); var style = span.style; + var classes = []; if (this.foreground != this.DEFAULT_COLOR) style.color = this.foreground; @@ -12846,8 +14853,10 @@ hterm.TextAttributes.prototype.createContainer = function(opt_textContent) { if (this.italic) style.fontStyle = 'italic'; - if (this.blink) - style.fontStyle = 'italic'; + if (this.blink) { + classes.push('blink-node'); + span.blinkNode = true; + } var textDecoration = ''; if (this.underline) { @@ -12863,19 +14872,23 @@ hterm.TextAttributes.prototype.createContainer = function(opt_textContent) { } if (this.wcNode) { - span.className = 'wc-node'; + classes.push('wc-node'); span.wcNode = true; } + span.asciiNode = this.asciiNode; if (this.tileData != null) { - // This could be a wcNode too, so we add to the className here. - span.className += ' tile tile_' + this.tileData; + classes.push('tile'); + classes.push('tile_' + this.tileData); span.tileNode = true; } if (opt_textContent) span.textContent = opt_textContent; + if (classes.length) + span.className = classes.join(' '); + return span; }; @@ -12893,19 +14906,24 @@ hterm.TextAttributes.prototype.createContainer = function(opt_textContent) { * this attributes instance. */ hterm.TextAttributes.prototype.matchesContainer = function(obj) { - if (typeof obj == 'string' || obj.nodeType == 3) + if (typeof obj == 'string' || obj.nodeType == Node.TEXT_NODE) return this.isDefault(); var style = obj.style; // We don't want to put multiple characters in a wcNode or a tile. // See the comments in createContainer. + // For attributes that default to false, we do not require that obj have them + // declared, so always normalize them using !! (to turn undefined into false) + // in the compares below. return (!(this.wcNode || obj.wcNode) && + this.asciiNode == obj.asciiNode && !(this.tileData != null || obj.tileNode) && this.foreground == style.color && this.background == style.backgroundColor && (this.enableBold && this.bold) == !!style.fontWeight && - (this.blink || this.italic) == !!style.fontStyle && + this.blink == !!obj.blinkNode && + this.italic == !!style.fontStyle && !!this.underline == !!obj.underline && !!this.strikethrough == !!obj.strikethrough); }; @@ -12999,7 +15017,7 @@ hterm.TextAttributes.containersMatch = function(obj1, obj2) { if (obj1.nodeType != obj2.nodeType) return false; - if (obj1.nodeType == 3) + if (obj1.nodeType == Node.TEXT_NODE) return true; var style1 = obj1.style; @@ -13021,7 +15039,7 @@ hterm.TextAttributes.containersMatch = function(obj1, obj2) { * @return {boolean} True if the object is unstyled. */ hterm.TextAttributes.containerIsDefault = function(obj) { - return typeof obj == 'string' || obj.nodeType == 3; + return typeof obj == 'string' || obj.nodeType == Node.TEXT_NODE; }; /** @@ -13032,7 +15050,7 @@ hterm.TextAttributes.containerIsDefault = function(obj) { * @return {integer} The column width of the node's textContent. */ hterm.TextAttributes.nodeWidth = function(node) { - if (node.wcNode) { + if (!node.asciiNode) { return lib.wc.strWidth(node.textContent); } else { return node.textContent.length; @@ -13050,7 +15068,7 @@ hterm.TextAttributes.nodeWidth = function(node) { * @return {integer} The extracted substr of the node's textContent. */ hterm.TextAttributes.nodeSubstr = function(node, start, width) { - if (node.wcNode) { + if (!node.asciiNode) { return lib.wc.substr(node.textContent, start, width); } else { return node.textContent.substr(start, width); @@ -13068,12 +15086,12 @@ hterm.TextAttributes.nodeSubstr = function(node, start, width) { * @return {integer} The extracted substring of the node's textContent. */ hterm.TextAttributes.nodeSubstring = function(node, start, end) { - if (node.wcNode) { + if (!node.asciiNode) { return lib.wc.substring(node.textContent, start, end); } else { return node.textContent.substring(start, end); } -} +}; /** * Static method to split a string into contiguous runs of single-width @@ -13082,32 +15100,62 @@ hterm.TextAttributes.nodeSubstring = function(node, start, end) { * @param {string} str The string to split. * @return {Array} An array of objects that contain substrings of str, where * each substring is either a contiguous runs of single-width characters - * or a double-width character. For object that contains a double-width - * character, its wcNode property is set to true. + * or a double-width character. For objects that contain a double-width + * character, its wcNode property is set to true. For objects that contain + * only ASCII content, its asciiNode property is set to true. */ hterm.TextAttributes.splitWidecharString = function(str) { var rv = []; - var base = 0, length = 0; - - for (var i = 0; i < str.length; i++) { - var c = str.charCodeAt(i); - if (c < 128 || lib.wc.charWidth(c) == 1) { - length++; + var base = 0, length = 0, wcStrWidth = 0, wcCharWidth; + var asciiNode = true; + + for (var i = 0; i < str.length;) { + var c = str.codePointAt(i); + var increment; + if (c < 128) { + wcStrWidth += 1; + length += 1; + increment = 1; } else { - if (length) { - rv.push({str: str.substr(base, length)}); + increment = (c <= 0xffff) ? 1 : 2; + wcCharWidth = lib.wc.charWidth(c); + if (wcCharWidth <= 1) { + wcStrWidth += wcCharWidth; + length += increment; + asciiNode = false; + } else { + if (length) { + rv.push({ + str: str.substr(base, length), + asciiNode: asciiNode, + wcStrWidth: wcStrWidth, + }); + asciiNode = true; + wcStrWidth = 0; + } + rv.push({ + str: str.substr(i, increment), + wcNode: true, + asciiNode: false, + wcStrWidth: 2, + }); + base = i + increment; + length = 0; } - rv.push({str: str.substr(i, 1), wcNode: true}); - base = i + 1; - length = 0; } + i += increment; } - if (length) - rv.push({str: str.substr(base, length)}); + if (length) { + rv.push({ + str: str.substr(base, length), + asciiNode: asciiNode, + wcStrWidth: wcStrWidth, + }); + } return rv; -} +}; // SOURCE FILE: hterm/js/hterm_vt.js // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -13127,24 +15175,7 @@ lib.rtdep('lib.colors', 'lib.f', 'lib.UTF8Decoder', * This interpreter is intended to be compatible with xterm, though it * ignores some of the more esoteric escape sequences. * - * Some sequences are marked "Will not implement", meaning that they aren't - * considered relevant to hterm and will probably never be implemented. - * - * Others are marked "Not currently implemented", meaning that they are lower - * priority items that may be useful to implement at some point. - * - * See also: - * [VT100] VT100 User Guide - * http://vt100.net/docs/vt100-ug/chapter3.html - * [VT510] VT510 Video Terminal Programmer Information - * http://vt100.net/docs/vt510-rm/contents - * [XTERM] Xterm Control Sequences - * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html - * [CTRL] Wikipedia: C0 and C1 Control Codes - * http://en.wikipedia.org/wiki/C0_and_C1_control_codes - * [CSI] Wikipedia: ANSI Escape Code - * http://en.wikipedia.org/wiki/Control_Sequence_Introducer - * man 5 terminfo, man infocmp, infocmp -L xterm-new + * Control sequences are documented in hterm/doc/ControlSequences.md. * * @param {hterm.Terminal} terminal Terminal to use with the interpreter. */ @@ -13176,15 +15207,6 @@ hterm.VT = function(terminal) { // The amount of time we're willing to wait for the end of an OSC sequence. this.oscTimeLimit_ = 20000; - // Construct a regular expression to match the known one-byte control chars. - // This is used in parseUnknown_ to quickly scan a string for the next - // control character. - var cc1 = Object.keys(hterm.VT.CC1).map( - function(e) { - return '\\x' + lib.f.zpad(e.charCodeAt().toString(16), 2) - }).join(''); - this.cc1Pattern_ = new RegExp('[' + cc1 + ']'); - // Decoder to maintain UTF-8 decode state. this.utf8Decoder_ = new lib.UTF8Decoder(); @@ -13229,16 +15251,28 @@ hterm.VT = function(terminal) { /** * If true, emit warnings when we encounter a control character or escape * sequence that we don't recognize or explicitly ignore. + * + * We disable this by default as the console logging can be expensive when + * dumping binary files (e.g. `cat /dev/zero`) to the point where you can't + * recover w/out restarting. */ - this.warnUnimplemented = true; + this.warnUnimplemented = false; + + /** + * The set of available character maps (used by G0...G3 below). + */ + this.characterMaps = new hterm.VT.CharacterMaps(); /** * The default G0...G3 character maps. + * We default to the US/ASCII map everywhere as that aligns with other + * terminals, and it makes it harder to accidentally switch to the graphics + * character map (Ctrl-N). Any program that wants to use the graphics map + * will usually select it anyways since there's no guarantee what state any + * of the maps are in at any particular time. */ - this.G0 = hterm.VT.CharacterMap.maps['B']; - this.G1 = hterm.VT.CharacterMap.maps['0']; - this.G2 = hterm.VT.CharacterMap.maps['B']; - this.G3 = hterm.VT.CharacterMap.maps['B']; + this.G0 = this.G1 = this.G2 = this.G3 = + this.characterMaps.getMap('B'); /** * The 7-bit visible character set. @@ -13258,6 +15292,21 @@ hterm.VT = function(terminal) { */ this.GR = 'G0'; + /** + * The current encoding of the terminal. + * + * We only support ECMA-35 and UTF-8, so go with a boolean here. + * The encoding can be locked too. + */ + this.codingSystemUtf8_ = false; + this.codingSystemLocked_ = false; + + // Construct a regular expression to match the known one-byte control chars. + // This is used in parseUnknown_ to quickly scan a string for the next + // control character. + this.cc1Pattern_ = null; + this.updateEncodingState_(); + // Saved state used in DECSC. // // This is a place to store a copy VT state, it is *not* the active state. @@ -13340,7 +15389,7 @@ hterm.VT.ParseState.prototype.resetArguments = function(opt_arg_zero) { /** * Get an argument as an integer. * - * @param {number} argnum The argument number to retreive. + * @param {number} argnum The argument number to retrieve. */ hterm.VT.ParseState.prototype.iarg = function(argnum, defaultValue) { var str = this.args[argnum]; @@ -13355,7 +15404,7 @@ hterm.VT.ParseState.prototype.iarg = function(argnum, defaultValue) { }; /** - * Advance the parse postion. + * Advance the parse position. * * @param {integer} count The number of bytes to advance. */ @@ -13434,10 +15483,10 @@ hterm.VT.CursorState.prototype.restore = function() { }; hterm.VT.prototype.reset = function() { - this.G0 = hterm.VT.CharacterMap.maps['B']; - this.G1 = hterm.VT.CharacterMap.maps['0']; - this.G2 = hterm.VT.CharacterMap.maps['B']; - this.G3 = hterm.VT.CharacterMap.maps['B']; + this.G0 = this.characterMaps.getMap('B'); + this.G1 = this.characterMaps.getMap('0'); + this.G2 = this.characterMaps.getMap('B'); + this.G3 = this.characterMaps.getMap('B'); this.GL = 'G0'; this.GR = 'G0'; @@ -13475,9 +15524,9 @@ hterm.VT.prototype.onTerminalMouse_ = function(e) { var y = String.fromCharCode(lib.f.clamp(e.terminalRow + 32, 32, 255)); switch (e.type) { - case 'mousewheel': + case 'wheel': // Mouse wheel is treated as button 1 or 2 plus an additional 64. - b = ((e.wheelDeltaY > 0) ? 0 : 1) + 96; + b = (((e.deltaY * -1) > 0) ? 0 : 1) + 96; b |= mod; response = '\x1b[M' + String.fromCharCode(b) + x + y; @@ -13487,7 +15536,7 @@ hterm.VT.prototype.onTerminalMouse_ = function(e) { case 'mousedown': // Buttons are encoded as button number plus 32. - var b = Math.min(e.which - 1, 2) + 32; + var b = Math.min(e.button, 2) + 32; // And mix in the modifier keys. b |= mod; @@ -13501,9 +15550,27 @@ hterm.VT.prototype.onTerminalMouse_ = function(e) { break; case 'mousemove': - if (this.mouseReport == this.MOUSE_REPORT_DRAG && e.which) { - // Standard button bits. - b = 32 + Math.min(e.which - 1, 2); + if (this.mouseReport == this.MOUSE_REPORT_DRAG && e.buttons) { + // Standard button bits. The XTerm protocol only reports the first + // button press (e.g. if left & right are pressed, right is ignored), + // and it only supports the first three buttons. If none of them are + // pressed, then XTerm flags it as a release. We'll do the same. + b = 32; + + // Priority here matches XTerm: left, middle, right. + if (e.buttons & 0x1) { + // Report left button. + b += 0; + } else if (e.buttons & 0x4) { + // Report middle button. + b += 1; + } else if (e.buttons & 0x2) { + // Report right button. + b += 2; + } else { + // Release higher buttons. + b += 3; + } // Add 32 to indicate mouse motion. b += 32; @@ -13565,7 +15632,7 @@ hterm.VT.prototype.decode = function(str) { /** * Encode a UTF-16 string as UTF-8. * - * See also: http://en.wikipedia.org/wiki/UTF-16 + * See also: https://en.wikipedia.org/wiki/UTF-16 */ hterm.VT.prototype.encodeUTF8 = function(str) { return lib.encodeUTF8(str); @@ -13578,6 +15645,46 @@ hterm.VT.prototype.decodeUTF8 = function(str) { return this.utf8Decoder_.decode(str); }; +/** + * Set the encoding of the terminal. + * + * @param {string} encoding The name of the encoding to set. + */ +hterm.VT.prototype.setEncoding = function(encoding) { + switch (encoding) { + default: + console.warn('Invalid value for "terminal-encoding": ' + encoding); + // Fall through. + case 'iso-2022': + this.codingSystemUtf8_ = false; + this.codingSystemLocked_ = false; + break; + case 'utf-8-locked': + this.codingSystemUtf8_ = true; + this.codingSystemLocked_ = true; + break; + case 'utf-8': + this.codingSystemUtf8_ = true; + this.codingSystemLocked_ = false; + break; + } + + this.updateEncodingState_(); +}; + +/** + * Refresh internal state when the encoding changes. + */ +hterm.VT.prototype.updateEncodingState_ = function() { + // If we're in UTF8 mode, don't suport 8-bit escape sequences as we'll never + // see those -- everything should be UTF8! + var cc1 = Object.keys(hterm.VT.CC1) + .filter((e) => !this.codingSystemUtf8_ || e.charCodeAt() < 0x80) + .map((e) => '\\x' + lib.f.zpad(e.charCodeAt().toString(16), 2)) + .join(''); + this.cc1Pattern_ = new RegExp(`[${cc1}]`); +}; + /** * The default parse function. * @@ -13589,12 +15696,9 @@ hterm.VT.prototype.parseUnknown_ = function(parseState) { var self = this; function print(str) { - if (self[self.GL].GL) + if (!self.codingSystemUtf8_ && self[self.GL].GL) str = self[self.GL].GL(str); - if (self[self.GR].GR) - str = self[self.GR].GR(str); - self.terminal.print(str); }; @@ -13637,7 +15741,7 @@ hterm.VT.prototype.parseCSI_ = function(parseState) { parseState.resetParseFunction(); } else if (ch == ';') { - // Parameter delimeter. + // Parameter delimiter. if (this.trailingModifier_) { // Parameter delimiter after the trailing modifier. That's a paddlin'. parseState.resetParseFunction(); @@ -13703,15 +15807,37 @@ hterm.VT.prototype.parseCSI_ = function(parseState) { */ hterm.VT.prototype.parseUntilStringTerminator_ = function(parseState) { var buf = parseState.peekRemainingBuf(); - var nextTerminator = buf.search(/(\x1b\\|\x07)/); var args = parseState.args; + // Since we might modify parse state buffer locally, if we want to advance + // the parse state buffer later on, we need to know how many chars we added. + let bufInserted = 0; if (!args.length) { args[0] = ''; args[1] = new Date(); + } else { + // If our saved buffer ends with an escape, it's because we were hoping + // it's an ST split across two buffers. Move it from our saved buffer + // to the start of our current buffer for processing anew. + if (args[0].slice(-1) == '\x1b') { + args[0] = args[0].slice(0, -1); + buf = '\x1b' + buf; + bufInserted = 1; + } } - if (nextTerminator == -1) { + const nextTerminator = buf.search(/[\x1b\x07]/); + const terminator = buf[nextTerminator]; + let foundTerminator; + + // If the next escape we see is not a start of a ST, fall through. This will + // either be invalid (embedded escape), or we'll queue it up (wait for \\). + if (terminator == '\x1b' && buf[nextTerminator + 1] != '\\') + foundTerminator = false; + else + foundTerminator = (nextTerminator != -1); + + if (!foundTerminator) { // No terminator here, have to wait for the next string. args[0] += buf; @@ -13721,20 +15847,24 @@ hterm.VT.prototype.parseUntilStringTerminator_ = function(parseState) { if (args[0].length > this.maxStringSequence) abortReason = 'too long: ' + args[0].length; - if (args[0].indexOf('\x1b') != -1) - abortReason = 'embedded escape: ' + args[0].indexOf('\x1b'); + // Special case: If our buffering happens to split the ST (\e\\), we have to + // buffer the content temporarily. So don't reject a trailing escape here, + // instead we let it timeout or be rejected in the next pass. + if (terminator == '\x1b' && nextTerminator != buf.length - 1) + abortReason = 'embedded escape: ' + nextTerminator; if (new Date() - args[1] > this.oscTimeLimit_) - abortReason = 'timeout expired: ' + new Date() - args[1]; + abortReason = 'timeout expired: ' + (new Date() - args[1]); if (abortReason) { - console.log('parseUntilStringTerminator_: aborting: ' + abortReason, - args[0]); + if (this.warnUnimplemented) + console.log('parseUntilStringTerminator_: aborting: ' + abortReason, + args[0]); parseState.reset(args[0]); return false; } - parseState.advance(buf.length); + parseState.advance(buf.length - bufInserted); return true; } @@ -13748,7 +15878,7 @@ hterm.VT.prototype.parseUntilStringTerminator_ = function(parseState) { parseState.resetParseFunction(); parseState.advance(nextTerminator + - (buf.substr(nextTerminator, 1) == '\x1b' ? 2 : 1)); + (terminator == '\x1b' ? 2 : 1) - bufInserted); return true; }; @@ -13792,18 +15922,12 @@ hterm.VT.prototype.dispatch = function(type, code, parseState) { * * Invoked in response to SM/RM. * - * Expected values for code: - * 2 - Keyboard Action Mode (AM). Will not implement. - * 4 - Insert Mode (IRM). - * 12 - Send/receive (SRM). Will not implement. - * 20 - Automatic Newline (LNM). - * * Unexpected and unimplemented values are silently ignored. */ hterm.VT.prototype.setANSIMode = function(code, state) { - if (code == '4') { + if (code == 4) { // Insert Mode (IRM) this.terminal.setInsertMode(state); - } else if (code == '20') { + } else if (code == 20) { // Automatic Newline (LNM) this.terminal.setAutoCarriageReturn(state); } else if (this.warnUnimplemented) { console.warn('Unimplemented ANSI Mode: ' + code); @@ -13814,76 +15938,14 @@ hterm.VT.prototype.setANSIMode = function(code, state) { * Set or reset one of the DEC Private modes. * * Invoked in response to DECSET/DECRST. - * - * Expected values for code: - * 1 - Application Cursor Keys (DECCKM). - * 2 - [!] Designate USASCII for character sets G0-G3 (DECANM), and set - * VT100 mode. - * 3 - 132 Column Mode (DECCOLM). - * 4 - [x] Smooth (Slow) Scroll (DECSCLM). - * 5 - Reverse Video (DECSCNM). - * 6 - Origin Mode (DECOM). - * 7 - Wraparound Mode (DECAWM). - * 8 - [x] Auto-repeat Keys (DECARM). - * 9 - [!] Send Mouse X & Y on button press. - * 10 - [x] Show toolbar (rxvt). - * 12 - Start Blinking Cursor (att610). - * 18 - [!] Print form feed (DECPFF). - * 19 - [x] Set print extent to full screen (DECPEX). - * 25 - Show Cursor (DECTCEM). - * 30 - [!] Show scrollbar (rxvt). - * 35 - [x] Enable font-shifting functions (rxvt). - * 38 - [x] Enter Tektronix Mode (DECTEK). - * 40 - Allow 80 - 132 Mode. - * 41 - [!] more(1) fix (see curses resource). - * 42 - [!] Enable Nation Replacement Character sets (DECNRCM). - * 44 - [!] Turn On Margin Bell. - * 45 - Reverse-wraparound Mode. - * 46 - [x] Start Logging. - * 47 - [!] Use Alternate Screen Buffer. - * 66 - [!] Application keypad (DECNKM). - * 67 - Backarrow key sends backspace (DECBKM). - * 1000 - Send Mouse X & Y on button press and release. (MOUSE_REPORT_CLICK) - * 1001 - [!] Use Hilite Mouse Tracking. - * 1002 - Use Cell Motion Mouse Tracking. (MOUSE_REPORT_DRAG) - * 1003 - [!] Use All Motion Mouse Tracking. - * 1004 - [!] Send FocusIn/FocusOut events. - * 1005 - [!] Enable Extended Mouse Mode. - * 1010 - Scroll to bottom on tty output (rxvt). - * 1011 - Scroll to bottom on key press (rxvt). - * 1034 - [x] Interpret "meta" key, sets eighth bit. - * 1035 - [x] Enable special modifiers for Alt and NumLock keys. - * 1036 - Send ESC when Meta modifies a key. - * 1037 - [!] Send DEL from the editing-keypad Delete key. - * 1039 - Send ESC when Alt modifies a key. - * 1040 - [x] Keep selection even if not highlighted. - * 1041 - [x] Use the CLIPBOARD selection. - * 1042 - [!] Enable Urgency window manager hint when Control-G is received. - * 1043 - [!] Enable raising of the window when Control-G is received. - * 1047 - [!] Use Alternate Screen Buffer. - * 1048 - Save cursor as in DECSC. - * 1049 - Save cursor as in DECSC and use Alternate Screen Buffer, clearing - * it first. (This may be disabled by the titeInhibit resource). This - * combines the effects of the 1047 and 1048 modes. Use this with - * terminfo-based applications rather than the 47 mode. - * 1050 - [!] Set terminfo/termcap function-key mode. - * 1051 - [x] Set Sun function-key mode. - * 1052 - [x] Set HP function-key mode. - * 1053 - [x] Set SCO function-key mode. - * 1060 - [x] Set legacy keyboard emulation (X11R6). - * 1061 - [!] Set VT220 keyboard emulation. - * 2004 - Set bracketed paste mode. - * - * [!] - Not currently implemented, may be in the future. - * [x] - Will not implement. */ hterm.VT.prototype.setDECMode = function(code, state) { - switch (code) { - case '1': // DECCKM + switch (parseInt(code, 10)) { + case 1: // DECCKM this.terminal.keyboard.applicationCursor = state; break; - case '3': // DECCOLM + case 3: // DECCOLM if (this.allowColumnWidthChanges_) { this.terminal.setWidth(state ? 132 : 80); @@ -13892,62 +15954,72 @@ hterm.VT.prototype.setDECMode = function(code, state) { } break; - case '5': // DECSCNM + case 5: // DECSCNM this.terminal.setReverseVideo(state); break; - case '6': // DECOM + case 6: // DECOM this.terminal.setOriginMode(state); break; - case '7': // DECAWM + case 7: // DECAWM this.terminal.setWraparound(state); break; - case '12': // att610 + case 12: // Start blinking cursor if (this.enableDec12) this.terminal.setCursorBlink(state); break; - case '25': // DECTCEM + case 25: // DECTCEM this.terminal.setCursorVisible(state); break; - case '40': // no-spec + case 30: // Show scrollbar + this.terminal.setScrollbarVisible(state); + break; + + case 40: // Allow 80 - 132 (DECCOLM) Mode this.terminal.allowColumnWidthChanges_ = state; break; - case '45': // no-spec + case 45: // Reverse-wraparound Mode this.terminal.setReverseWraparound(state); break; - case '67': // DECBKM + case 67: // Backarrow key sends backspace (DECBKM) this.terminal.keyboard.backspaceSendsBackspace = state; break; - case '1000': // Report on mouse clicks only. + case 1000: // Report on mouse clicks only. this.mouseReport = ( state ? this.MOUSE_REPORT_CLICK : this.MOUSE_REPORT_DISABLED); + this.terminal.syncMouseStyle(); break; - case '1002': // Report on mouse clicks and drags + case 1002: // Report on mouse clicks and drags this.mouseReport = ( state ? this.MOUSE_REPORT_DRAG : this.MOUSE_REPORT_DISABLED); + this.terminal.syncMouseStyle(); + break; + + case 1004: // Report on window focus change. + this.terminal.reportFocus = state; break; - case '1010': // rxvt + case 1010: // Scroll to bottom on tty output this.terminal.scrollOnOutput = state; break; - case '1011': // rxvt + case 1011: // Scroll to bottom on key press this.terminal.scrollOnKeystroke = state; break; - case '1036': // no-spec + case 1036: // Send ESC when Meta modifies a key this.terminal.keyboard.metaSendsEscape = state; break; - case '1039': // no-spec + case 1039: // Send ESC when Alt modifies a key if (state) { if (!this.terminal.keyboard.previousAltSendsWhat_) { this.terminal.keyboard.previousAltSendsWhat_ = @@ -13961,15 +16033,15 @@ hterm.VT.prototype.setDECMode = function(code, state) { } break; - case '47': - case '1047': // no-spec + case 47: // Use Alternate Screen Buffer + case 1047: this.terminal.setAlternateMode(state); break; - case '1048': // Save cursor as in DECSC. + case 1048: // Save cursor as in DECSC. this.savedState_.save(); - case '1049': // 1047 + 1048 + clear. + case 1049: // 1047 + 1048 + clear. if (state) { this.savedState_.save(); this.terminal.setAlternateMode(state); @@ -13981,7 +16053,7 @@ hterm.VT.prototype.setDECMode = function(code, state) { break; - case '2004': // Bracketed paste mode. + case 2004: // Bracketed paste mode. this.terminal.setBracketedPaste(state); break; @@ -14043,7 +16115,7 @@ hterm.VT.VT52 = {}; * * Silently ignored. */ -hterm.VT.CC1['\x00'] = function () {}; +hterm.VT.CC1['\x00'] = hterm.VT.ignore; /** * Enquiry (ENQ). @@ -14104,9 +16176,7 @@ hterm.VT.CC1['\x0b'] = hterm.VT.CC1['\x0a']; * * Interpreted as LF. */ -hterm.VT.CC1['\x0c'] = function() { - this.terminal.formFeed(); -}; +hterm.VT.CC1['\x0c'] = hterm.VT.CC1['\x0a']; /** * Carriage Return (CR). @@ -14162,6 +16232,11 @@ hterm.VT.CC1['\x13'] = hterm.VT.ignore; * It also causes the error character to be displayed. */ hterm.VT.CC1['\x18'] = function(parseState) { + // If we've shifted in the G1 character set, shift it back out to + // the default character set. + if (this.GL == 'G1') { + this.GL = 'G0'; + } parseState.resetParseFunction(); this.terminal.print('?'); }; @@ -14273,7 +16348,7 @@ hterm.VT.ESC['P'] = function(parseState) { }; /** - * Start of Protected Area (SPA). + * Start of Guarded Area (SPA). * * Will not implement. */ @@ -14281,7 +16356,7 @@ hterm.VT.CC1['\x96'] = hterm.VT.ESC['V'] = hterm.VT.ignore; /** - * End of Protected Area (EPA). + * End of Guarded Area (EPA). * * Will not implement. */ @@ -14409,21 +16484,11 @@ hterm.VT.ESC['\x20'] = function(parseState) { /** * DEC 'ESC #' sequences. - * - * Handled: - * ESC # 8 - DEC Screen Alignment Test (DECALN). - * Fills the terminal with 'E's. Used liberally by vttest. - * - * Ignored: - * ESC # 3 - DEC double-height line, top half (DECDHL). - * ESC # 4 - DEC double-height line, bottom half (DECDHL). - * ESC # 5 - DEC single-width line (DECSWL). - * ESC # 6 - DEC double-width line (DECDWL). */ hterm.VT.ESC['#'] = function(parseState) { parseState.func = function(parseState) { var ch = parseState.consumeChar(); - if (ch == '8') + if (ch == '8') // DEC Screen Alignment Test (DECALN) this.terminal.fill('E'); parseState.resetParseFunction(); @@ -14431,21 +16496,56 @@ hterm.VT.ESC['#'] = function(parseState) { }; /** - * 'ESC %' sequences, character set control. Not currently implemented. - * - * To be implemented (currently ignored): - * ESC % @ - Set ISO 8859-1 character set. - * ESC % G - Set UTF-8 character set. - * - * All other ESC # sequences are echoed to the terminal. - * - * TODO(rginda): Implement. + * Designate Other Coding System (DOCS). */ hterm.VT.ESC['%'] = function(parseState) { parseState.func = function(parseState) { var ch = parseState.consumeChar(); - if (ch != '@' && ch != 'G' && this.warnUnimplemented) - console.warn('Unknown ESC % argument: ' + JSON.stringify(ch)); + + // If we've locked the encoding, then just eat the bytes and return. + if (this.codingSystemLocked_) { + if (ch == '/') + parseState.consumeChar(); + parseState.resetParseFunction(); + return; + } + + // Process the encoding requests. + switch (ch) { + case '@': + // Switch to ECMA 35. + this.setEncoding('iso-2022'); + break; + + case 'G': + // Switch to UTF-8. + this.setEncoding('utf-8'); + break; + + case '/': + // One way transition to something else. + ch = parseState.consumeChar(); + switch (ch) { + case 'G': // UTF-8 Level 1. + case 'H': // UTF-8 Level 2. + case 'I': // UTF-8 Level 3. + // We treat all UTF-8 levels the same. + this.setEncoding('utf-8-locked'); + break; + + default: + if (this.warnUnimplemented) + console.warn('Unknown ESC % / argument: ' + JSON.stringify(ch)); + break; + } + break; + + default: + if (this.warnUnimplemented) + console.warn('Unknown ESC % argument: ' + JSON.stringify(ch)); + break; + } + parseState.resetParseFunction(); }; }; @@ -14461,24 +16561,7 @@ hterm.VT.ESC['%'] = function(parseState) { * ESC . Ps - Set G2 character set (VT300). * ESC / Ps - Set G3 character set (VT300). * - * Values for Ps are: - * 0 - DEC Special Character and Line Drawing Set. - * A - United Kingdom (UK). - * B - United States (USASCII). - * 4 - Dutch. - * C or 5 - Finnish. - * R - French. - * Q - French Canadian. - * K - German. - * Y - Italian. - * E or 6 - Norwegian/Danish. - * Z - Spanish. - * H or 7 - Swedish. - * = - Swiss. - * * All other sequences are echoed to the terminal. - * - * TODO(rginda): Implement. */ hterm.VT.ESC['('] = hterm.VT.ESC[')'] = @@ -14495,15 +16578,16 @@ hterm.VT.ESC['/'] = function(parseState, code) { return; } - if (ch in hterm.VT.CharacterMap.maps) { + var map = this.characterMaps.getMap(ch); + if (map !== undefined) { if (code == '(') { - this.G0 = hterm.VT.CharacterMap.maps[ch]; + this.G0 = map; } else if (code == ')' || code == '-') { - this.G1 = hterm.VT.CharacterMap.maps[ch]; + this.G1 = map; } else if (code == '*' || code == '.') { - this.G2 = hterm.VT.CharacterMap.maps[ch]; + this.G2 = map; } else if (code == '+' || code == '/') { - this.G3 = hterm.VT.CharacterMap.maps[ch]; + this.G3 = map; } } else if (this.warnUnimplemented) { console.log('Invalid character set for "' + code + '": ' + ch); @@ -14528,7 +16612,7 @@ hterm.VT.ESC['7'] = function() { }; /** - * Restore Cursor (DECSC). + * Restore Cursor (DECRC). */ hterm.VT.ESC['8'] = function() { this.savedState_.restore(); @@ -14542,14 +16626,14 @@ hterm.VT.ESC['8'] = function() { hterm.VT.ESC['9'] = hterm.VT.ignore; /** - * Application keypad (DECPAM). + * Application keypad (DECKPAM). */ hterm.VT.ESC['='] = function() { this.terminal.keyboard.applicationKeypad = true; }; /** - * Normal keypad (DECPNM). + * Normal keypad (DECKPNM). */ hterm.VT.ESC['>'] = function() { this.terminal.keyboard.applicationKeypad = false; @@ -14677,6 +16761,79 @@ hterm.VT.OSC['4'] = function(parseState) { this.terminal.io.sendString('\x1b]4;' + responseArray.join(';') + '\x07'); }; +/** + * iTerm2 growl notifications. + */ +hterm.VT.OSC['9'] = function(parseState) { + // This just dumps the entire string as the message. + hterm.notify({'body': parseState.args[0]}); +}; + +/** + * Change VT100 text foreground color. + */ +hterm.VT.OSC['10'] = function(parseState) { + // Args come in as a single string, but extra args will chain to the following + // OSC sequences. + var args = parseState.args[0].split(';'); + if (!args) + return; + + var colorArg; + var colorX11 = lib.colors.x11ToCSS(args.shift()); + if (colorX11) + this.terminal.setForegroundColor(colorX11); + + if (args.length > 0) { + parseState.args[0] = args.join(';'); + hterm.VT.OSC['11'].apply(this, [parseState]); + } +}; + +/** + * Change VT100 text background color. + */ +hterm.VT.OSC['11'] = function(parseState) { + // Args come in as a single string, but extra args will chain to the following + // OSC sequences. + var args = parseState.args[0].split(';'); + if (!args) + return; + + var colorArg; + var colorX11 = lib.colors.x11ToCSS(args.shift()); + if (colorX11) + this.terminal.setBackgroundColor(colorX11); + + if (args.length > 0) { + parseState.args[0] = args.join(';'); + hterm.VT.OSC['12'].apply(this, [parseState]); + } +}; + +/** + * Change text cursor color. + */ +hterm.VT.OSC['12'] = function(parseState) { + // Args come in as a single string, but extra args will chain to the following + // OSC sequences. + var args = parseState.args[0].split(';'); + if (!args) + return; + + var colorArg; + var colorX11 = lib.colors.x11ToCSS(args.shift()); + if (colorX11) + this.terminal.setCursorColor(colorX11); + + /* Note: If we support OSC 13+, we'd chain it here. + if (args.length > 0) { + parseState.args[0] = args.join(';'); + hterm.VT.OSC['13'].apply(this, [parseState]); + } + */ +}; + /** * Set the cursor shape. * @@ -14700,15 +16857,15 @@ hterm.VT.OSC['50'] = function(parseState) { } switch (args[1]) { - case '1': + case '1': // CursorShape=1: I-Beam. this.terminal.setCursorShape(hterm.Terminal.cursorShape.BEAM); break; - case '2': + case '2': // CursorShape=2: Underline. this.terminal.setCursorShape(hterm.Terminal.cursorShape.UNDERLINE); break; - default: + default: // CursorShape=0: Block. this.terminal.setCursorShape(hterm.Terminal.cursorShape.BLOCK); } }; @@ -14736,6 +16893,39 @@ hterm.VT.OSC['52'] = function(parseState) { this.terminal.copyStringToClipboard(this.decode(data)); }; +/** + * URxvt perl modules. + * + * This is the escape system used by rxvt-unicode and its perl modules. + * Obviously we don't support perl or custom modules, so we list a few common + * ones that we find useful. + * + * Technically there is no format here, but most modules obey: + * ; + */ +hterm.VT.OSC['777'] = function(parseState) { + var ary; + var urxvtMod = parseState.args[0].split(';', 1)[0]; + + switch (urxvtMod) { + case 'notify': + // Format: + // notify;title;message + var title, message; + ary = parseState.args[0].match(/^[^;]+;([^;]*)(;([\s\S]*))?$/); + if (ary) { + title = ary[1]; + message = ary[3]; + } + hterm.notify({'title': title, 'body': message}); + break; + + default: + console.warn('Unknown urxvt module: ' + parseState.args[0]); + break; + } +}; + /** * Insert (blank) characters (ICH). */ @@ -14826,13 +17016,13 @@ hterm.VT.CSI['J'] = hterm.VT.CSI['?J'] = function(parseState, code) { var arg = parseState.args[0]; - if (!arg || arg == '0') { - this.terminal.eraseBelow(); - } else if (arg == '1') { + if (!arg || arg == 0) { + this.terminal.eraseBelow(); + } else if (arg == 1) { this.terminal.eraseAbove(); - } else if (arg == '2') { + } else if (arg == 2) { this.terminal.clear(); - } else if (arg == '3') { + } else if (arg == 3) { // The xterm docs say this means "Erase saved lines", but we'll just clear // the display since killing the scrollback seems rude. this.terminal.clear(); @@ -14846,11 +17036,11 @@ hterm.VT.CSI['K'] = hterm.VT.CSI['?K'] = function(parseState, code) { var arg = parseState.args[0]; - if (!arg || arg == '0') { + if (!arg || arg == 0) { this.terminal.eraseToRight(); - } else if (arg == '1'){ + } else if (arg == 1) { this.terminal.eraseToLeft(); - } else if (arg == '2') { + } else if (arg == 2) { this.terminal.eraseLine(); } }; @@ -14933,9 +17123,17 @@ hterm.VT.CSI['Z'] = function(parseState) { /** * Character Position Absolute (HPA). + * + * Same as Cursor Character Absolute (CHA). */ -hterm.VT.CSI['`'] = function(parseState) { - this.terminal.setCursorColumn(parseState.iarg(0, 1) - 1); +hterm.VT.CSI['`'] = hterm.VT.CSI['G']; + +/** + * Character Position Relative (HPR). + */ +hterm.VT.CSI['a'] = function(parseState) { + this.terminal.setCursorColumn(this.terminal.getCursorColumn() + + parseState.iarg(0, 1)); }; /** @@ -14953,7 +17151,7 @@ hterm.VT.CSI['b'] = hterm.VT.ignore; * we fill out the 'Not currently implemented' parts. */ hterm.VT.CSI['c'] = function(parseState) { - if (!parseState.args[0] || parseState.args[0] == '0') { + if (!parseState.args[0] || parseState.args[0] == 0) { this.terminal.io.sendString('\x1b[?1;2c'); } }; @@ -14987,10 +17185,10 @@ hterm.VT.CSI['f'] = hterm.VT.CSI['H']; * Tab Clear (TBC). */ hterm.VT.CSI['g'] = function(parseState) { - if (!parseState.args[0] || parseState.args[0] == '0') { + if (!parseState.args[0] || parseState.args[0] == 0) { // Clear tab stop at cursor. this.terminal.clearTabStopAtCursor(false); - } else if (parseState.args[0] == '3') { + } else if (parseState.args[0] == 3) { // Clear all tab stops. this.terminal.clearAllTabStops(); } @@ -15044,90 +17242,19 @@ hterm.VT.CSI['?l'] = function(parseState) { /** * Character Attributes (SGR). * - * Iterate through the list of arguments, applying the following attribute - * changes based on the argument value... - * - * 0 Normal (default). - * 1 Bold. - * 2 Faint. - * 3 Italic (non-xterm). - * 4 Underlined. - * 5 Blink (appears as Bold). - * 7 Inverse. - * 8 Invisible, i.e., hidden (VT300). - * 9 Crossed out (ECMA-48). - * 22 Normal (neither bold nor faint). - * 23 Not italic (non-xterm). - * 24 Not underlined. - * 25 Steady (not blinking). - * 27 Positive (not inverse). - * 28 Visible, i.e., not hidden (VT300). - * 29 Not crossed out (ECMA-48). - * 30 Set foreground color to Black. - * 31 Set foreground color to Red. - * 32 Set foreground color to Green. - * 33 Set foreground color to Yellow. - * 34 Set foreground color to Blue. - * 35 Set foreground color to Magenta. - * 36 Set foreground color to Cyan. - * 37 Set foreground color to White. - * 39 Set foreground color to default (original). - * 40 Set background color to Black. - * 41 Set background color to Red. - * 42 Set background color to Green. - * 43 Set background color to Yellow. - * 44 Set background color to Blue. - * 45 Set background color to Magenta. - * 46 Set background color to Cyan. - * 47 Set background color to White. - * 49 Set background color to default (original) - * - * Non-xterm (italic) codes have mixed support, but are supported by both - * gnome-terminal and rxvt and are recognized as CSI codes on Wikipedia - * (http://en.wikipedia.org/wiki/ANSI_escape_code). - * - * For 16-color support, the following apply. - * - * 90 Set foreground color to Bright Black. - * 91 Set foreground color to Bright Red. - * 92 Set foreground color to Bright Green. - * 93 Set foreground color to Bright Yellow. - * 94 Set foreground color to Bright Blue. - * 95 Set foreground color to Bright Magenta. - * 96 Set foreground color to Bright Cyan. - * 97 Set foreground color to Bright White. - * 100 Set background color to Bright Black. - * 101 Set background color to Bright Red. - * 102 Set background color to Bright Green. - * 103 Set background color to Bright Yellow. - * 104 Set background color to Bright Blue. - * 105 Set background color to Bright Magenta. - * 106 Set background color to Bright Cyan. - * 107 Set background color to Bright White. - * - * For 88- or 256-color support, the following apply. - * 38 ; 5 ; P Set foreground color to P. - * 48 ; 5 ; P Set background color to P. - * - * For true color (24-bit) support, the following apply. - * 38 ; 2 ; R ; G ; B Set foreground color to rgb(R, G, B) - * 48 ; 2 ; R ; G ; B Set background color to rgb(R, G, B) - * - * Note that most terminals consider "bold" to be "bold and bright". In - * some documents the bold state is even referred to as bright. We interpret - * bold as bold-bright here too, but only when the "bold" setting comes before - * the color selection. + * Iterate through the list of arguments, applying the attribute changes based + * on the argument value... */ hterm.VT.CSI['m'] = function(parseState) { function get256(i) { - if (parseState.args.length < i + 2 || parseState.args[i + 1] != '5') + if (parseState.args.length < i + 2 || parseState.args[i + 1] != 5) return null; return parseState.iarg(i + 2, 0); } function getTrueColor(i) { - if (parseState.args.length < i + 5 || parseState.args[i + 1] != '2') + if (parseState.args.length < i + 5 || parseState.args[i + 1] != 2) return null; var r = parseState.iarg(i + 2, 0); var g = parseState.iarg(i + 3, 0); @@ -15147,38 +17274,38 @@ hterm.VT.CSI['m'] = function(parseState) { var arg = parseState.iarg(i, 0); if (arg < 30) { - if (arg == 0) { + if (arg == 0) { // Normal (default). attrs.reset(); - } else if (arg == 1) { + } else if (arg == 1) { // Bold. attrs.bold = true; - } else if (arg == 2) { + } else if (arg == 2) { // Faint. attrs.faint = true; - } else if (arg == 3) { + } else if (arg == 3) { // Italic. attrs.italic = true; - } else if (arg == 4) { + } else if (arg == 4) { // Underline. attrs.underline = true; - } else if (arg == 5) { + } else if (arg == 5) { // Blink. attrs.blink = true; } else if (arg == 7) { // Inverse. attrs.inverse = true; } else if (arg == 8) { // Invisible. attrs.invisible = true; - } else if (arg == 9) { + } else if (arg == 9) { // Crossed out. attrs.strikethrough = true; - } else if (arg == 22) { + } else if (arg == 22) { // Not bold & not faint. attrs.bold = false; attrs.faint = false; - } else if (arg == 23) { + } else if (arg == 23) { // Not italic. attrs.italic = false; - } else if (arg == 24) { + } else if (arg == 24) { // Not underlined. attrs.underline = false; - } else if (arg == 25) { + } else if (arg == 25) { // Not blink. attrs.blink = false; - } else if (arg == 27) { + } else if (arg == 27) { // Steady. attrs.inverse = false; - } else if (arg == 28) { + } else if (arg == 28) { // Visible. attrs.invisible = false; - } else if (arg == 29) { + } else if (arg == 29) { // Not crossed out. attrs.strikethrough = false; } @@ -15268,9 +17395,9 @@ hterm.VT.CSI['>m'] = hterm.VT.ignore; * 6 - Report Cursor Position (CPR) [row;column]. Result is CSI r ; c R */ hterm.VT.CSI['n'] = function(parseState) { - if (parseState.args[0] == '5') { + if (parseState.args[0] == 5) { this.terminal.io.sendString('\x1b0n'); - } else if (parseState.args[0] == '6') { + } else if (parseState.args[0] == 6) { var row = this.terminal.getCursorRow() + 1; var col = this.terminal.getCursorColumn() + 1; this.terminal.io.sendString('\x1b[' + row + ';' + col + 'R'); @@ -15298,17 +17425,17 @@ hterm.VT.CSI['>n'] = hterm.VT.ignore; * or CSI ? 5 0 n No Locator, if not. */ hterm.VT.CSI['?n'] = function(parseState) { - if (parseState.args[0] == '6') { + if (parseState.args[0] == 6) { var row = this.terminal.getCursorRow() + 1; var col = this.terminal.getCursorColumn() + 1; this.terminal.io.sendString('\x1b[' + row + ';' + col + 'R'); - } else if (parseState.args[0] == '15') { + } else if (parseState.args[0] == 15) { this.terminal.io.sendString('\x1b[?11n'); - } else if (parseState.args[0] == '25') { + } else if (parseState.args[0] == 25) { this.terminal.io.sendString('\x1b[?21n'); - } else if (parseState.args[0] == '26') { + } else if (parseState.args[0] == 26) { this.terminal.io.sendString('\x1b[?12;1;0;0n'); - } else if (parseState.args[0] == '53') { + } else if (parseState.args[0] == 53) { this.terminal.io.sendString('\x1b[?50n'); } }; @@ -15361,28 +17488,28 @@ hterm.VT.CSI['q'] = hterm.VT.ignore; /** * Set cursor style (DECSCUSR, VT520). - * - * 0 - Blinking block. - * 1 - Blinking block (default). - * 2 - Steady block. - * 3 - Blinking underline. - * 4 - Steady underline. */ hterm.VT.CSI[' q'] = function(parseState) { var arg = parseState.args[0]; - if (arg == '0' || arg == '1') { + if (arg == 0 || arg == 1) { this.terminal.setCursorShape(hterm.Terminal.cursorShape.BLOCK); this.terminal.setCursorBlink(true); - } else if (arg == '2') { + } else if (arg == 2) { this.terminal.setCursorShape(hterm.Terminal.cursorShape.BLOCK); this.terminal.setCursorBlink(false); - } else if (arg == '3') { + } else if (arg == 3) { this.terminal.setCursorShape(hterm.Terminal.cursorShape.UNDERLINE); this.terminal.setCursorBlink(true); - } else if (arg == '4') { + } else if (arg == 4) { this.terminal.setCursorShape(hterm.Terminal.cursorShape.UNDERLINE); this.terminal.setCursorBlink(false); + } else if (arg == 5) { + this.terminal.setCursorShape(hterm.Terminal.cursorShape.BEAM); + this.terminal.setCursorBlink(true); + } else if (arg == 6) { + this.terminal.setCursorShape(hterm.Terminal.cursorShape.BEAM); + this.terminal.setCursorBlink(false); } else { console.warn('Unknown cursor style: ' + arg); } @@ -15513,7 +17640,7 @@ hterm.VT.CSI['$x'] = hterm.VT.ignore; /** * vt_tiledata (as used by NAOhack and UnNetHack) - * (see http://nethackwiki.com/wiki/Vt_tiledata for more info) + * (see https://nethackwiki.com/wiki/Vt_tiledata for more info) * * Implemented as far as we care (start a glyph and end a glyph). */ @@ -15521,12 +17648,12 @@ hterm.VT.CSI['z'] = function(parseState) { if (parseState.args.length < 1) return; var arg = parseState.args[0]; - if (arg == '0') { + if (arg == 0) { // Start a glyph (one parameter, the glyph number). if (parseState.args.length < 2) return; this.terminal.getTextAttributes().tileData = parseState.args[1]; - } else if (arg == '1') { + } else if (arg == 1) { // End a glyph. this.terminal.getTextAttributes().tileData = null; } @@ -15565,14 +17692,14 @@ hterm.VT.CSI['\'|'] = hterm.VT.ignore; * * Will not implement. */ -hterm.VT.CSI[' }'] = hterm.VT.ignore; +hterm.VT.CSI['\'}'] = hterm.VT.ignore; /** * Delete P s Columns (DECDC), VT420 and up. * * Will not implement. */ -hterm.VT.CSI[' ~'] = hterm.VT.ignore; +hterm.VT.CSI['\'~'] = hterm.VT.ignore; // SOURCE FILE: hterm/js/hterm_vt_character_map.js // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -15585,80 +17712,175 @@ lib.rtdep('lib.f'); /** * Character map object. * - * @param {object} The GL mapping from input characters to output characters. - * The GR mapping will be automatically created. + * Mapping from received to display character, used depending on the active + * VT character set. + * + * GR maps are not currently supported. + * + * @param {string} description A human readable description of this map. + * @param {Object} glmap The GL mapping from input to output characters. */ -hterm.VT.CharacterMap = function(name, glmap) { +hterm.VT.CharacterMap = function(description, glmap) { /** - * Short name for this character set, useful for debugging. + * Short description for this character set, useful for debugging. */ - this.name = name; + this.description = description; /** * The function to call to when this map is installed in GL. */ this.GL = null; - /** - * The function to call to when this map is installed in GR. - */ - this.GR = null; + // Always keep an unmodified reference to the map. + // This allows us to sanely reset back to the original state. + this.glmapBase_ = glmap; - if (glmap) - this.reset(glmap); + // Now sync the internal state as needed. + this.sync_(); }; /** - * @param {object} The GL mapping from input characters to output characters. - * The GR mapping will be automatically created. + * Internal helper for resyncing internal state. + * + * Used when the mappings change. + * + * @param {Object?} opt_glmap Additional mappings to overlay on top of the + * base mapping. */ -hterm.VT.CharacterMap.prototype.reset = function(glmap) { - // Set the the GL mapping. - this.glmap = glmap; +hterm.VT.CharacterMap.prototype.sync_ = function(opt_glmap) { + // If there are no maps, then reset the state back. + if (!this.glmapBase_ && !opt_glmap) { + this.GL = null; + delete this.glmap_; + delete this.glre_; + return; + } - var glkeys = Object.keys(this.glmap).map(function(key) { - return '\\x' + lib.f.zpad(key.charCodeAt(0).toString(16)); - }); + // Set the the GL mapping. If we're given a custom mapping, then create a + // new object to hold the merged map. This way we can cleanly reset back. + if (opt_glmap) + this.glmap_ = Object.assign({}, this.glmapBase_, opt_glmap); + else + this.glmap_ = this.glmapBase_; - this.glre = new RegExp('[' + glkeys.join('') + ']', 'g'); + var glchars = Object.keys(this.glmap_).map((key) => + '\\x' + lib.f.zpad(key.charCodeAt(0).toString(16))); + this.glre_ = new RegExp('[' + glchars.join('') + ']', 'g'); - // Compute the GR mapping. - // This is the same as GL except all keys have their MSB set. - this.grmap = {}; + this.GL = (str) => str.replace(this.glre_, (ch) => this.glmap_[ch]); +}; - glkeys.forEach(function(glkey) { - var grkey = String.fromCharCode(glkey.charCodeAt(0) & 0x80); - this.grmap[grkey] = this.glmap[glkey]; - }.bind(this)); +/** + * Reset map back to original mappings (discarding runtime updates). + * + * Specifically, any calls to setOverrides will be discarded. + */ +hterm.VT.CharacterMap.prototype.reset = function() { + // If we haven't been given a custom mapping, then there's nothing to reset. + if (this.glmap_ !== this.glmapBase_) + this.sync_(); +}; - var grkeys = Object.keys(this.grmap).map(function(key) { - return '\\x' + lib.f.zpad(key.charCodeAt(0).toString(16), 2); - }); +/** + * Merge custom changes to this map. + * + * The input map need not duplicate the existing mappings as it is merged with + * the existing base map (what was created with). Subsequent calls to this + * will throw away previous override settings. + * + * @param {Object} glmap The custom map to override existing mappings. + */ +hterm.VT.CharacterMap.prototype.setOverrides = function(glmap) { + this.sync_(glmap); +}; + +/** + * Return a copy of this mapping. + * + * @return {hterm.VT.CharacterMap} A new hterm.VT.CharacterMap instance. + */ +hterm.VT.CharacterMap.prototype.clone = function() { + var map = new hterm.VT.CharacterMap(this.description, this.glmapBase_); + if (this.glmap_ !== this.glmapBase_) + map.setOverrides(this.glmap_); + return map; +}; - this.grre = new RegExp('[' + grkeys.join('') + ']', 'g'); +/** + * Table of character maps. + */ +hterm.VT.CharacterMaps = function() { + this.maps_ = hterm.VT.CharacterMaps.DefaultMaps; - this.GL = function(str) { - return str.replace(this.glre, - function(ch) { return this.glmap[ch] }.bind(this)); - }.bind(this); + // Always keep an unmodified reference to the map. + // This allows us to sanely reset back to the original state. + this.mapsBase_ = this.maps_; +}; - this.GR = function(str) { - return str.replace(this.grre, - function(ch) { return this.grmap[ch] }.bind(this)); - }.bind(this); +/** + * Look up a previously registered map. + * + * @param {String} name The name of the map to lookup. + * @return {hterm.VT.CharacterMap} The map, if it's been registered. + */ +hterm.VT.CharacterMaps.prototype.getMap = function(name) { + if (this.maps_.hasOwnProperty(name)) + return this.maps_[name]; + else + return undefined; }; /** - * Mapping from received to display character, used depending on the active - * VT character set. + * Register a new map. + * + * Any previously registered maps by this name will be discarded. + * + * @param {String} name The name of the map. + * @param {hterm.VT.CharacterMap} map The map to register. + */ +hterm.VT.CharacterMaps.prototype.addMap = function(name, map) { + if (this.maps_ === this.mapsBase_) + this.maps_ = Object.assign({}, this.mapsBase_); + this.maps_[name] = map; +}; + +/** + * Reset the table and all its maps back to original state. + */ +hterm.VT.CharacterMaps.prototype.reset = function() { + if (this.maps_ !== hterm.VT.CharacterMaps.DefaultMaps) + this.maps_ = hterm.VT.CharacterMaps.DefaultMaps; +}; + +/** + * Merge custom changes to this table. + * + * @param {Object} maps A set of hterm.VT.CharacterMap objects. + */ +hterm.VT.CharacterMaps.prototype.setOverrides = function(maps) { + if (this.maps_ === this.mapsBase_) + this.maps_ = Object.assign({}, this.mapsBase_); + + for (var name in maps) { + var map = this.getMap(name); + if (map !== undefined) { + this.maps_[name] = map.clone(); + this.maps_[name].setOverrides(maps[name]); + } else + this.addMap(name, new hterm.VT.CharacterMap('user ' + name, maps[name])); + } +}; + +/** + * The default set of supported character maps. */ -hterm.VT.CharacterMap.maps = {}; +hterm.VT.CharacterMaps.DefaultMaps = {}; /** * VT100 Graphic character map. * http://vt100.net/docs/vt220-rm/table2-4.html */ -hterm.VT.CharacterMap.maps['0'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['0'] = new hterm.VT.CharacterMap( 'graphic', { '\x60':'\u25c6', // ` -> diamond '\x61':'\u2592', // a -> grey-box @@ -15697,7 +17919,7 @@ hterm.VT.CharacterMap.maps['0'] = new hterm.VT.CharacterMap( * British character map. * http://vt100.net/docs/vt220-rm/table2-5.html */ -hterm.VT.CharacterMap.maps['A'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['A'] = new hterm.VT.CharacterMap( 'british', { '\x23': '\u00a3', // # -> british-pound }); @@ -15705,14 +17927,14 @@ hterm.VT.CharacterMap.maps['A'] = new hterm.VT.CharacterMap( /** * US ASCII map, no changes. */ -hterm.VT.CharacterMap.maps['B'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['B'] = new hterm.VT.CharacterMap( 'us', null); /** * Dutch character map. * http://vt100.net/docs/vt220-rm/table2-6.html */ -hterm.VT.CharacterMap.maps['4'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['4'] = new hterm.VT.CharacterMap( 'dutch', { '\x23': '\u00a3', // # -> british-pound @@ -15732,8 +17954,8 @@ hterm.VT.CharacterMap.maps['4'] = new hterm.VT.CharacterMap( * Finnish character map. * http://vt100.net/docs/vt220-rm/table2-7.html */ -hterm.VT.CharacterMap.maps['C'] = -hterm.VT.CharacterMap.maps['5'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['C'] = +hterm.VT.CharacterMaps.DefaultMaps['5'] = new hterm.VT.CharacterMap( 'finnish', { '\x5b': '\u00c4', // [ -> 'A' umlaut '\x5c': '\u00d6', // \ -> 'O' umlaut @@ -15752,7 +17974,7 @@ hterm.VT.CharacterMap.maps['5'] = new hterm.VT.CharacterMap( * French character map. * http://vt100.net/docs/vt220-rm/table2-8.html */ -hterm.VT.CharacterMap.maps['R'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['R'] = new hterm.VT.CharacterMap( 'french', { '\x23': '\u00a3', // # -> british-pound @@ -15772,7 +17994,7 @@ hterm.VT.CharacterMap.maps['R'] = new hterm.VT.CharacterMap( * French Canadian character map. * http://vt100.net/docs/vt220-rm/table2-9.html */ -hterm.VT.CharacterMap.maps['Q'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['Q'] = new hterm.VT.CharacterMap( 'french canadian', { '\x40': '\u00e0', // @ -> 'a' grave @@ -15793,7 +18015,7 @@ hterm.VT.CharacterMap.maps['Q'] = new hterm.VT.CharacterMap( * German character map. * http://vt100.net/docs/vt220-rm/table2-10.html */ -hterm.VT.CharacterMap.maps['K'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['K'] = new hterm.VT.CharacterMap( 'german', { '\x40': '\u00a7', // @ -> section symbol (double s) @@ -15811,7 +18033,7 @@ hterm.VT.CharacterMap.maps['K'] = new hterm.VT.CharacterMap( * Italian character map. * http://vt100.net/docs/vt220-rm/table2-11.html */ -hterm.VT.CharacterMap.maps['Y'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['Y'] = new hterm.VT.CharacterMap( 'italian', { '\x23': '\u00a3', // # -> british-pound @@ -15833,8 +18055,8 @@ hterm.VT.CharacterMap.maps['Y'] = new hterm.VT.CharacterMap( * Norwegian/Danish character map. * http://vt100.net/docs/vt220-rm/table2-12.html */ -hterm.VT.CharacterMap.maps['E'] = -hterm.VT.CharacterMap.maps['6'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['E'] = +hterm.VT.CharacterMaps.DefaultMaps['6'] = new hterm.VT.CharacterMap( 'norwegian/danish', { '\x40': '\u00c4', // @ -> 'A' umlaut @@ -15855,7 +18077,7 @@ hterm.VT.CharacterMap.maps['6'] = new hterm.VT.CharacterMap( * Spanish character map. * http://vt100.net/docs/vt220-rm/table2-13.html */ -hterm.VT.CharacterMap.maps['Z'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['Z'] = new hterm.VT.CharacterMap( 'spanish', { '\x23': '\u00a3', // # -> british-pound @@ -15874,8 +18096,8 @@ hterm.VT.CharacterMap.maps['Z'] = new hterm.VT.CharacterMap( * Swedish character map. * http://vt100.net/docs/vt220-rm/table2-14.html */ -hterm.VT.CharacterMap.maps['7'] = -hterm.VT.CharacterMap.maps['H'] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['7'] = +hterm.VT.CharacterMaps.DefaultMaps['H'] = new hterm.VT.CharacterMap( 'swedish', { '\x40': '\u00c9', // @ -> 'E' acute @@ -15896,7 +18118,7 @@ hterm.VT.CharacterMap.maps['H'] = new hterm.VT.CharacterMap( * Swiss character map. * http://vt100.net/docs/vt220-rm/table2-15.html */ -hterm.VT.CharacterMap.maps['='] = new hterm.VT.CharacterMap( +hterm.VT.CharacterMaps.DefaultMaps['='] = new hterm.VT.CharacterMap( 'swiss', { '\x23': '\u00f9', // # -> 'u' grave @@ -16045,23 +18267,125 @@ lib.resource.add('hterm/audio/bell', 'audio/ogg;base64', '' ); +lib.resource.add('hterm/images/icon-96', 'image/png;base64', +'iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABGdBTUEAALGPC/xhBQAAAAFzUkdC' + +'AK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dE' + +'AP8A/wD/oL2nkwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAFKhJREFUeNrtXXlsXMd5/30z8649uDzE' + +'mxRFibIsOXZ8VInTJFYSW3actE1ctWkctEF6I0VRFEWAoihQoAjQFmiBogWaIEADFCmQXklto04T' + +'O0ndWI4bxZalWHJinTYtkRJFkctzl9zd977+8c49+UjuipbCD1y+9+ae75vvmJlv3gO2YRu2YRu2' + +'YRu2YUuAtroBN3nfeKsaSXWurarvRvUrTnlccV/5a3lDReRKFdc4Za6nzvW2b7OIpwZh7N37iHYi' + +'Pztyvy4iqA00Tng/WXH1f3GQsFki0Qbz+cAV12jeRkTwwUd2yfsVI89OjbLrwnoJILw8EoAOIAFg' + +'LwDTCxcAJBEJIiIAgoiICAIgIgIBJGpdPRCRq3sPCBAJAii8QgAk/PIFkSBBQvh3QRkQXtECBKpx' + +'H9br5hMikhcg4QV4dYkgARFBSkmlUmnp7LmLX8rl8q95OPKJ0DQCkPeTEcQrAD179+7+7LsP3vtJ' + +'w9A1ZvbwFfQM/r1/AyD64KLBv5JHIaIwIpI5GIbevd82r0I3OMjvJfOo5ffCqw1EhIRlQQi3a37p' + +'0atfTVB22PhIuHt95tnnBr75zHN/AGASoYjyxVVTCOCPfOWN9sGfue+df/L4r3z8MSGUOv3aWYDI' + +'q43BEXXEQRPCQK5qFleFMdduOwMV3WKUBXFVyVXhtm3jrjtvw13vuL1uPXGAAUghkGlLPXJ9ZvZz' + +'L738oz8HsOhFF2u3aH0E8JEvAWhe+n2PHD70Z7/xmccfLBSK9M1nX0AqnYFSKiB7fIiOzg3k21Be' + +'YHW1gMkr1/DBB+6HkGLTxmRfbxf9+qc/8WszM9lzF99468twxZCAq5wbQiMCREWPBkDXde3eI489' + +'+he/+1u/et/c3AK+/uSzyLTvgK7rm+tBE4CZA1HRaFT7oqNQKCCdsqBp61GD9eHBD77XunJ16o/+' + +'6q+/cLJYLP2fhzfGGkRYiwBRK2fnL/3iRz7/uT/8nfuuz2Txla8+hXRbJ6QUKBaLuJmgVLJRKuSh' + +'lIBpatiEFApACIFHH/lA//NHj33qe0ePvQJXEa/JnHEIoABYd925/zOPf+JjBxMJC//yxX+GYaZg' + +'GAZse00ue1uByyWMQrGEldVVKCWbQgAA6OnegQP7997zvaPH2gGsIpQidWuoRwA/o2/bDz70off+' + +'nFIa/fczz2Pq2hzSbRksLCxsNT43BI7jYCW/ihd/cBKWZTZhQcFV9qMjQ0gmEwm4hkqsOVEjDogq' + +'37bOjvaElBKLizmYVgKWZW01HjeOLGaAbUipoJTWHAKwa4KYpmHCJUB0lQCoU0scK0gCMJRSqqOj' + +'Hel0EqZpIpFIbDUeNwwOM2y7gO4dnWhrSzVFBDEzMpkULNM04BIgFsS1ggxNUzKVSiCRsEBEUEoF' + +'iRq2v5HNXjMd18pSHVeZnuuniZaopIIQBAIhnUqgvb1tU3OBKFiWCdMydABWBH+bIoCvA3RNU9Ky' + +'DOiahG2XAAAzszO4NHkZINcKALuddRHi3VWFReLcWy8dhxO5aFpvkhamD5HFwQQuStgwLPpsOza4' + +'5GD/yD4MDw2jVCrCMHSkUwmws3kCMADD0GCZpialMG3bia4trVsJ+xkJAKSUStM0oWsSQrgTGdu2' + +'MXllEmezF/HRhz+C4b6hyEgrnyjVLLzhcho1iFsDiGomOzt+Ds/8z7PIzmfR39eP1dVVSOEijR0n' + +'RsFrg1ISpmkoQ9cTufxKrBbHmoUoJZWmlPDXRZgdMDNsx8HuXbtx3zvvhRQKTdFmLQACoT2dwY9e' + +'fRWlvA1m1xJy2IEggkPrnUvXB9M0lGkaiVx+xR/ADQuPRQAppaY0JfzOBB0joFAs4Oyb59E0Y7pF' + +'4DDDdmw47LgygQHbbs7Ij4JpGMIwjGRFcF0xFJcDdE0pUb3YQ1hYWsDFSxff7vgHMyO3kkMGiaAP' + +'zScAwzB0YVlmAuHo3zQHkKaUppTHAUQBLQnAYm4J41feCldAGeHe2FaCq9fdXQMP8qt5sB6OlGbP' + +'4pkBwzBgGHoKMdcIG82Ew0RK6UqTxHAJEHSBCLmVHCavXwUcwGpXMJIS2YnVhrq01cAOQxkC7YMG' + +'5i6vwi65LV4trIK10GJyHLvpTTR0DZZlJtEEMxR+IVJJTSlFAFdZL47joFgswrEZ3X06Dv3eAH78' + +'7Vm8/t0s8nMld9PjBhHCN1G7dlm490g3rIzCt/5yHIWiA5dxGQ5HOcBpatuYGZquwTSNTXMAogVo' + +'SukuAXwlzFUpSRCyl1cx+VoOBz/Zi93vyeDE16bx1iuLsIsOSLSWCuwwEh0a9h/uxDs+2gWnxDj+' + +'79dQKjhlg4bZl/vkiaDmtkvXNFimmURMJ4VYOkBpSldSug91TDYiIDdXwtEvTeDNlxZw3y/34PDn' + +'duLCi/M4+eQ0Zt5cCdI1G/FKFxg5mME9R7rRMWTi/AtzOPnENLKXV2tyrA+lFqzkKk3BNI0k3BWE' + +'5swDXA7wlm0bFEkEODbjzWPzmDqTw4HDnbjz57swdHcKp56+jte/k0VurtRUInSPJXD3Y90YfXcb' + +'Zt7I49t/M45LJ5ZgF7lMAbsN9BfiXE5uthXEzFBK+TpAhrVunAAEeEp4DQ4oyyQI+fkSjn/tGsZf' + +'WcA9j3Xjvk/0Yte72vD8FyZw/Y2VauRsAA483ImDn+oF28DL/zqFn3wni/xcESSoTvkExxdBBNil' + +'FnCAlLBMM+Hhdk3HtThoIE1TulTuDlscAgAuNxCA6XN5HP+Pa8heWsHAgSQyA0ZzFr8IGHhHCuke' + +'HedfmMOpb8wgly021jXkTsjYm9C0YjNJSgFvHuAP7qbMA3TpcwAo1ooDOwwjKTH2QDvu/lg3lCnw' + +'g69cxcSpJc8dZJPgACeeuAYhgf0Pd6JjyMArX5/GlZ8sg23U5TCf+ESt0QFCCFiWYcF131kT4lhB' + +'pDSXAMy+Eq1PAXYAIYHBu9O490g3evclMf7yAk785zSuX8i7Y68ZOoCA6xdW8N2/u4TRd2dw75Fu' + +'PPqnu3Dmu7N49RszWLiyGvgGRfM47HjNdzmg6U6kRLAs02wGAXwieBwgggoaMUD7oI67fmEHbjvU' + +'gfmrBTz395fw5ksLKK26pmgzO0wCsFcZ576XxeTpZdzxaCfu+HAXRg624eST0zh/dB6FXDjK3TUg' + +'VwQREUot0AFCEEx3U8ZoBgEAVwdoUnheFnWGLztA1y4Tj/zxCIyUwI+emsaPn5nF8qyvFFs0D/C8' + +'05Zni3jpq1MY/+EC7jnSg/f+5gB69yXw/BcnYBfDIeMrYaLW6ACAYFmmjpi7YqpmCRWMq2maLgIO' + +'qFcUQ7MErp5ZxqmnZ0Jx0+IJWNBIr5qpszl852/fwp73ZNC3PwmhKCQAUWCGAu5MuNlriEQEy6za' + +'FauLhHg6QClNejte9YQICcL1i3k8/4UJd/bZZHETGwGCYK8yzjw3h4vHFmAXym19dxfNE0Etcqkx' + +'TVPTdd0qFApRPNaEtcxQAiA0TelCeKvRDTSoXWTYJb5ho75Rq0kApbwDrphrOREd0Ip5AOBuyhiG' + +'HsttpB4BohiUmqZpgel4Mx1qournYCbcUg4wpLccUasVZVCLAJUZhKaUTp5hvTWCpXnAcEIOsG00' + +'fxuVYRq6MA3dX5JuCGt5xhEAqWkq4IC4M+GYbV0/bLJ6h92dmlaJIG9ThkyzbE9gQ0rYB6lpSgUc' + +'0CT8C0nQzPUvCDk2o7iysUU0gmsFcSCCnJZspeq6BtPUk3HSxrGChKZpmu/U2gwKsMPo2Z/E+397' + +'AELFL48EMHFqGd//x0k49gYwR+VWUGvmAQxD12GZZgox1tpiuSa6HOCJIJ8umxo5hELOxvSFPEiu' + +'IxcR5idXNzVqqwnQXBZghr8r5m/KbHgxzs+oNE1T/sBvhggiAcyOr+B//+FyUzsfD0ERM7RFIkjT' + +'gj2BNTmgnhUUXcd2N4SpBUp4C6DVHABmaEr5+8L+rtiGlTADUK4I8kJ8XeDDes/KAw37zPUSrYUn' + +'5tpJOJqE4ThOSACn+RzAAKSU/p7AmgI2phWkyeB4ZqQiAsFZtkFOZI+Ao7SgytVgeJoQVBkf+HRG' + +'rxVhVBFGqHj24imSP3psFUAylYCSEsWSDdu2y86WNQukuytmIdwVq3tSJo5zrtI0JUMjiAJzbrB/' + +'AA8YRnCWNnLON3JuFyEiIj8AZen9Vc0wL0JkRtMgGlfjDHBwDSLKzwp7dRZL+aYivZwAApZlWnAP' + +'t0TxuSYBKocCA1BKUxIgMBy0taUAOCiVikilUkin0/FbFnEz3xxQLGMg6rpemX9paQm37x2DlLLM' + +'U6IZIITwOUCraEAVERotR4ccoDQJAI7DGBrsx8MP3o+nv/V9dHf3BAc1IjguO00d+OpHffYrw5ir' + +'09WMi5wd4PC8QLDHXHGmIHr1G8dgsOOgoyOJB973LjR/KSLYFYtuymxYCZOUUtM8z2i/w48cPgTT' + +'MPDD46eQX1mG768Smqq+qAFEROwIQSASZVdBAiQIQggI8q7+c/AjSCEgZBgm/TgZ3stovKy4Rsqz' + +'LBMjOweRSiXhNOFwRi0CmJbhE2BTm/KspNQ0pcrMVaUkDj/0fnzg0P0olkqhs+4a71xoeA0LKCur' + +'Irhmf2rJzca9cl0Um3U0qZoAqNwV25AS9pEdnA2IguM4kFLC95bYLPiiJYIjtEI83BggWKapCSEs' + +'x3E2txinlPJOx9z8k7AbBUTBSRkrl8tv+GUdDIClksphFsvL+ZacKLn1gL3V0DICrOuQXvSohUNE' + +'2rnz41QqcdPNtVsRGEBbOgnbdkjTVKUZWgWqRn4fHABOoVBcNE2ztHPnoL7NAfHANHS8dPzE0sxM' + +'dsILqvsGrXocEGRYXFx67fUz5y729e7Yw4ADjumb2AJoWq2xCtrwdh0TQRz74YmLpZI9HitHjTCC' + +'a0KZANKGoX88lUo+pCmlhBASYMmAjE76Ea4CoNyerDYuUZHRXwiq2Pan8r/yNkcMAiqvv+pwFFWm' + +'pQqbl6isaqoVVtajsJfB0piXwCEidhyHp6/PHpudnfs8gDm4b07xX+xXBnEW43jv2Ojo73/20x+e' + +'zc47Fy6MN/IOXZ+ZxBvIE6eeCovbn0FXzjXqt4urEsVlGsPQ8NFHP0RP/dez4sv/9G8ZuK8wq2uK' + +'xtkRs+44cNs7e3t61NEXXwVIVUye1o+f+nnXsT1ZlrwiH9dKjLp+TZVhoRNy/Jb5PrPjlyfAzDiw' + +'f28vgD4AV+AuS5dq5au3FuS/I0IB6B3bM7L7wsW3IJSBjvb2ls0gb3YgIiym0hi/NImB/p5Mpi09' + +'Or+weBqu+CliHYtx/ruCpGWZu3cOD/Sceu08ioUiFhcX12rHTy0QEXTdwKVLV7B/326tt3fHnvmF' + +'RQMu8v03aAERIjTyC5IAtJGdg/s7OjLmbHYBXV29TVt6uFVB13VMXZtFwrIwMNA3dvbcGxaAFYQb' + +'9LE5QAFI7Nk9cgdAyOeL2CFlS8XPrbDUoZTC4lIexVIJw0P9IwDScBVxzVOT9QggvbiuvWOjY9ns' + +'PBxmLC0tbc+G1wApJWyHMTObxcjwYB+ALgBTCN8+WTYpa0QAQUTDu0eH+ycmp5BOtyGVSm0r4Big' + +'6wYmJqYwNNTfIaXss237DEIRVMYFUQIEnnDwOGBwoG9ff19P+tXT52BZiVtCRLS6D8wM0zRx6fJV' + +'/Oz991jdOzp3Xp2a9iVKlTlayQFR89PYPTp8wLJMys4tItNuYH5+fqvx97YHIQQ0XcfUtRmkUgnq' + +'7+8duTo1raGOj1AlB0TnAOm9Y6O35XJ5MAskk8lt8bMOmMzOwHEYw0P9IydOnjYR6oC6BADK5wD9' + +'e8d2DV65Og3dMKGUuuUUcCvFkcPA/PwCRnYODAJoA3AdNRy1anGABCA7O9vHRnYOdrx84sdgBubm' + +'5rY5ICa4m/8Sk1enMTQ00A2gG8BbKOcCBmpzgASgj44M7+/oaJfXpmfR3t5xy07AWsUFhUIRlyem' + +'cOcde9OpVHJgaWn5FawhgqLfhkmOje26nZmRyxXQtePmfU3xVoFpmbg2PYtMW1rr6+3eeX5pOaqE' + +'gyWJShHkJ9px297RXddnsiiWbCwuLv5UiJ9aX/bYSBlE7nV5OYe2dAqDA727zl94s5IAZSIoKv9F' + +'ImHt2rN7pDs7N4/l5WVIOesRwH8Tbs2qgwvXi6uKr9PB+u8ujomSeKlonZG0RmRl6AcPHcTAQC8G' + +'B/uGEb5RPToh46j3bhCxc3hg39Bgn9nbswPpVBK53ErZR2tqOV358eVx4X2wzRRx2K103q12yEXo' + +'5Bvcry99I4ewuI5kYdsj6SIOxV5omXOwphS6ujoghMDw0EAvXEvoSgTfAKrfaUMA9F0jQ7d3d3ch' + +'k0njoQ+9b83NiK0VTnHendOqdnLdIIY7K3YJ0N8ppeixbecMYixFpHaNDI+mU0n3pdl8a9n+NxJ8' + +'7ujv7030dO8YvHL1mr8zWsYBlZrZymTSKaUlQNLAVo/vmxsIxCV0tLeJzs72bo8AboSH71qroStL' + +'S8u567PzyK86G9ox32yjW1lU6/sTrYFhmQqWZSGdSmZqpVZlqV3IzcxkZ6evTWFpebWmT2+tj6MF' + +'76OtdbSL61gyzDXTlZ0hKE9Q9rEGrrK8uELec1Vc+bcJIvfRwyM1wpiry2sU5opvRqYtCcuUKBSK' + +'JYQf/QzcFX0CRN0Rc8dPnD5qJZ7okVKCHYd8V27/RRcM9gAAewc/2bsLH+GnCf+Xp/PmFsFtEBum' + +'Lqss8oTIX9lzUFCQJ9rAijRV92VtjTxHyquqpKzLjn+Fu+xsKyULzLzyxhuXnkSNL66WnYRB+KnC' + +'DNydHP/dZzpCU7WWUuAGzxwjvlYZ9cLWm4cbxMUpD2vkqQzzkVwEUIC7Gb/iXQvez3fSYlWR0YZL' + +'uUUvkYHw453+JGK9EKdTrdT0Db2TW9CO6DeGSyhHetWXVqOfvXAq7m0vY9xvBW+28RvJ3ygP4ca3' + +'KcpJUU7wER/VAQBqK2H/DRZ+hspDe81EYKsQsZV1Vg7oKNKjyGegsXNuFOE302Ywr/G8Fe2pq4fq' + +'IfZmQvjbHbZ6AGzDNmzDNmzD2xT+H+5UT7Tyxc2HAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA2' + +'LTMwVDExOjUwOjAyLTA0OjAwOaSkCgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMy0xMS0wMVQxMDoz' + +'ODoyNC0wNDowMNba8BsAAAAASUVORK5CYII=' + +'' +); + lib.resource.add('hterm/concat/date', 'text/plain', -'Fri, 03 Apr 2015 09:02:15 +0000' + +'Sun, 22 Oct 2017 11:00:51 +0000' + '' ); lib.resource.add('hterm/changelog/version', 'text/plain', -'1.54' + +'1.73' + '' ); lib.resource.add('hterm/changelog/date', 'text/plain', -'2015-03-19' + +'2017-10-16' + '' ); lib.resource.add('hterm/git/HEAD', 'text/plain', -'5db5b0ceefff97ce8b7a97edd3f5ba6857db54cf' + +'git rev-parse HEAD' + '' ); diff --git a/src/wetty.js b/src/wetty.js new file mode 100644 index 0000000..4bb10d8 --- /dev/null +++ b/src/wetty.js @@ -0,0 +1,84 @@ +const socket = io(location.origin, { path: '/wetty/socket.io' }); +let term; +let buf = ''; + +class Wetty { + constructor(argv) { + this.argv_ = argv; + this.io = null; + this.pid_ = -1; + } + + run() { + this.io = this.argv_.io.push(); + this.io.onVTKeystroke = this.sendString_.bind(this); + this.io.sendString = this.sendString_.bind(this); + this.io.onTerminalResize = this.onTerminalResize.bind(this); + } + + sendString_(str) { + socket.emit('input', str); + } + + onTerminalResize(col, row) { + socket.emit('resize', { col, row }); + } +} + +socket.on('connect', () => { + document.getElementById('overlay').style.display = 'none'; + window.addEventListener('beforeunload', handler, false); + lib.init(() => { + hterm.defaultStorage = new lib.Storage.Local(); + term = new hterm.Terminal(); + window.term = term; + term.decorate(document.getElementById('terminal')); + + term.setCursorPosition(0, 0); + term.setCursorVisible(true); + term.prefs_.set('ctrl-c-copy', true); + term.prefs_.set('ctrl-v-paste', true); + term.prefs_.set('use-default-window-copy', true); + term.prefs_.set('send-encoding', 'raw'); + term.prefs_.set('receive-encoding', 'raw'); + term.prefs_.set('font-size', 14); + term.scrollPort_.screen_.setAttribute('spellcheck', 'false'); + term.scrollPort_.screen_.setAttribute('autocorrect', 'false'); + term.scrollPort_.screen_.setAttribute('autocomplete', 'false'); + term.scrollPort_.screen_.setAttribute('contenteditable', 'false'); + + term.runCommandClass(Wetty, document.location.hash.substr(1)); + socket.emit('resize', { + col: term.screenSize.width, + row: term.screenSize.height, + }); + + if (buf && buf !== '') { + term.io.writeUTF8(buf); + buf = ''; + } + }); +}); + +socket.on('output', data => { + if (!term) { + buf += data; + return; + } + term.io.writeUTF8(data); +}); + +socket.on('logout', () => { + document.getElementById('overlay').style.display = 'block'; + window.removeEventListener('beforeunload', handler, false); +}); + +socket.on('disconnect', () => { + document.getElementById('overlay').style.display = 'block'; + window.removeEventListener('beforeunload', handler, false); +}); + +function handler(e) { + e.returnValue = 'Are you sure?'; + return e.returnValue; +} diff --git a/wetty.mjs b/wetty.mjs new file mode 100644 index 0000000..b5181e1 --- /dev/null +++ b/wetty.mjs @@ -0,0 +1,88 @@ +import express from 'express'; +import http from 'http'; +import https from 'https'; +import path from 'path'; +import server from 'socket.io'; +import { spawn } from 'node-pty'; +import EventEmitter from 'events'; +import favicon from 'serve-favicon'; + +const app = express(); +app.use(favicon(`${__dirname}/public/favicon.ico`)); +// For using wetty at /wetty on a vhost +app.get('/wetty/ssh/:user', (req, res) => { + res.sendFile(`${__dirname}/public/wetty/index.html`); +}); +app.get('/wetty/', (req, res) => { + res.sendFile(`${__dirname}/public/wetty/index.html`); +}); +// For using wetty on a vhost by itself +app.get('/ssh/:user', (req, res) => { + res.sendFile(`${__dirname}/public/wetty/index.html`); +}); +app.get('/', (req, res) => { + res.sendFile(`${__dirname}/public/wetty/index.html`); +}); +// For serving css and javascript +app.use('/', express.static(path.join(__dirname, 'public'))); + +function createServer(port, sslopts) { + return sslopts && sslopts.key && sslopts.cert + ? https.createServer(sslopts, app).listen(port, () => { + console.log(`https on port ${port}`); + }) + : http.createServer(app).listen(port, () => { + console.log(`http on port ${port}`); + }); +} + +function getCommand(socket, sshuser, sshhost, sshport, sshauth) { + const { request } = socket; + const match = request.headers.referer.match('.+/ssh/.+$'); + const sshAddress = sshuser ? `${sshuser}@${sshhost}` : sshhost; + const ssh = match ? `${match[0].split('/ssh/').pop()}@${sshhost}` : sshAddress; + + return [ + process.getuid() === 0 && sshhost === 'localhost' + ? ['login', '-h', socket.client.conn.remoteAddress.split(':')[3]] + : [ + path.join(__dirname, 'bin/ssh'), + ssh, + '-p', + sshport, + '-o', + `PreferredAuthentications=${sshauth}`, + ], + ssh, + ]; +} + +export default function start(port, sshuser, sshhost, sshport, sshauth, sslopts) { + const events = new EventEmitter(); + const io = server(createServer(port, sslopts), { path: '/wetty/socket.io' }); + io.on('connection', socket => { + console.log(`${new Date()} Connection accepted.`); + const [args, ssh] = getCommand(socket, sshuser, sshhost, sshport, sshauth); + const term = spawn('/usr/bin/env', args, { + name: 'xterm-256color', + cols: 80, + rows: 30, + }); + + console.log(`${new Date()} PID=${term.pid} STARTED on behalf of user=${ssh}`); + term.on('data', data => socket.emit('output', data)); + term.on('exit', code => { + console.log(`${new Date()} PID=${term.pid} ENDED`); + socket.emit('logout'); + events.emit('exit', code); + }); + socket.on('resize', ({ col, row }) => term.resize(col, row)); + socket.on('input', input => term.write(input)); + socket.on('disconnect', () => { + term.end(); + term.destroy(); + events.emit('disconnect'); + }); + }); + return events; +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..cce41fc --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4166 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@std/esm@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@std/esm/-/esm-0.12.1.tgz#d07b7c5e2701beade1e7db74b95484f5d91c46bf" + +abbrev@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + +accepts@1.3.3, accepts@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.1.tgz#53fe161111f912ab999ee887a90a0bc52822fd75" + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + +ajv-keywords@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + +ajv@^4.7.0, ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-regex@^0.2.0, ansi-regex@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +aproba@^1.0.3: + version "1.1.2" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" + +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +aria-query@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-0.7.0.tgz#4af10a1e61573ddea0cf3b99b51c52c05b424d24" + dependencies: + ast-types-flow "0.0.7" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + +array-each@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + +array-slice@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.0.0.tgz#e73034f00dcc1f40876008fd20feae77bd4b7c2f" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1, array-uniq@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arraybuffer.slice@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +ast-types-flow@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async@^2.1.5: + version "2.5.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + dependencies: + lodash "^4.14.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +axobject-query@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-0.1.0.tgz#62f59dbc59c9f9242759ca349960e7a2fe3c36c0" + dependencies: + ast-types-flow "0.0.7" + +babel-cli@6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.24.1.tgz#207cd705bba61489b2ea41b5312341cf6aca2283" + dependencies: + babel-core "^6.24.1" + babel-polyfill "^6.23.0" + babel-register "^6.24.1" + babel-runtime "^6.22.0" + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.0.0" + glob "^7.0.0" + lodash "^4.2.0" + output-file-sync "^1.1.0" + path-is-absolute "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + v8flags "^2.0.10" + optionalDependencies: + chokidar "^1.6.1" + +babel-code-frame@^6.16.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" + dependencies: + babel-code-frame "^6.22.0" + babel-generator "^6.24.1" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-core@^6.0.2, babel-core@^6.24.1, babel-core@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.0" + debug "^2.6.8" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.7" + slash "^1.0.0" + source-map "^0.5.6" + +babel-eslint@7.2.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.3.tgz#b2fe2d80126470f5c19442dc757253a897710827" + dependencies: + babel-code-frame "^6.22.0" + babel-traverse "^6.23.1" + babel-types "^6.23.0" + babylon "^6.17.0" + +babel-generator@^6.24.1, babel-generator@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.6" + trim-right "^1.0.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-add-module-exports@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz#9ae9a1f4a8dc67f0cdec4f4aeda1e43a5ff65e25" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-es6-promise@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-es6-promise/-/babel-plugin-es6-promise-1.1.1.tgz#0202f0929705f2fdcdda8ffd1222246c2cb9d6ae" + dependencies: + babel-template "^6.7.0" + babel-types "^6.7.2" + +babel-plugin-syntax-async-functions@6.13.0, babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-transform-async-to-generator@6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-object-assign@6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-assign/-/babel-plugin-transform-object-assign-6.22.0.tgz#f99d2f66f1a0b0d498e346c5359684740caa20ba" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-polyfill@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-preset-es2015@6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.24.1" + babel-plugin-transform-es2015-classes "^6.24.1" + babel-plugin-transform-es2015-computed-properties "^6.24.1" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.24.1" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.24.1" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-plugin-transform-es2015-modules-systemjs "^6.24.1" + babel-plugin-transform-es2015-modules-umd "^6.24.1" + babel-plugin-transform-es2015-object-super "^6.24.1" + babel-plugin-transform-es2015-parameters "^6.24.1" + babel-plugin-transform-es2015-shorthand-properties "^6.24.1" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.24.1" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.24.1" + babel-plugin-transform-regenerator "^6.24.1" + +babel-register@^6.24.1, babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.7.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24.1, babel-types@^6.26.0, babel-types@^6.7.2: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.11.0, babylon@^6.17.0, babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +beeper@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + dependencies: + callsite "1.0.0" + +binary-extensions@^1.0.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" + +blob@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +brace-expansion@^1.0.0, brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +builtin-modules@^1.0.0, builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +chalk@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + dependencies: + ansi-styles "^1.1.0" + escape-string-regexp "^1.0.0" + has-ansi "^0.1.0" + strip-ansi "^0.3.0" + supports-color "^0.2.0" + +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + +clone-stats@^0.0.1, clone-stats@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + +clone@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + +clone@^1.0.0, clone@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + +clone@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + +cloneable-readable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.0.0.tgz#a6290d413f217a61232f95e458ff38418cfb0117" + dependencies: + inherits "^2.0.1" + process-nextick-args "^1.0.6" + through2 "^2.0.1" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.8.1, commander@~2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + +component-emitter@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.7, concat-stream@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-with-sourcemaps@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.4.tgz#f55b3be2aeb47601b10a2d5259ccfb70fd2f1dd6" + dependencies: + source-map "^0.5.1" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +convert-source-map@^1.1.0, convert-source-map@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.0.tgz#569c050918be6486b3837552028ae0466b717086" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + +damerau-levenshtein@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +dateformat@^1.0.7-1.2.3: + version "1.0.12" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" + dependencies: + get-stdin "^4.0.1" + meow "^3.3.0" + +dateformat@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.0.0.tgz#2743e3abb5c3fc2462e527dca445e04e9f4dee17" + +debug@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + dependencies: + ms "0.7.2" + +debug@2.6.8, debug@^2.1.1, debug@^2.2.0, debug@^2.6.8: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" + dependencies: + ms "2.0.0" + +decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-extend@~0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defaults@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + dependencies: + clone "^1.0.2" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +del@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" + dependencies: + globby "^6.1.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + p-map "^1.1.1" + pify "^3.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@1.1.1, depd@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + +deprecated@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-file@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + dependencies: + fs-exists-sync "^0.1.0" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +duplexer2@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + dependencies: + readable-stream "~1.1.9" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +emoji-regex@^6.1.0: + version "6.5.1" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + +end-of-stream@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf" + dependencies: + once "~1.3.0" + +engine.io-client@~1.8.4: + version "1.8.4" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.4.tgz#9fe85dee25853ca6babe25bd2ad68710863e91c2" + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "2.3.3" + engine.io-parser "1.3.2" + has-cors "1.1.0" + indexof "0.0.1" + parsejson "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + ws "1.1.2" + xmlhttprequest-ssl "1.5.3" + yeast "0.1.2" + +engine.io-parser@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.2.tgz#937b079f0007d0893ec56d46cb220b8cb435220a" + dependencies: + after "0.8.2" + arraybuffer.slice "0.0.6" + base64-arraybuffer "0.1.5" + blob "0.0.4" + has-binary "0.1.7" + wtf-8 "1.0.0" + +engine.io@~1.8.4: + version "1.8.4" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.4.tgz#77bce12b80e5d60429337fec3b0daf691ebc9003" + dependencies: + accepts "1.3.3" + base64id "1.0.0" + cookie "0.3.1" + debug "2.3.3" + engine.io-parser "1.3.2" + ws "1.1.4" + +error-ex@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.8.0.tgz#3b00385e85729932beffa9163bbea1234e932914" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.0" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.27" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.27.tgz#bf926b058c62b1cb5de1a887930673b6aa6d9a66" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + +es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-symbol "^3.1" + +es6-map@^0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" + +es6-promise@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a" + +es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" + +es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + dependencies: + d "1" + es5-ext "~0.10.14" + +es6-weak-map@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-config-airbnb-base@^11.3.0: + version "11.3.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.3.1.tgz#c0ab108c9beed503cb999e4c60f4ef98eda0ed30" + dependencies: + eslint-restricted-globals "^0.1.1" + +eslint-config-airbnb@^15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-15.1.0.tgz#fd432965a906e30139001ba830f58f73aeddae8e" + dependencies: + eslint-config-airbnb-base "^11.3.0" + +eslint-config-standard@10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz#c061e4d066f379dc17cd562c64e819b4dd454591" + +eslint-import-resolver-node@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz#4422574cde66a9a7b099938ee4d508a199e0e3cc" + dependencies: + debug "^2.6.8" + resolve "^1.2.0" + +eslint-module-utils@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" + dependencies: + debug "^2.6.8" + pkg-dir "^1.0.0" + +eslint-plugin-import@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.7.0.tgz#21de33380b9efb55f5ef6d2e210ec0e07e7fa69f" + dependencies: + builtin-modules "^1.1.1" + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.1.1" + has "^1.0.1" + lodash.cond "^4.3.0" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + +eslint-plugin-jsx-a11y@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-5.1.1.tgz#5c96bb5186ca14e94db1095ff59b3e2bd94069b1" + dependencies: + aria-query "^0.7.0" + array-includes "^3.0.3" + ast-types-flow "0.0.7" + axobject-query "^0.1.0" + damerau-levenshtein "^1.0.0" + emoji-regex "^6.1.0" + jsx-ast-utils "^1.4.0" + +eslint-plugin-node@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-5.1.1.tgz#a7ed956e780c22aef6afd1116005acd82f26eac6" + dependencies: + ignore "^3.3.3" + minimatch "^3.0.4" + resolve "^1.3.3" + semver "5.3.0" + +eslint-plugin-promise@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca" + +eslint-plugin-react@^7.1.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.2.1.tgz#c2673526ed6571b08c69c5f453d03f5f13e8ddbe" + dependencies: + doctrine "^2.0.0" + has "^1.0.1" + jsx-ast-utils "^2.0.0" + +eslint-plugin-standard@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" + +eslint-restricted-globals@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" + +eslint@3.19.0: + version "3.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" + dependencies: + babel-code-frame "^6.16.0" + chalk "^1.1.3" + concat-stream "^1.5.2" + debug "^2.1.1" + doctrine "^2.0.0" + escope "^3.6.0" + espree "^3.4.0" + esquery "^1.0.0" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.0.3" + globals "^9.14.0" + ignore "^3.2.0" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.7.5" + strip-bom "^3.0.0" + strip-json-comments "~2.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.4.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.0.tgz#98358625bdd055861ea27e2867ea729faf463d8d" + dependencies: + acorn "^5.1.1" + acorn-jsx "^3.0.0" + +esprima@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esquery@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" + dependencies: + estraverse "^4.1.0" + object-assign "^4.0.1" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" + +event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + dependencies: + d "1" + es5-ext "~0.10.14" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +expand-tilde@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + dependencies: + os-homedir "^1.0.1" + +expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + dependencies: + homedir-polyfill "^1.0.1" + +express@^4.15.3: + version "4.15.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.15.4.tgz#032e2253489cf8fce02666beca3d11ed7a2daed1" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.2" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.8" + depd "~1.1.1" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + finalhandler "~1.0.4" + fresh "0.5.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.5" + qs "6.5.0" + range-parser "~1.2.0" + send "0.15.4" + serve-static "1.12.4" + setprototypeof "1.0.3" + statuses "~1.3.1" + type-is "~1.6.15" + utils-merge "1.0.0" + vary "~1.1.1" + +extend@^3.0.0, extend@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extend@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-1.2.1.tgz#a0f5fd6cfc83a5fe49ef698d60ec8a624dd4576c" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.3.0, extsprintf@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +fancy-log@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948" + dependencies: + chalk "^1.1.1" + time-stamp "^1.0.0" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +finalhandler@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.4.tgz#18574f2e7c4b98b8ae3b230c21f201f31bdb3fb7" + dependencies: + debug "2.6.8" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.1" + statuses "~1.3.1" + unpipe "~1.0.0" + +find-index@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +findup-sync@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + dependencies: + detect-file "^0.1.0" + is-glob "^2.0.1" + micromatch "^2.3.7" + resolve-dir "^0.1.0" + +fined@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fined/-/fined-1.1.0.tgz#b37dc844b76a2f5e7081e884f7c0ae344f153476" + dependencies: + expand-tilde "^2.0.2" + is-plain-object "^2.0.3" + object.defaults "^1.1.0" + object.pick "^1.2.0" + parse-filepath "^1.0.1" + +first-chunk-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" + +flagged-respawn@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5" + +flat-cache@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + dependencies: + for-in "^1.0.1" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + +fresh@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" + +fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + +fs-extra@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.1.tgz#7fc0c6c8957f983f57f306a24e5b9ddd8d0dd880" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^3.0.0" + universalify "^0.1.0" + +fs-readdir-recursive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.36" + +fstream-ignore@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2, function-bind@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gaze@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f" + dependencies: + globule "~0.1.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob-stream@^3.1.5: + version "3.1.18" + resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b" + dependencies: + glob "^4.3.1" + glob2base "^0.0.12" + minimatch "^2.0.1" + ordered-read-streams "^0.1.0" + through2 "^0.6.1" + unique-stream "^1.0.0" + +glob-watcher@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b" + dependencies: + gaze "^0.5.1" + +glob2base@^0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" + dependencies: + find-index "^0.1.1" + +glob@^4.3.1: + version "4.5.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "^2.0.1" + once "^1.3.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@~3.1.21: + version "3.1.21" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd" + dependencies: + graceful-fs "~1.2.0" + inherits "1" + minimatch "~0.2.11" + +global-modules@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + dependencies: + global-prefix "^0.1.4" + is-windows "^0.2.0" + +global-prefix@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + dependencies: + homedir-polyfill "^1.0.0" + ini "^1.3.4" + is-windows "^0.2.0" + which "^1.2.12" + +globals@^9.14.0, globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globule@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5" + dependencies: + glob "~3.1.21" + lodash "~1.0.1" + minimatch "~0.2.11" + +glogg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5" + dependencies: + sparkles "^1.0.0" + +graceful-fs@^3.0.0: + version "3.0.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" + dependencies: + natives "^1.1.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +graceful-fs@~1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" + +gulp-babel@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/gulp-babel/-/gulp-babel-6.1.2.tgz#7c0176e4ba3f244c60588a0c4b320a45d1adefce" + dependencies: + babel-core "^6.0.2" + gulp-util "^3.0.0" + object-assign "^4.0.1" + replace-ext "0.0.1" + through2 "^2.0.0" + vinyl-sourcemaps-apply "^0.2.0" + +gulp-concat@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/gulp-concat/-/gulp-concat-2.6.1.tgz#633d16c95d88504628ad02665663cee5a4793353" + dependencies: + concat-with-sourcemaps "^1.0.0" + through2 "^2.0.0" + vinyl "^2.0.0" + +gulp-minify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gulp-minify/-/gulp-minify-1.0.0.tgz#f41ba577eba44b4b4f514b6306c69ddd3f9a1ffc" + dependencies: + gulp-util "^2.2.14" + minimatch "^3.0.2" + through2 "^0.4.0" + uglify-es "^3.0.3" + +gulp-shell@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/gulp-shell/-/gulp-shell-0.6.3.tgz#2eaa6edfffa8bdff7a8f0b9f9852876f33331c6b" + dependencies: + async "^2.1.5" + gulp-util "^3.0.8" + lodash "^4.17.4" + through2 "^2.0.3" + +gulp-util@^2.2.14: + version "2.2.20" + resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-2.2.20.tgz#d7146e5728910bd8f047a6b0b1e549bc22dbd64c" + dependencies: + chalk "^0.5.0" + dateformat "^1.0.7-1.2.3" + lodash._reinterpolate "^2.4.1" + lodash.template "^2.4.1" + minimist "^0.2.0" + multipipe "^0.1.0" + through2 "^0.5.0" + vinyl "^0.2.1" + +gulp-util@^3.0.0, gulp-util@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" + dependencies: + array-differ "^1.0.0" + array-uniq "^1.0.2" + beeper "^1.0.0" + chalk "^1.0.0" + dateformat "^2.0.0" + fancy-log "^1.1.0" + gulplog "^1.0.0" + has-gulplog "^0.1.0" + lodash._reescape "^3.0.0" + lodash._reevaluate "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.template "^3.0.0" + minimist "^1.1.0" + multipipe "^0.1.2" + object-assign "^3.0.0" + replace-ext "0.0.1" + through2 "^2.0.0" + vinyl "^0.5.0" + +gulp@^3.9.1: + version "3.9.1" + resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4" + dependencies: + archy "^1.0.0" + chalk "^1.0.0" + deprecated "^0.0.1" + gulp-util "^3.0.0" + interpret "^1.0.0" + liftoff "^2.1.0" + minimist "^1.1.0" + orchestrator "^0.3.0" + pretty-hrtime "^1.0.0" + semver "^4.1.0" + tildify "^1.0.0" + v8flags "^2.0.2" + vinyl-fs "^0.3.0" + +gulplog@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" + dependencies: + glogg "^1.0.0" + +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +has-ansi@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + dependencies: + ansi-regex "^0.2.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-binary@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + dependencies: + isarray "0.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + +has-gulplog@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" + dependencies: + sparkles "^1.0.0" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + dependencies: + parse-passwd "^1.0.0" + +hosted-git-info@^2.1.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + +http-errors@~1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +ignore@^3.2.0, ignore@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@^1.3.4, ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +interpret@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" + +invariant@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +ipaddr.js@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0" + +is-absolute@^0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb" + dependencies: + is-relative "^0.2.1" + is-windows "^0.2.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.10.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-plain-object@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-relative@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5" + dependencies: + is-unc-path "^0.1.1" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-unc-path@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.2.tgz#6ab053a72573c10250ff416a3814c35178af39b9" + dependencies: + unc-path-regex "^0.1.0" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0, isobject@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.5.1: + version "3.9.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.1.tgz#08775cebdfdd359209f0d2acd383c8f86a6904a0" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json3@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +json5@^0.5.0, json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jsx-ast-utils@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" + +jsx-ast-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.0.tgz#ec06a3d60cf307e5e119dac7bad81e89f096f0f8" + dependencies: + array-includes "^3.0.3" + +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +liftoff@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385" + dependencies: + extend "^3.0.0" + findup-sync "^0.4.2" + fined "^1.0.1" + flagged-respawn "^0.3.2" + lodash.isplainobject "^4.0.4" + lodash.isstring "^4.0.1" + lodash.mapvalues "^4.4.0" + rechoir "^0.6.2" + resolve "^1.1.7" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._basetostring@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" + +lodash._basevalues@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" + +lodash._escapehtmlchar@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz#df67c3bb6b7e8e1e831ab48bfa0795b92afe899d" + dependencies: + lodash._htmlescapes "~2.4.1" + +lodash._escapestringchar@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz#ecfe22618a2ade50bfeea43937e51df66f0edb72" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._htmlescapes@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz#32d14bf0844b6de6f8b62a051b4f67c228b624cb" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash._isnative@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._isnative/-/lodash._isnative-2.4.1.tgz#3ea6404b784a7be836c7b57580e1cdf79b14832c" + +lodash._objecttypes@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz#7c0b7f69d98a1f76529f890b0cdb1b4dfec11c11" + +lodash._reescape@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" + +lodash._reevaluate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" + +lodash._reinterpolate@^2.4.1, lodash._reinterpolate@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz#4f1227aa5a8711fc632f5b07a1f4607aab8b3222" + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + +lodash._reunescapedhtml@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz#747c4fc40103eb3bb8a0976e571f7a2659e93ba7" + dependencies: + lodash._htmlescapes "~2.4.1" + lodash.keys "~2.4.1" + +lodash._root@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + +lodash._shimkeys@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz#6e9cc9666ff081f0b5a6c978b83e242e6949d203" + dependencies: + lodash._objecttypes "~2.4.1" + +lodash.cond@^4.3.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" + +lodash.defaults@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-2.4.1.tgz#a7e8885f05e68851144b6e12a8f3678026bc4c54" + dependencies: + lodash._objecttypes "~2.4.1" + lodash.keys "~2.4.1" + +lodash.escape@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" + dependencies: + lodash._root "^3.0.0" + +lodash.escape@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-2.4.1.tgz#2ce12c5e084db0a57dda5e5d1eeeb9f5d175a3b4" + dependencies: + lodash._escapehtmlchar "~2.4.1" + lodash._reunescapedhtml "~2.4.1" + lodash.keys "~2.4.1" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.isobject@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.4.1.tgz#5a2e47fe69953f1ee631a7eba1fe64d2d06558f5" + dependencies: + lodash._objecttypes "~2.4.1" + +lodash.isplainobject@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.keys@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.4.1.tgz#48dea46df8ff7632b10d706b8acb26591e2b3727" + dependencies: + lodash._isnative "~2.4.1" + lodash._shimkeys "~2.4.1" + lodash.isobject "~2.4.1" + +lodash.mapvalues@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash.template@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.4.1.tgz#9e611007edf629129a974ab3c48b817b3e1cf20d" + dependencies: + lodash._escapestringchar "~2.4.1" + lodash._reinterpolate "~2.4.1" + lodash.defaults "~2.4.1" + lodash.escape "~2.4.1" + lodash.keys "~2.4.1" + lodash.templatesettings "~2.4.1" + lodash.values "~2.4.1" + +lodash.template@^3.0.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" + dependencies: + lodash._basecopy "^3.0.0" + lodash._basetostring "^3.0.0" + lodash._basevalues "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + lodash.keys "^3.0.0" + lodash.restparam "^3.0.0" + lodash.templatesettings "^3.0.0" + +lodash.templatesettings@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + +lodash.templatesettings@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz#ea76c75d11eb86d4dbe89a83893bb861929ac699" + dependencies: + lodash._reinterpolate "~2.4.1" + lodash.escape "~2.4.1" + +lodash.values@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.4.1.tgz#abf514436b3cb705001627978cbcf30b1280eea4" + dependencies: + lodash.keys "~2.4.1" + +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +lodash@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" + +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + +lru-cache@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +map-cache@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +meow@^3.3.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5, micromatch@^2.3.7: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +mime-db@~1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.29.0.tgz#48d26d235589651704ac5916ca06001914266878" + +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: + version "2.1.16" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.16.tgz#2b858a52e5ecd516db897ac2be87487830698e23" + dependencies: + mime-db "~1.29.0" + +mime@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +minimatch@^2.0.1: + version "2.0.10" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + dependencies: + brace-expansion "^1.0.0" + +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimatch@~0.2.11: + version "0.2.14" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.0.tgz#4dffe525dae2b864c66c2e23c6271d7afdecefce" + +minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +multipipe@^0.1.0, multipipe@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" + dependencies: + duplexer2 "0.0.2" + +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + +nan@2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.3.5.tgz#822a0dc266290ce4cd3a12282ca3e7e364668a08" + +nan@^2.3.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" + +natives@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +node-pre-gyp@^0.6.36: + version "0.6.36" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786" + dependencies: + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "^2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^2.2.1" + tar-pack "^3.4.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + +object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + +object.defaults@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf" + dependencies: + array-each "^1.0.1" + array-slice "^1.0.0" + for-own "^1.0.0" + isobject "^3.0.0" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.2.0.tgz#b5392bee9782da6d9fb7d6afaf539779f1234c2b" + dependencies: + isobject "^2.1.0" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +once@~1.3.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +optimist@^0.6: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +options@>=0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + +orchestrator@^0.3.0: + version "0.3.8" + resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e" + dependencies: + end-of-stream "~0.1.5" + sequencify "~0.0.7" + stream-consume "~0.1.0" + +ordered-read-streams@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz#fd565a9af8eb4473ba69b6ed8a34352cb552f126" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-shim@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +p-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-map@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.1.1.tgz#05f5e4ae97a068371bc2a5cc86bfbdbc19c4ae7a" + +parse-filepath@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73" + dependencies: + is-absolute "^0.2.3" + map-cache "^0.2.0" + path-root "^0.1.1" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + +parsejson@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" + dependencies: + better-assert "~1.0.0" + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + dependencies: + better-assert "~1.0.0" + +parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + dependencies: + path-root-regex "^0.1.0" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +pre-commit@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6" + dependencies: + cross-spawn "^5.0.1" + spawn-sync "^1.0.15" + which "1.2.x" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +pretty-hrtime@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" + +private@^0.1.6, private@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" + +process-nextick-args@^1.0.6, process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +progress@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +proxy-addr@~1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.4.0" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +pty.js@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pty.js/-/pty.js-0.3.1.tgz#81f5bed332d6e5e7ab685688d1ba0373410d51b5" + dependencies: + extend "~1.2.1" + nan "2.3.5" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49" + +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +randomatic@^1.1.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +rc@^1.1.7: + version "1.2.1" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +"readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.17: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + +regenerator-runtime@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" + +regenerator-transform@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.0.tgz#f9ab3eac9cc2de38431d996a6a8abf1c50f2e459" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + +replace-ext@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + +request@^2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-dir@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + dependencies: + expand-tilde "^1.2.2" + global-modules "^0.2.3" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" + dependencies: + path-parse "^1.0.5" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" + dependencies: + glob "^7.0.5" + +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + +safe-buffer@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" + +safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + +semver@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +semver@^4.1.0: + version "4.3.6" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + +send@0.15.4: + version "0.15.4" + resolved "https://registry.yarnpkg.com/send/-/send-0.15.4.tgz#985faa3e284b0273c793364a35c6737bd93905b9" + dependencies: + debug "2.6.8" + depd "~1.1.1" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + fresh "0.5.0" + http-errors "~1.6.2" + mime "1.3.4" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.1" + +sequencify@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c" + +serve-favicon@^2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.4.3.tgz#5986b17b0502642b641c21f818b1acce32025d23" + dependencies: + etag "~1.8.0" + fresh "0.5.0" + ms "2.0.0" + parseurl "~1.3.1" + safe-buffer "5.0.1" + +serve-static@1.12.4: + version "1.12.4" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.4.tgz#9b6aa98eeb7253c4eedc4c1f6fdbca609901a961" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.15.4" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +shelljs@^0.7.5: + version "0.7.8" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +socket.io-adapter@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" + dependencies: + debug "2.3.3" + socket.io-parser "2.3.1" + +socket.io-client@1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.4.tgz#ec9f820356ed99ef6d357f0756d648717bdd4281" + dependencies: + backo2 "1.0.2" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "2.3.3" + engine.io-client "~1.8.4" + has-binary "0.1.7" + indexof "0.0.1" + object-component "0.0.3" + parseuri "0.0.5" + socket.io-parser "2.3.1" + to-array "0.1.4" + +socket.io-parser@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" + dependencies: + component-emitter "1.1.2" + debug "2.2.0" + isarray "0.0.1" + json3 "3.3.2" + +socket.io@^1.3.7: + version "1.7.4" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.4.tgz#2f7ecedc3391bf2d5c73e291fe233e6e34d4dd00" + dependencies: + debug "2.3.3" + engine.io "~1.8.4" + has-binary "0.1.7" + object-assign "4.1.0" + socket.io-adapter "0.5.0" + socket.io-client "1.7.4" + socket.io-parser "2.3.1" + +source-map-support@^0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" + dependencies: + source-map "^0.5.6" + +source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6, source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +sparkles@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" + +spawn-sync@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + dependencies: + concat-stream "^1.4.7" + os-shim "^0.1.2" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +"statuses@>= 1.3.1 < 2", statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stream-consume@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + dependencies: + ansi-regex "^0.2.1" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794" + dependencies: + first-chunk-stream "^1.0.0" + is-utf8 "^0.2.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +tar-pack@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through2@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b" + dependencies: + readable-stream "~1.0.17" + xtend "~2.1.1" + +through2@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.5.1.tgz#dfdd012eb9c700e2323fd334f38ac622ab372da7" + dependencies: + readable-stream "~1.0.17" + xtend "~3.0.0" + +through2@^0.6.1: + version "0.6.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" + dependencies: + readable-stream ">=1.0.33-1 <1.1.0-0" + xtend ">=4.0.0 <4.1.0-0" + +through2@^2.0.0, through2@^2.0.1, through2@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +tildify@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a" + dependencies: + os-homedir "^1.0.0" + +time-stamp@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-is@~1.6.15: + version "1.6.15" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.15" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uglify-es@^3.0.3: + version "3.0.27" + resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.0.27.tgz#391790388f369196be23a49caeb0d5c424fa774e" + dependencies: + commander "~2.11.0" + source-map "~0.5.1" + +uid-number@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +ultron@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + +unc-path-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + +unique-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b" + +universalify@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + +v8flags@^2.0.10, v8flags@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" + dependencies: + user-home "^1.1.1" + +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +vary@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vinyl-fs@^0.3.0: + version "0.3.14" + resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6" + dependencies: + defaults "^1.0.0" + glob-stream "^3.1.5" + glob-watcher "^0.0.6" + graceful-fs "^3.0.0" + mkdirp "^0.5.0" + strip-bom "^1.0.0" + through2 "^0.6.1" + vinyl "^0.4.0" + +vinyl-sourcemaps-apply@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" + dependencies: + source-map "^0.5.1" + +vinyl@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.2.3.tgz#bca938209582ec5a49ad538a00fa1f125e513252" + dependencies: + clone-stats "~0.0.1" + +vinyl@^0.4.0: + version "0.4.6" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" + dependencies: + clone "^0.2.0" + clone-stats "^0.0.1" + +vinyl@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + +which@1.2.x: + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + dependencies: + isexe "^2.0.0" + +which@^1.2.12, which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +ws@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + +ws@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + +wtf-8@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + +xmlhttprequest-ssl@1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" + +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +xtend@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" + dependencies: + object-keys "~0.4.0" + +xtend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-3.0.0.tgz#5cce7407baf642cba7becda568111c493f59665a" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"