├── .codeclimate.yml ├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── dist ├── dual-emitter.js └── dual-emitter.min.js ├── index.js ├── package.json └── test.js /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | languages: 2 | JavaScript: true 3 | exclude_paths: 4 | - "dist/**/*" 5 | - "dist/*.js" 6 | - "dist/**/*.js" 7 | - "dist/**.js" 8 | - "dist/dual-emitter.js" 9 | - "dist/dual-emitter.min.js" 10 | 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # .editorconfig 2 | # 3 | # Copyright (c) 2015 Charlike Mike Reagent, contributors. 4 | # Released under the MIT license. 5 | # 6 | 7 | root = true 8 | 9 | [*] 10 | charset = utf-8 11 | end_of_line = lf 12 | indent_size = 2 13 | indent_style = space 14 | 15 | [*.js] 16 | insert_final_newline = true 17 | trim_trailing_whitespace = true 18 | 19 | [*.php] 20 | indent_size = 4 21 | insert_final_newline = true 22 | trim_trailing_whitespace = true 23 | 24 | [*.md] 25 | insert_final_newline = false 26 | trim_trailing_whitespace = false 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore 2 | # 3 | # Copyright (c) 2015 Charlike Mike Reagent, contributors. 4 | # Released under the MIT license. 5 | # 6 | 7 | # Always-ignore dirs # 8 | # #################### 9 | _gh_pages 10 | node_modules 11 | bower_components 12 | components 13 | vendor 14 | build 15 | dest 16 | src 17 | lib-cov 18 | coverage 19 | nbproject 20 | cache 21 | temp 22 | tmp 23 | dual-emitter 24 | 25 | # Packages # 26 | # ########## 27 | *.7z 28 | *.dmg 29 | *.gz 30 | *.iso 31 | *.jar 32 | *.rar 33 | *.tar 34 | *.zip 35 | 36 | # OS, Logs and databases # 37 | # ######################### 38 | *.pid 39 | *.dat 40 | *.log 41 | *.sql 42 | *.sqlite 43 | *~ 44 | ~* 45 | 46 | # Another files # 47 | # ############### 48 | Icon? 49 | .DS_Store* 50 | Thumbs.db 51 | ehthumbs.db 52 | Desktop.ini 53 | npm-debug.log 54 | .directory 55 | ._* 56 | lcov.info 57 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: "node_js" 2 | sudo: false 3 | 4 | node_js: 5 | - "0.10" 6 | - "0.12" 7 | - "1" 8 | - "2" 9 | 10 | notifications: 11 | email: 12 | on_success: never 13 | on_failure: never 14 | 15 | before_script: 16 | - npm install standard 17 | - standard 18 | 19 | script: 20 | - npm install istanbul-harmony 21 | - node --harmony node_modules/.bin/istanbul cover test.js 22 | 23 | after_success: 24 | - npm install coveralls 25 | - cat coverage/lcov.info | coveralls 26 | - mv coverage/lcov.info . 27 | 28 | matrix: 29 | allow_failures: 30 | - node_js: "0.10" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 0.0.0 - 2015-07-29 4 | - first commits -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Contributions are always welcome! 4 | 5 | **Before spending lots of time on something, ask for feedback on your idea first!** 6 | 7 | Please search issues and pull requests before adding something new to avoid duplicating efforts and conversations. 8 | 9 | 10 | ## Installing 11 | 12 | Fork and clone the repo, then `npm install` to install all dependencies and `npm test` to ensure all is okey before you start anything. 13 | 14 | 15 | ## Testing 16 | 17 | Tests are run with `npm test`. Please ensure all tests are passing before submitting a pull request (unless you're creating a failing test to increase test coverage or show a problem). 18 | 19 | ## Code Style 20 | 21 | [![standard][standard-image]][standard-url] 22 | 23 | This repository uses [`standard`][standard-url] to maintain code style and consistency, and to avoid style arguments. You are encouraged to install it globally. `npm test` runs `standard` so you don't have to! 24 | 25 | ``` 26 | npm i standard -g 27 | ``` 28 | 29 | It is intentional to don't have `standard`, `istanbul` and `coveralls` in the devDependencies. Travis will handle all that stuffs. That approach will save bandwidth also installing and development time. 30 | 31 | [standard-image]: https://cdn.rawgit.com/feross/standard/master/badge.svg 32 | [standard-url]: https://github.com/feross/standard -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright (c) 2015 [Charlike Make Reagent](http://j.mp/1stW47C) 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | > SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [dual-emitter][author-www-url] [![npmjs.com][npmjs-img]][npmjs-url] [![The MIT License][license-img]][license-url] 2 | 3 | > EventEmitter done right and no dependencies. For nodejs and the browser (>= IE8). Can emit custom or DOM events. 4 | 5 | [![code climate][codeclimate-img]][codeclimate-url] [![standard code style][standard-img]][standard-url] [![travis build status][travis-img]][travis-url] [![coverage status][coveralls-img]][coveralls-url] [![dependency status][david-img]][david-url] 6 | 7 | 8 | ## Install 9 | ``` 10 | npm i dual-emitter --save 11 | npm test 12 | ``` 13 | 14 | 15 | ## Features 16 | - minimal, yet simple to use 17 | - just 4kb minified - no jQuery, no dependencies 18 | - works on the browser (**even IE8**), [use dist/dual-emitter.min.js](./dist/dual-emitter.min.js) 19 | - works on the server, just install it and `require` it 20 | - can emit (trigger or whatever you call it) DOM events manually 21 | - have `.on`, `.off`, `.once` and `.emit` methods 22 | 23 | 24 | ## Usage 25 | > For more use-cases see the [tests](./test.js) 26 | 27 | ```js 28 | var DualEmitter = require('dual-emitter') 29 | var emitter = new DualEmitter() 30 | 31 | function handler () { 32 | console.log('foo bar') 33 | } 34 | 35 | emitter 36 | .once('custom', function () { 37 | console.log('executed once') 38 | }) 39 | .on('foo', handler) 40 | .emit('custom', 'abc') 41 | .emit('custom', 'foo', ['bar', 'baz']) 42 | .emit('custom') 43 | .off('foo', handler) 44 | .on('click', function () { 45 | console.log('link clicked') 46 | }, document.body.querySelector('a[href]')) 47 | ``` 48 | 49 | ## API 50 | ### [DualEmitter](./index.js#L30) 51 | > Create a new instance of `DualEmitter`. 52 | 53 | - `[events]` **{Object}** Initialize with default events. 54 | 55 | **Example** 56 | 57 | ```js 58 | var DualEmitter = require('dual-emitter') 59 | var emitter = new DualEmitter() 60 | ``` 61 | 62 | ### [.on](./index.js#L64) 63 | > Add/bind event listener to custom or DOM event. Notice that `this` in event handler function vary - it can be the DOM element or DualEmitter instance. 64 | 65 | - `` **{String}** event name 66 | - `` **{Function}** event handler 67 | - `[el]` **{Object}** optional DOM element 68 | - `returns` **{DualEmitter}** DualEmitter for chaining 69 | 70 | **Example** 71 | 72 | ```js 73 | function handler (a, b) { 74 | console.log('hi', a, b) //=> hi 123 bar 75 | } 76 | 77 | function onclick (evt) { 78 | console.log(evt, 'clicked') 79 | } 80 | 81 | var element = document.body.querySelector('a.link') 82 | 83 | emitter.on('custom', handler).emit('custom', 123, 'bar') 84 | emitter.on('click', onclick, element).off('click', onclick, element) 85 | ``` 86 | 87 | ### [.off](./index.js#L103) 88 | > Remove/unbind event listener of custom or DOM event. 89 | 90 | - `` **{String}** event name 91 | - `` **{Function}** event handler 92 | - `[el]` **{Object}** optional DOM element 93 | - `returns` **{DualEmitter}** DualEmitter for chaining 94 | 95 | **Example** 96 | 97 | ```js 98 | var element = document.body.querySelector('a.link') 99 | emitter.off('custom', handler) 100 | emitter.off('click', onclick, element) 101 | ``` 102 | 103 | ### [.once](./index.js#L147) 104 | > Add one-time event listener to custom or DOM event. Notice that `this` in event handler function vary - it can be the DOM element or DualEmitter instance. 105 | 106 | - `` **{String}** event name 107 | - `` **{Function}** event handler 108 | - `[el]` **{Object}** optional DOM element 109 | - `returns` **{DualEmitter}** DualEmitter for chaining 110 | 111 | **Example** 112 | 113 | ```js 114 | emitter 115 | .once('custom', function () { 116 | console.log('executed one time') 117 | }) 118 | .emit('custom') 119 | .emit('custom') 120 | 121 | var element = document.body.querySelector('a.link') 122 | emitter.once('click', function () { 123 | console.log('listen for click event only once') 124 | }, element) 125 | ``` 126 | 127 | ### [.emit](./index.js#L196) 128 | > Emit/execute some type of event listener. You also can emit DOM events if last argument is the DOM element that have attached event listener. 129 | 130 | - `` **{String}** event name 131 | - `[args...]` **{Mixed}** context to pass to event listeners 132 | - `[el]` **{Object}** optional DOM element 133 | - `returns` **{DualEmitter}** DualEmitter for chaining 134 | 135 | **Example** 136 | 137 | ```js 138 | var i = 0 139 | 140 | emitter 141 | .on('custom', function () { 142 | console.log('i ==', i++, arguments) 143 | }) 144 | .emit('custom') 145 | .emit('custom', 123) 146 | .emit('custom', 'foo', 'bar', 'baz') 147 | .emit('custom', [1, 2, 3], 4, 5) 148 | 149 | // or even emit DOM events, but you should 150 | // give the element as last argument to `.emit` method 151 | var element = document.body.querySelector('a.link') 152 | var clicks = 0 153 | 154 | emitter 155 | .on('click', function (a) { 156 | console.log(a, 'clicked', clicks++) 157 | }, element) 158 | .emit('click', 123, element) 159 | .emit('click', element) 160 | .emit('click', foo, element) 161 | ``` 162 | 163 | ### [._isDom](./index.js#L231) 164 | > Check that given `val` is DOM element. Used internally. 165 | 166 | - `val` **{Mixed}** 167 | - `returns` **{Boolean}** 168 | 169 | **Example** 170 | 171 | ```js 172 | var element = document.body.querySelector('a.link') 173 | 174 | emitter._isDom(element) //=> true 175 | emitter._isDom({a: 'b'}) //=> false 176 | ``` 177 | 178 | ### [._hasOwn](./index.js#L255) 179 | > Check that `key` exists in the given `obj`. 180 | 181 | - `obj` **{Object}** 182 | - `key` **{String}** 183 | - `returns` **{Boolean}** 184 | 185 | **Example** 186 | 187 | ```js 188 | var obj = {a: 'b'} 189 | 190 | emitter._hasOwn(obj, 'a') //=> true 191 | emitter._hasOwn(obj, 'foo') //=> false 192 | ``` 193 | 194 | ### [.extend](index.js#L287) 195 | > Static method for inheriting both the prototype and static methods of the `DualEmitter` class. 196 | 197 | - `Ctor` **{Function}** The constructor to extend. 198 | 199 | **Example** 200 | 201 | ```js 202 | function MyApp(options) { 203 | DualEmitter.call(this) 204 | } 205 | DualEmitter.extend(MyApp) 206 | 207 | // Optionally pass another object to extend onto `MyApp` 208 | function MyApp(options) { 209 | DualEmitter.call(this) 210 | Foo.call(this, options) 211 | } 212 | DualEmitter.extend(MyApp, Foo.prototype) 213 | ``` 214 | 215 | 216 | ## Contributing 217 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/tunnckoCore/dual-emitter/issues/new). 218 | But before doing anything, please read the [CONTRIBUTING.md](./CONTRIBUTING.md) guidelines. 219 | 220 | 221 | ## [Charlike Make Reagent](http://j.mp/1stW47C) [![new message to charlike][new-message-img]][new-message-url] [![freenode #charlike][freenode-img]][freenode-url] 222 | 223 | [![tunnckocore.tk][author-www-img]][author-www-url] [![keybase tunnckocore][keybase-img]][keybase-url] [![tunnckoCore npm][author-npm-img]][author-npm-url] [![tunnckoCore twitter][author-twitter-img]][author-twitter-url] [![tunnckoCore github][author-github-img]][author-github-url] 224 | 225 | 226 | [npmjs-url]: https://www.npmjs.com/package/dual-emitter 227 | [npmjs-img]: https://img.shields.io/npm/v/dual-emitter.svg?label=dual-emitter 228 | 229 | [license-url]: https://github.com/tunnckoCore/dual-emitter/blob/master/LICENSE.md 230 | [license-img]: https://img.shields.io/badge/license-MIT-blue.svg 231 | 232 | 233 | [codeclimate-url]: https://codeclimate.com/github/tunnckoCore/dual-emitter 234 | [codeclimate-img]: https://img.shields.io/codeclimate/github/tunnckoCore/dual-emitter.svg 235 | 236 | [travis-url]: https://travis-ci.org/tunnckoCore/dual-emitter 237 | [travis-img]: https://img.shields.io/travis/tunnckoCore/dual-emitter.svg 238 | 239 | [coveralls-url]: https://coveralls.io/r/tunnckoCore/dual-emitter 240 | [coveralls-img]: https://img.shields.io/coveralls/tunnckoCore/dual-emitter.svg 241 | 242 | [david-url]: https://david-dm.org/tunnckoCore/dual-emitter 243 | [david-img]: https://img.shields.io/david/tunnckoCore/dual-emitter.svg 244 | 245 | [standard-url]: https://github.com/feross/standard 246 | [standard-img]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg 247 | 248 | 249 | [author-www-url]: http://www.tunnckocore.tk 250 | [author-www-img]: https://img.shields.io/badge/www-tunnckocore.tk-fe7d37.svg 251 | 252 | [keybase-url]: https://keybase.io/tunnckocore 253 | [keybase-img]: https://img.shields.io/badge/keybase-tunnckocore-8a7967.svg 254 | 255 | [author-npm-url]: https://www.npmjs.com/~tunnckocore 256 | [author-npm-img]: https://img.shields.io/badge/npm-~tunnckocore-cb3837.svg 257 | 258 | [author-twitter-url]: https://twitter.com/tunnckoCore 259 | [author-twitter-img]: https://img.shields.io/badge/twitter-@tunnckoCore-55acee.svg 260 | 261 | [author-github-url]: https://github.com/tunnckoCore 262 | [author-github-img]: https://img.shields.io/badge/github-@tunnckoCore-4183c4.svg 263 | 264 | [freenode-url]: http://webchat.freenode.net/?channels=charlike 265 | [freenode-img]: https://img.shields.io/badge/freenode-%23charlike-5654a4.svg 266 | 267 | [new-message-url]: https://github.com/tunnckoCore/messages 268 | [new-message-img]: https://img.shields.io/badge/send%20me-message-green.svg 269 | -------------------------------------------------------------------------------- /dist/dual-emitter.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.DualEmitter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1) { 72 | for (var i = 1; i < arguments.length; i++) { 73 | args[i - 1] = arguments[i]; 74 | } 75 | } 76 | queue.push(new Item(fun, args)); 77 | if (queue.length === 1 && !draining) { 78 | setTimeout(drainQueue, 0); 79 | } 80 | }; 81 | 82 | // v8 likes predictible objects 83 | function Item(fun, array) { 84 | this.fun = fun; 85 | this.array = array; 86 | } 87 | Item.prototype.run = function () { 88 | this.fun.apply(null, this.array); 89 | }; 90 | process.title = 'browser'; 91 | process.browser = true; 92 | process.env = {}; 93 | process.argv = []; 94 | process.version = ''; // empty string to avoid regexp issues 95 | process.versions = {}; 96 | 97 | function noop() {} 98 | 99 | process.on = noop; 100 | process.addListener = noop; 101 | process.once = noop; 102 | process.off = noop; 103 | process.removeListener = noop; 104 | process.removeAllListeners = noop; 105 | process.emit = noop; 106 | 107 | process.binding = function (name) { 108 | throw new Error('process.binding is not supported'); 109 | }; 110 | 111 | // TODO(shtylman) 112 | process.cwd = function () { return '/' }; 113 | process.chdir = function (dir) { 114 | throw new Error('process.chdir is not supported'); 115 | }; 116 | process.umask = function() { return 0; }; 117 | 118 | },{}],3:[function(require,module,exports){ 119 | module.exports = function isBuffer(arg) { 120 | return arg && typeof arg === 'object' 121 | && typeof arg.copy === 'function' 122 | && typeof arg.fill === 'function' 123 | && typeof arg.readUInt8 === 'function'; 124 | } 125 | },{}],4:[function(require,module,exports){ 126 | (function (process,global){ 127 | // Copyright Joyent, Inc. and other Node contributors. 128 | // 129 | // Permission is hereby granted, free of charge, to any person obtaining a 130 | // copy of this software and associated documentation files (the 131 | // "Software"), to deal in the Software without restriction, including 132 | // without limitation the rights to use, copy, modify, merge, publish, 133 | // distribute, sublicense, and/or sell copies of the Software, and to permit 134 | // persons to whom the Software is furnished to do so, subject to the 135 | // following conditions: 136 | // 137 | // The above copyright notice and this permission notice shall be included 138 | // in all copies or substantial portions of the Software. 139 | // 140 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 141 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 142 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 143 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 144 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 145 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 146 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 147 | 148 | var formatRegExp = /%[sdj%]/g; 149 | exports.format = function(f) { 150 | if (!isString(f)) { 151 | var objects = []; 152 | for (var i = 0; i < arguments.length; i++) { 153 | objects.push(inspect(arguments[i])); 154 | } 155 | return objects.join(' '); 156 | } 157 | 158 | var i = 1; 159 | var args = arguments; 160 | var len = args.length; 161 | var str = String(f).replace(formatRegExp, function(x) { 162 | if (x === '%%') return '%'; 163 | if (i >= len) return x; 164 | switch (x) { 165 | case '%s': return String(args[i++]); 166 | case '%d': return Number(args[i++]); 167 | case '%j': 168 | try { 169 | return JSON.stringify(args[i++]); 170 | } catch (_) { 171 | return '[Circular]'; 172 | } 173 | default: 174 | return x; 175 | } 176 | }); 177 | for (var x = args[i]; i < len; x = args[++i]) { 178 | if (isNull(x) || !isObject(x)) { 179 | str += ' ' + x; 180 | } else { 181 | str += ' ' + inspect(x); 182 | } 183 | } 184 | return str; 185 | }; 186 | 187 | 188 | // Mark that a method should not be used. 189 | // Returns a modified function which warns once by default. 190 | // If --no-deprecation is set, then it is a no-op. 191 | exports.deprecate = function(fn, msg) { 192 | // Allow for deprecating things in the process of starting up. 193 | if (isUndefined(global.process)) { 194 | return function() { 195 | return exports.deprecate(fn, msg).apply(this, arguments); 196 | }; 197 | } 198 | 199 | if (process.noDeprecation === true) { 200 | return fn; 201 | } 202 | 203 | var warned = false; 204 | function deprecated() { 205 | if (!warned) { 206 | if (process.throwDeprecation) { 207 | throw new Error(msg); 208 | } else if (process.traceDeprecation) { 209 | console.trace(msg); 210 | } else { 211 | console.error(msg); 212 | } 213 | warned = true; 214 | } 215 | return fn.apply(this, arguments); 216 | } 217 | 218 | return deprecated; 219 | }; 220 | 221 | 222 | var debugs = {}; 223 | var debugEnviron; 224 | exports.debuglog = function(set) { 225 | if (isUndefined(debugEnviron)) 226 | debugEnviron = process.env.NODE_DEBUG || ''; 227 | set = set.toUpperCase(); 228 | if (!debugs[set]) { 229 | if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { 230 | var pid = process.pid; 231 | debugs[set] = function() { 232 | var msg = exports.format.apply(exports, arguments); 233 | console.error('%s %d: %s', set, pid, msg); 234 | }; 235 | } else { 236 | debugs[set] = function() {}; 237 | } 238 | } 239 | return debugs[set]; 240 | }; 241 | 242 | 243 | /** 244 | * Echos the value of a value. Trys to print the value out 245 | * in the best way possible given the different types. 246 | * 247 | * @param {Object} obj The object to print out. 248 | * @param {Object} opts Optional options object that alters the output. 249 | */ 250 | /* legacy: obj, showHidden, depth, colors*/ 251 | function inspect(obj, opts) { 252 | // default options 253 | var ctx = { 254 | seen: [], 255 | stylize: stylizeNoColor 256 | }; 257 | // legacy... 258 | if (arguments.length >= 3) ctx.depth = arguments[2]; 259 | if (arguments.length >= 4) ctx.colors = arguments[3]; 260 | if (isBoolean(opts)) { 261 | // legacy... 262 | ctx.showHidden = opts; 263 | } else if (opts) { 264 | // got an "options" object 265 | exports._extend(ctx, opts); 266 | } 267 | // set default options 268 | if (isUndefined(ctx.showHidden)) ctx.showHidden = false; 269 | if (isUndefined(ctx.depth)) ctx.depth = 2; 270 | if (isUndefined(ctx.colors)) ctx.colors = false; 271 | if (isUndefined(ctx.customInspect)) ctx.customInspect = true; 272 | if (ctx.colors) ctx.stylize = stylizeWithColor; 273 | return formatValue(ctx, obj, ctx.depth); 274 | } 275 | exports.inspect = inspect; 276 | 277 | 278 | // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics 279 | inspect.colors = { 280 | 'bold' : [1, 22], 281 | 'italic' : [3, 23], 282 | 'underline' : [4, 24], 283 | 'inverse' : [7, 27], 284 | 'white' : [37, 39], 285 | 'grey' : [90, 39], 286 | 'black' : [30, 39], 287 | 'blue' : [34, 39], 288 | 'cyan' : [36, 39], 289 | 'green' : [32, 39], 290 | 'magenta' : [35, 39], 291 | 'red' : [31, 39], 292 | 'yellow' : [33, 39] 293 | }; 294 | 295 | // Don't use 'blue' not visible on cmd.exe 296 | inspect.styles = { 297 | 'special': 'cyan', 298 | 'number': 'yellow', 299 | 'boolean': 'yellow', 300 | 'undefined': 'grey', 301 | 'null': 'bold', 302 | 'string': 'green', 303 | 'date': 'magenta', 304 | // "name": intentionally not styling 305 | 'regexp': 'red' 306 | }; 307 | 308 | 309 | function stylizeWithColor(str, styleType) { 310 | var style = inspect.styles[styleType]; 311 | 312 | if (style) { 313 | return '\u001b[' + inspect.colors[style][0] + 'm' + str + 314 | '\u001b[' + inspect.colors[style][1] + 'm'; 315 | } else { 316 | return str; 317 | } 318 | } 319 | 320 | 321 | function stylizeNoColor(str, styleType) { 322 | return str; 323 | } 324 | 325 | 326 | function arrayToHash(array) { 327 | var hash = {}; 328 | 329 | array.forEach(function(val, idx) { 330 | hash[val] = true; 331 | }); 332 | 333 | return hash; 334 | } 335 | 336 | 337 | function formatValue(ctx, value, recurseTimes) { 338 | // Provide a hook for user-specified inspect functions. 339 | // Check that value is an object with an inspect function on it 340 | if (ctx.customInspect && 341 | value && 342 | isFunction(value.inspect) && 343 | // Filter out the util module, it's inspect function is special 344 | value.inspect !== exports.inspect && 345 | // Also filter out any prototype objects using the circular check. 346 | !(value.constructor && value.constructor.prototype === value)) { 347 | var ret = value.inspect(recurseTimes, ctx); 348 | if (!isString(ret)) { 349 | ret = formatValue(ctx, ret, recurseTimes); 350 | } 351 | return ret; 352 | } 353 | 354 | // Primitive types cannot have properties 355 | var primitive = formatPrimitive(ctx, value); 356 | if (primitive) { 357 | return primitive; 358 | } 359 | 360 | // Look up the keys of the object. 361 | var keys = Object.keys(value); 362 | var visibleKeys = arrayToHash(keys); 363 | 364 | if (ctx.showHidden) { 365 | keys = Object.getOwnPropertyNames(value); 366 | } 367 | 368 | // IE doesn't make error fields non-enumerable 369 | // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx 370 | if (isError(value) 371 | && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { 372 | return formatError(value); 373 | } 374 | 375 | // Some type of object without properties can be shortcutted. 376 | if (keys.length === 0) { 377 | if (isFunction(value)) { 378 | var name = value.name ? ': ' + value.name : ''; 379 | return ctx.stylize('[Function' + name + ']', 'special'); 380 | } 381 | if (isRegExp(value)) { 382 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 383 | } 384 | if (isDate(value)) { 385 | return ctx.stylize(Date.prototype.toString.call(value), 'date'); 386 | } 387 | if (isError(value)) { 388 | return formatError(value); 389 | } 390 | } 391 | 392 | var base = '', array = false, braces = ['{', '}']; 393 | 394 | // Make Array say that they are Array 395 | if (isArray(value)) { 396 | array = true; 397 | braces = ['[', ']']; 398 | } 399 | 400 | // Make functions say that they are functions 401 | if (isFunction(value)) { 402 | var n = value.name ? ': ' + value.name : ''; 403 | base = ' [Function' + n + ']'; 404 | } 405 | 406 | // Make RegExps say that they are RegExps 407 | if (isRegExp(value)) { 408 | base = ' ' + RegExp.prototype.toString.call(value); 409 | } 410 | 411 | // Make dates with properties first say the date 412 | if (isDate(value)) { 413 | base = ' ' + Date.prototype.toUTCString.call(value); 414 | } 415 | 416 | // Make error with message first say the error 417 | if (isError(value)) { 418 | base = ' ' + formatError(value); 419 | } 420 | 421 | if (keys.length === 0 && (!array || value.length == 0)) { 422 | return braces[0] + base + braces[1]; 423 | } 424 | 425 | if (recurseTimes < 0) { 426 | if (isRegExp(value)) { 427 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 428 | } else { 429 | return ctx.stylize('[Object]', 'special'); 430 | } 431 | } 432 | 433 | ctx.seen.push(value); 434 | 435 | var output; 436 | if (array) { 437 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 438 | } else { 439 | output = keys.map(function(key) { 440 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 441 | }); 442 | } 443 | 444 | ctx.seen.pop(); 445 | 446 | return reduceToSingleString(output, base, braces); 447 | } 448 | 449 | 450 | function formatPrimitive(ctx, value) { 451 | if (isUndefined(value)) 452 | return ctx.stylize('undefined', 'undefined'); 453 | if (isString(value)) { 454 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 455 | .replace(/'/g, "\\'") 456 | .replace(/\\"/g, '"') + '\''; 457 | return ctx.stylize(simple, 'string'); 458 | } 459 | if (isNumber(value)) 460 | return ctx.stylize('' + value, 'number'); 461 | if (isBoolean(value)) 462 | return ctx.stylize('' + value, 'boolean'); 463 | // For some reason typeof null is "object", so special case here. 464 | if (isNull(value)) 465 | return ctx.stylize('null', 'null'); 466 | } 467 | 468 | 469 | function formatError(value) { 470 | return '[' + Error.prototype.toString.call(value) + ']'; 471 | } 472 | 473 | 474 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 475 | var output = []; 476 | for (var i = 0, l = value.length; i < l; ++i) { 477 | if (hasOwnProperty(value, String(i))) { 478 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 479 | String(i), true)); 480 | } else { 481 | output.push(''); 482 | } 483 | } 484 | keys.forEach(function(key) { 485 | if (!key.match(/^\d+$/)) { 486 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 487 | key, true)); 488 | } 489 | }); 490 | return output; 491 | } 492 | 493 | 494 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 495 | var name, str, desc; 496 | desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; 497 | if (desc.get) { 498 | if (desc.set) { 499 | str = ctx.stylize('[Getter/Setter]', 'special'); 500 | } else { 501 | str = ctx.stylize('[Getter]', 'special'); 502 | } 503 | } else { 504 | if (desc.set) { 505 | str = ctx.stylize('[Setter]', 'special'); 506 | } 507 | } 508 | if (!hasOwnProperty(visibleKeys, key)) { 509 | name = '[' + key + ']'; 510 | } 511 | if (!str) { 512 | if (ctx.seen.indexOf(desc.value) < 0) { 513 | if (isNull(recurseTimes)) { 514 | str = formatValue(ctx, desc.value, null); 515 | } else { 516 | str = formatValue(ctx, desc.value, recurseTimes - 1); 517 | } 518 | if (str.indexOf('\n') > -1) { 519 | if (array) { 520 | str = str.split('\n').map(function(line) { 521 | return ' ' + line; 522 | }).join('\n').substr(2); 523 | } else { 524 | str = '\n' + str.split('\n').map(function(line) { 525 | return ' ' + line; 526 | }).join('\n'); 527 | } 528 | } 529 | } else { 530 | str = ctx.stylize('[Circular]', 'special'); 531 | } 532 | } 533 | if (isUndefined(name)) { 534 | if (array && key.match(/^\d+$/)) { 535 | return str; 536 | } 537 | name = JSON.stringify('' + key); 538 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 539 | name = name.substr(1, name.length - 2); 540 | name = ctx.stylize(name, 'name'); 541 | } else { 542 | name = name.replace(/'/g, "\\'") 543 | .replace(/\\"/g, '"') 544 | .replace(/(^"|"$)/g, "'"); 545 | name = ctx.stylize(name, 'string'); 546 | } 547 | } 548 | 549 | return name + ': ' + str; 550 | } 551 | 552 | 553 | function reduceToSingleString(output, base, braces) { 554 | var numLinesEst = 0; 555 | var length = output.reduce(function(prev, cur) { 556 | numLinesEst++; 557 | if (cur.indexOf('\n') >= 0) numLinesEst++; 558 | return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; 559 | }, 0); 560 | 561 | if (length > 60) { 562 | return braces[0] + 563 | (base === '' ? '' : base + '\n ') + 564 | ' ' + 565 | output.join(',\n ') + 566 | ' ' + 567 | braces[1]; 568 | } 569 | 570 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 571 | } 572 | 573 | 574 | // NOTE: These type checking functions intentionally don't use `instanceof` 575 | // because it is fragile and can be easily faked with `Object.create()`. 576 | function isArray(ar) { 577 | return Array.isArray(ar); 578 | } 579 | exports.isArray = isArray; 580 | 581 | function isBoolean(arg) { 582 | return typeof arg === 'boolean'; 583 | } 584 | exports.isBoolean = isBoolean; 585 | 586 | function isNull(arg) { 587 | return arg === null; 588 | } 589 | exports.isNull = isNull; 590 | 591 | function isNullOrUndefined(arg) { 592 | return arg == null; 593 | } 594 | exports.isNullOrUndefined = isNullOrUndefined; 595 | 596 | function isNumber(arg) { 597 | return typeof arg === 'number'; 598 | } 599 | exports.isNumber = isNumber; 600 | 601 | function isString(arg) { 602 | return typeof arg === 'string'; 603 | } 604 | exports.isString = isString; 605 | 606 | function isSymbol(arg) { 607 | return typeof arg === 'symbol'; 608 | } 609 | exports.isSymbol = isSymbol; 610 | 611 | function isUndefined(arg) { 612 | return arg === void 0; 613 | } 614 | exports.isUndefined = isUndefined; 615 | 616 | function isRegExp(re) { 617 | return isObject(re) && objectToString(re) === '[object RegExp]'; 618 | } 619 | exports.isRegExp = isRegExp; 620 | 621 | function isObject(arg) { 622 | return typeof arg === 'object' && arg !== null; 623 | } 624 | exports.isObject = isObject; 625 | 626 | function isDate(d) { 627 | return isObject(d) && objectToString(d) === '[object Date]'; 628 | } 629 | exports.isDate = isDate; 630 | 631 | function isError(e) { 632 | return isObject(e) && 633 | (objectToString(e) === '[object Error]' || e instanceof Error); 634 | } 635 | exports.isError = isError; 636 | 637 | function isFunction(arg) { 638 | return typeof arg === 'function'; 639 | } 640 | exports.isFunction = isFunction; 641 | 642 | function isPrimitive(arg) { 643 | return arg === null || 644 | typeof arg === 'boolean' || 645 | typeof arg === 'number' || 646 | typeof arg === 'string' || 647 | typeof arg === 'symbol' || // ES6 symbol 648 | typeof arg === 'undefined'; 649 | } 650 | exports.isPrimitive = isPrimitive; 651 | 652 | exports.isBuffer = require('./support/isBuffer'); 653 | 654 | function objectToString(o) { 655 | return Object.prototype.toString.call(o); 656 | } 657 | 658 | 659 | function pad(n) { 660 | return n < 10 ? '0' + n.toString(10) : n.toString(10); 661 | } 662 | 663 | 664 | var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 665 | 'Oct', 'Nov', 'Dec']; 666 | 667 | // 26 Feb 16:19:34 668 | function timestamp() { 669 | var d = new Date(); 670 | var time = [pad(d.getHours()), 671 | pad(d.getMinutes()), 672 | pad(d.getSeconds())].join(':'); 673 | return [d.getDate(), months[d.getMonth()], time].join(' '); 674 | } 675 | 676 | 677 | // log is just a thin wrapper to console.log that prepends a timestamp 678 | exports.log = function() { 679 | console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); 680 | }; 681 | 682 | 683 | /** 684 | * Inherit the prototype methods from one constructor into another. 685 | * 686 | * The Function.prototype.inherits from lang.js rewritten as a standalone 687 | * function (not on Function.prototype). NOTE: If this file is to be loaded 688 | * during bootstrapping this function needs to be rewritten using some native 689 | * functions as prototype setup using normal JavaScript does not work as 690 | * expected during bootstrapping (see mirror.js in r114903). 691 | * 692 | * @param {function} ctor Constructor function which needs to inherit the 693 | * prototype. 694 | * @param {function} superCtor Constructor function to inherit prototype from. 695 | */ 696 | exports.inherits = require('inherits'); 697 | 698 | exports._extend = function(origin, add) { 699 | // Don't do anything if add isn't an object 700 | if (!add || !isObject(add)) return origin; 701 | 702 | var keys = Object.keys(add); 703 | var i = keys.length; 704 | while (i--) { 705 | origin[keys[i]] = add[keys[i]]; 706 | } 707 | return origin; 708 | }; 709 | 710 | function hasOwnProperty(obj, prop) { 711 | return Object.prototype.hasOwnProperty.call(obj, prop); 712 | } 713 | 714 | }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 715 | 716 | },{"./support/isBuffer":3,"_process":2,"inherits":1}],5:[function(require,module,exports){ 717 | /*! 718 | * dual-emitter 719 | * 720 | * Copyright (c) 2015 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk) 721 | * Released under the MIT license. 722 | */ 723 | 724 | /* jshint asi:true */ 725 | 726 | 'use strict' 727 | 728 | var util = require('util') 729 | 730 | /** 731 | * Expose `DualEmitter` 732 | */ 733 | 734 | module.exports = DualEmitter 735 | 736 | /** 737 | * > Create a new instance of `DualEmitter`. 738 | * 739 | * **Example** 740 | * 741 | * ```js 742 | * var DualEmitter = require('dual-emitter') 743 | * var emitter = new DualEmitter() 744 | * ``` 745 | * 746 | * @param {Object} `[events]` Initialize with default events. 747 | * @api public 748 | */ 749 | 750 | function DualEmitter (events) { 751 | if (!(this instanceof DualEmitter)) { 752 | return new DualEmitter(events) 753 | } 754 | 755 | this._events = events && typeof events === 'object' ? events : {} 756 | } 757 | 758 | /** 759 | * > Add/bind event listener to custom or DOM event. 760 | * Notice that `this` in event handler function vary - it can be the DOM element 761 | * or DualEmitter instance. 762 | * 763 | * **Example** 764 | * 765 | * ```js 766 | * function handler (a, b) { 767 | * console.log('hi', a, b) //=> hi 123 bar 768 | * } 769 | * 770 | * function onclick (evt) { 771 | * console.log(evt, 'clicked') 772 | * } 773 | * 774 | * var element = document.body.querySelector('a.link') 775 | * 776 | * emitter.on('custom', handler).emit('custom', 123, 'bar') 777 | * emitter.on('click', onclick, element).off('click', onclick, element) 778 | * ``` 779 | * 780 | * @param {String} `` event name 781 | * @param {Function} `` event handler 782 | * @param {Object} `[el]` optional DOM element 783 | * @return {DualEmitter} DualEmitter for chaining 784 | * @api public 785 | */ 786 | 787 | DualEmitter.prototype.on = function on (name, fn, el) { 788 | if (typeof name !== 'string') { 789 | throw new TypeError('DualEmitter#on expect `name` be string') 790 | } 791 | if (typeof fn !== 'function') { 792 | throw new TypeError('DualEmitter#on expect `fn` be function') 793 | } 794 | 795 | this._events[name] = this._hasOwn(this._events, name) ? this._events[name] : [] 796 | this._events[name].push(fn) 797 | 798 | if (el && this._isDom(el)) { 799 | fn.outerHTML = el.outerHTML 800 | this._element = el 801 | el.addEventListener ? el.addEventListener(name, fn, false) : el.attachEvent('on' + name, fn) 802 | } 803 | return this 804 | } 805 | 806 | /** 807 | * > Remove/unbind event listener of custom or DOM event. 808 | * 809 | * **Example** 810 | * 811 | * ```js 812 | * var element = document.body.querySelector('a.link') 813 | * emitter.off('custom', handler) 814 | * emitter.off('click', onclick, element) 815 | * ``` 816 | * 817 | * @param {String} `` event name 818 | * @param {Function} `` event handler 819 | * @param {Object} `[el]` optional DOM element 820 | * @return {DualEmitter} DualEmitter for chaining 821 | * @api public 822 | */ 823 | 824 | DualEmitter.prototype.off = function off (name, fn, el) { 825 | if (typeof name !== 'string') { 826 | throw new TypeError('DualEmitter#off expect `name` be string') 827 | } 828 | if (typeof fn !== 'function') { 829 | throw new TypeError('DualEmitter#off expect `fn` be function') 830 | } 831 | if (!this._hasOwn(this._events, name)) {return this} 832 | this._events[name].splice(this._events[name].indexOf(fn), 1) 833 | 834 | if (el && this._isDom(el)) { 835 | el.removeEventListener ? el.removeEventListener(name, fn, false) : el.detachEvent('on' + name, fn) 836 | } 837 | return this 838 | } 839 | 840 | /** 841 | * > Add one-time event listener to custom or DOM event. 842 | * Notice that `this` in event handler function vary - it can be the DOM element 843 | * or DualEmitter instance. 844 | * 845 | * **Example** 846 | * 847 | * ```js 848 | * emitter 849 | * .once('custom', function () { 850 | * console.log('executed one time') 851 | * }) 852 | * .emit('custom') 853 | * .emit('custom') 854 | * 855 | * var element = document.body.querySelector('a.link') 856 | * emitter.once('click', function () { 857 | * console.log('listen for click event only once') 858 | * }, element) 859 | * ``` 860 | * 861 | * @param {String} `` event name 862 | * @param {Function} `` event handler 863 | * @param {Object} `[el]` optional DOM element 864 | * @return {DualEmitter} DualEmitter for chaining 865 | * @api public 866 | */ 867 | 868 | DualEmitter.prototype.once = function once (name, fn, el) { 869 | var self = this 870 | function handler () { 871 | self.off(name, handler, el) 872 | return fn.apply(el, arguments) 873 | } 874 | return this.on(name, handler, el) 875 | } 876 | 877 | /** 878 | * > Emit/execute some type of event listener. 879 | * You also can emit DOM events if last argument 880 | * is the DOM element that have attached event listener. 881 | * 882 | * **Example** 883 | * 884 | * ```js 885 | * var i = 0 886 | * 887 | * emitter 888 | * .on('custom', function () { 889 | * console.log('i ==', i++, arguments) 890 | * }) 891 | * .emit('custom') 892 | * .emit('custom', 123) 893 | * .emit('custom', 'foo', 'bar', 'baz') 894 | * .emit('custom', [1, 2, 3], 4, 5) 895 | * 896 | * // or even emit DOM events, but you should 897 | * // give the element as last argument to `.emit` method 898 | * var element = document.body.querySelector('a.link') 899 | * var clicks = 0 900 | * 901 | * emitter 902 | * .on('click', function (a) { 903 | * console.log(a, 'clicked', clicks++) 904 | * console.log(this.textContent) // content of tag 905 | * }, element) 906 | * .emit('click', 123, element) 907 | * .emit('click', element) 908 | * .emit('click', foo, element) 909 | * ``` 910 | * 911 | * @param {String} `` event name 912 | * @param {Mixed} `[args...]` context to pass to event listeners 913 | * @param {Object} `[el]` optional DOM element 914 | * @return {DualEmitter} DualEmitter for chaining 915 | * @api public 916 | */ 917 | 918 | DualEmitter.prototype.emit = function emit (name) { 919 | if (!this._hasOwn(this._events, name)) {return this} 920 | var args = Array.prototype.slice.call(arguments, 1) 921 | var el = args[args.length - 1] 922 | var isdom = this._isDom(el) 923 | el = isdom ? el : this 924 | args = isdom ? args.slice(0, -1) : args 925 | 926 | for (var i = 0; i < this._events[name].length; i++) { 927 | var fn = this._events[name][i] 928 | if (isdom && fn.outerHTML !== el.outerHTML) { 929 | continue 930 | } 931 | fn.apply(el, args) 932 | } 933 | return this 934 | } 935 | 936 | /** 937 | * > Check that given `val` is DOM element. Used internally. 938 | * 939 | * **Example** 940 | * 941 | * ```js 942 | * var element = document.body.querySelector('a.link') 943 | * 944 | * emitter._isDom(element) //=> true 945 | * emitter._isDom({a: 'b'}) //=> false 946 | * ``` 947 | * 948 | * @param {Mixed} `val` 949 | * @return {Boolean} 950 | * @api public 951 | */ 952 | 953 | DualEmitter.prototype._isDom = function isDom (val) { 954 | val = Object.prototype.toString.call(val).slice(8, -1) 955 | return /(?:HTML)?(?:.*)Element/.test(val) 956 | } 957 | 958 | /** 959 | * > Check that `key` exists in the given `obj`. 960 | * 961 | * **Example** 962 | * 963 | * ```js 964 | * var obj = {a: 'b'} 965 | * 966 | * emitter._hasOwn(obj, 'a') //=> true 967 | * emitter._hasOwn(obj, 'foo') //=> false 968 | * ``` 969 | * 970 | * @param {Object} `obj` 971 | * @param {String} `key` 972 | * @return {Boolean} 973 | * @api public 974 | */ 975 | 976 | DualEmitter.prototype._hasOwn = function hasOwn (obj, key) { 977 | return Object.prototype.hasOwnProperty.call(obj, key) 978 | } 979 | 980 | /** 981 | * Static method for inheriting both the prototype and 982 | * static methods of the `DualEmitter` class. 983 | * 984 | * ```js 985 | * function MyApp(options) { 986 | * DualEmitter.call(this) 987 | * } 988 | * DualEmitter.extend(MyApp) 989 | * 990 | * 991 | * // Optionally pass another object to extend onto `MyApp` 992 | * function MyApp(options) { 993 | * DualEmitter.call(this) 994 | * Foo.call(this, options) 995 | * } 996 | * DualEmitter.extend(MyApp, Foo.prototype) 997 | * ``` 998 | * 999 | * @param {Function} `Ctor` The constructor to extend. 1000 | * @api public 1001 | */ 1002 | 1003 | DualEmitter.extend = function (Ctor, proto) { 1004 | util.inherits(Ctor, DualEmitter) 1005 | for (var key in DualEmitter) { 1006 | Ctor[key] = DualEmitter[key] 1007 | } 1008 | 1009 | if (typeof proto === 'object') { 1010 | var obj = Object.create(proto) 1011 | 1012 | for (var k in obj) { 1013 | Ctor.prototype[k] = obj[k] 1014 | } 1015 | } 1016 | } 1017 | 1018 | },{"util":4}]},{},[5])(5) 1019 | }); 1020 | //# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy5udm0vdmVyc2lvbnMvaW8uanMvdjMuMC4wL2xpYi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3Nlci1wYWNrL19wcmVsdWRlLmpzIiwiLi4vLi4vLm52bS92ZXJzaW9ucy9pby5qcy92My4wLjAvbGliL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9pbmhlcml0cy9pbmhlcml0c19icm93c2VyLmpzIiwiLi4vLi4vLm52bS92ZXJzaW9ucy9pby5qcy92My4wLjAvbGliL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9wcm9jZXNzL2Jyb3dzZXIuanMiLCIuLi8uLi8ubnZtL3ZlcnNpb25zL2lvLmpzL3YzLjAuMC9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL3V0aWwvc3VwcG9ydC9pc0J1ZmZlckJyb3dzZXIuanMiLCIuLi8uLi8ubnZtL3ZlcnNpb25zL2lvLmpzL3YzLjAuMC9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL3V0aWwvdXRpbC5qcyIsImluZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDMWtCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJpZiAodHlwZW9mIE9iamVjdC5jcmVhdGUgPT09ICdmdW5jdGlvbicpIHtcbiAgLy8gaW1wbGVtZW50YXRpb24gZnJvbSBzdGFuZGFyZCBub2RlLmpzICd1dGlsJyBtb2R1bGVcbiAgbW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBpbmhlcml0cyhjdG9yLCBzdXBlckN0b3IpIHtcbiAgICBjdG9yLnN1cGVyXyA9IHN1cGVyQ3RvclxuICAgIGN0b3IucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShzdXBlckN0b3IucHJvdG90eXBlLCB7XG4gICAgICBjb25zdHJ1Y3Rvcjoge1xuICAgICAgICB2YWx1ZTogY3RvcixcbiAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcbn0gZWxzZSB7XG4gIC8vIG9sZCBzY2hvb2wgc2hpbSBmb3Igb2xkIGJyb3dzZXJzXG4gIG1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gaW5oZXJpdHMoY3Rvciwgc3VwZXJDdG9yKSB7XG4gICAgY3Rvci5zdXBlcl8gPSBzdXBlckN0b3JcbiAgICB2YXIgVGVtcEN0b3IgPSBmdW5jdGlvbiAoKSB7fVxuICAgIFRlbXBDdG9yLnByb3RvdHlwZSA9IHN1cGVyQ3Rvci5wcm90b3R5cGVcbiAgICBjdG9yLnByb3RvdHlwZSA9IG5ldyBUZW1wQ3RvcigpXG4gICAgY3Rvci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBjdG9yXG4gIH1cbn1cbiIsIi8vIHNoaW0gZm9yIHVzaW5nIHByb2Nlc3MgaW4gYnJvd3NlclxuXG52YXIgcHJvY2VzcyA9IG1vZHVsZS5leHBvcnRzID0ge307XG52YXIgcXVldWUgPSBbXTtcbnZhciBkcmFpbmluZyA9IGZhbHNlO1xudmFyIGN1cnJlbnRRdWV1ZTtcbnZhciBxdWV1ZUluZGV4ID0gLTE7XG5cbmZ1bmN0aW9uIGNsZWFuVXBOZXh0VGljaygpIHtcbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIGlmIChjdXJyZW50UXVldWUubGVuZ3RoKSB7XG4gICAgICAgIHF1ZXVlID0gY3VycmVudFF1ZXVlLmNvbmNhdChxdWV1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgIH1cbiAgICBpZiAocXVldWUubGVuZ3RoKSB7XG4gICAgICAgIGRyYWluUXVldWUoKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGRyYWluUXVldWUoKSB7XG4gICAgaWYgKGRyYWluaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGNsZWFuVXBOZXh0VGljayk7XG4gICAgZHJhaW5pbmcgPSB0cnVlO1xuXG4gICAgdmFyIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB3aGlsZShsZW4pIHtcbiAgICAgICAgY3VycmVudFF1ZXVlID0gcXVldWU7XG4gICAgICAgIHF1ZXVlID0gW107XG4gICAgICAgIHdoaWxlICgrK3F1ZXVlSW5kZXggPCBsZW4pIHtcbiAgICAgICAgICAgIGN1cnJlbnRRdWV1ZVtxdWV1ZUluZGV4XS5ydW4oKTtcbiAgICAgICAgfVxuICAgICAgICBxdWV1ZUluZGV4ID0gLTE7XG4gICAgICAgIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB9XG4gICAgY3VycmVudFF1ZXVlID0gbnVsbDtcbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbn1cblxucHJvY2Vzcy5uZXh0VGljayA9IGZ1bmN0aW9uIChmdW4pIHtcbiAgICB2YXIgYXJncyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoIC0gMSk7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBxdWV1ZS5wdXNoKG5ldyBJdGVtKGZ1biwgYXJncykpO1xuICAgIGlmIChxdWV1ZS5sZW5ndGggPT09IDEgJiYgIWRyYWluaW5nKSB7XG4gICAgICAgIHNldFRpbWVvdXQoZHJhaW5RdWV1ZSwgMCk7XG4gICAgfVxufTtcblxuLy8gdjggbGlrZXMgcHJlZGljdGlibGUgb2JqZWN0c1xuZnVuY3Rpb24gSXRlbShmdW4sIGFycmF5KSB7XG4gICAgdGhpcy5mdW4gPSBmdW47XG4gICAgdGhpcy5hcnJheSA9IGFycmF5O1xufVxuSXRlbS5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZnVuLmFwcGx5KG51bGwsIHRoaXMuYXJyYXkpO1xufTtcbnByb2Nlc3MudGl0bGUgPSAnYnJvd3Nlcic7XG5wcm9jZXNzLmJyb3dzZXIgPSB0cnVlO1xucHJvY2Vzcy5lbnYgPSB7fTtcbnByb2Nlc3MuYXJndiA9IFtdO1xucHJvY2Vzcy52ZXJzaW9uID0gJyc7IC8vIGVtcHR5IHN0cmluZyB0byBhdm9pZCByZWdleHAgaXNzdWVzXG5wcm9jZXNzLnZlcnNpb25zID0ge307XG5cbmZ1bmN0aW9uIG5vb3AoKSB7fVxuXG5wcm9jZXNzLm9uID0gbm9vcDtcbnByb2Nlc3MuYWRkTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5vbmNlID0gbm9vcDtcbnByb2Nlc3Mub2ZmID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBub29wO1xucHJvY2Vzcy5lbWl0ID0gbm9vcDtcblxucHJvY2Vzcy5iaW5kaW5nID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuYmluZGluZyBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xuXG4vLyBUT0RPKHNodHlsbWFuKVxucHJvY2Vzcy5jd2QgPSBmdW5jdGlvbiAoKSB7IHJldHVybiAnLycgfTtcbnByb2Nlc3MuY2hkaXIgPSBmdW5jdGlvbiAoZGlyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmNoZGlyIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG5wcm9jZXNzLnVtYXNrID0gZnVuY3Rpb24oKSB7IHJldHVybiAwOyB9O1xuIiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBpc0J1ZmZlcihhcmcpIHtcbiAgcmV0dXJuIGFyZyAmJiB0eXBlb2YgYXJnID09PSAnb2JqZWN0J1xuICAgICYmIHR5cGVvZiBhcmcuY29weSA9PT0gJ2Z1bmN0aW9uJ1xuICAgICYmIHR5cGVvZiBhcmcuZmlsbCA9PT0gJ2Z1bmN0aW9uJ1xuICAgICYmIHR5cGVvZiBhcmcucmVhZFVJbnQ4ID09PSAnZnVuY3Rpb24nO1xufSIsIi8vIENvcHlyaWdodCBKb3llbnQsIEluYy4gYW5kIG90aGVyIE5vZGUgY29udHJpYnV0b3JzLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhXG4vLyBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlXG4vLyBcIlNvZnR3YXJlXCIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmdcbi8vIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCxcbi8vIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXRcbi8vIHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZVxuLy8gZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWRcbi8vIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1Ncbi8vIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0Zcbi8vIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU5cbi8vIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLFxuLy8gREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SXG4vLyBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFXG4vLyBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLlxuXG52YXIgZm9ybWF0UmVnRXhwID0gLyVbc2RqJV0vZztcbmV4cG9ydHMuZm9ybWF0ID0gZnVuY3Rpb24oZikge1xuICBpZiAoIWlzU3RyaW5nKGYpKSB7XG4gICAgdmFyIG9iamVjdHMgPSBbXTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgb2JqZWN0cy5wdXNoKGluc3BlY3QoYXJndW1lbnRzW2ldKSk7XG4gICAgfVxuICAgIHJldHVybiBvYmplY3RzLmpvaW4oJyAnKTtcbiAgfVxuXG4gIHZhciBpID0gMTtcbiAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG4gIHZhciBsZW4gPSBhcmdzLmxlbmd0aDtcbiAgdmFyIHN0ciA9IFN0cmluZyhmKS5yZXBsYWNlKGZvcm1hdFJlZ0V4cCwgZnVuY3Rpb24oeCkge1xuICAgIGlmICh4ID09PSAnJSUnKSByZXR1cm4gJyUnO1xuICAgIGlmIChpID49IGxlbikgcmV0dXJuIHg7XG4gICAgc3dpdGNoICh4KSB7XG4gICAgICBjYXNlICclcyc6IHJldHVybiBTdHJpbmcoYXJnc1tpKytdKTtcbiAgICAgIGNhc2UgJyVkJzogcmV0dXJuIE51bWJlcihhcmdzW2krK10pO1xuICAgICAgY2FzZSAnJWonOlxuICAgICAgICB0cnkge1xuICAgICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShhcmdzW2krK10pO1xuICAgICAgICB9IGNhdGNoIChfKSB7XG4gICAgICAgICAgcmV0dXJuICdbQ2lyY3VsYXJdJztcbiAgICAgICAgfVxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIHg7XG4gICAgfVxuICB9KTtcbiAgZm9yICh2YXIgeCA9IGFyZ3NbaV07IGkgPCBsZW47IHggPSBhcmdzWysraV0pIHtcbiAgICBpZiAoaXNOdWxsKHgpIHx8ICFpc09iamVjdCh4KSkge1xuICAgICAgc3RyICs9ICcgJyArIHg7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN0ciArPSAnICcgKyBpbnNwZWN0KHgpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gc3RyO1xufTtcblxuXG4vLyBNYXJrIHRoYXQgYSBtZXRob2Qgc2hvdWxkIG5vdCBiZSB1c2VkLlxuLy8gUmV0dXJucyBhIG1vZGlmaWVkIGZ1bmN0aW9uIHdoaWNoIHdhcm5zIG9uY2UgYnkgZGVmYXVsdC5cbi8vIElmIC0tbm8tZGVwcmVjYXRpb24gaXMgc2V0LCB0aGVuIGl0IGlzIGEgbm8tb3AuXG5leHBvcnRzLmRlcHJlY2F0ZSA9IGZ1bmN0aW9uKGZuLCBtc2cpIHtcbiAgLy8gQWxsb3cgZm9yIGRlcHJlY2F0aW5nIHRoaW5ncyBpbiB0aGUgcHJvY2VzcyBvZiBzdGFydGluZyB1cC5cbiAgaWYgKGlzVW5kZWZpbmVkKGdsb2JhbC5wcm9jZXNzKSkge1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiBleHBvcnRzLmRlcHJlY2F0ZShmbiwgbXNnKS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH07XG4gIH1cblxuICBpZiAocHJvY2Vzcy5ub0RlcHJlY2F0aW9uID09PSB0cnVlKSB7XG4gICAgcmV0dXJuIGZuO1xuICB9XG5cbiAgdmFyIHdhcm5lZCA9IGZhbHNlO1xuICBmdW5jdGlvbiBkZXByZWNhdGVkKCkge1xuICAgIGlmICghd2FybmVkKSB7XG4gICAgICBpZiAocHJvY2Vzcy50aHJvd0RlcHJlY2F0aW9uKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihtc2cpO1xuICAgICAgfSBlbHNlIGlmIChwcm9jZXNzLnRyYWNlRGVwcmVjYXRpb24pIHtcbiAgICAgICAgY29uc29sZS50cmFjZShtc2cpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihtc2cpO1xuICAgICAgfVxuICAgICAgd2FybmVkID0gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gIH1cblxuICByZXR1cm4gZGVwcmVjYXRlZDtcbn07XG5cblxudmFyIGRlYnVncyA9IHt9O1xudmFyIGRlYnVnRW52aXJvbjtcbmV4cG9ydHMuZGVidWdsb2cgPSBmdW5jdGlvbihzZXQpIHtcbiAgaWYgKGlzVW5kZWZpbmVkKGRlYnVnRW52aXJvbikpXG4gICAgZGVidWdFbnZpcm9uID0gcHJvY2Vzcy5lbnYuTk9ERV9ERUJVRyB8fCAnJztcbiAgc2V0ID0gc2V0LnRvVXBwZXJDYXNlKCk7XG4gIGlmICghZGVidWdzW3NldF0pIHtcbiAgICBpZiAobmV3IFJlZ0V4cCgnXFxcXGInICsgc2V0ICsgJ1xcXFxiJywgJ2knKS50ZXN0KGRlYnVnRW52aXJvbikpIHtcbiAgICAgIHZhciBwaWQgPSBwcm9jZXNzLnBpZDtcbiAgICAgIGRlYnVnc1tzZXRdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBtc2cgPSBleHBvcnRzLmZvcm1hdC5hcHBseShleHBvcnRzLCBhcmd1bWVudHMpO1xuICAgICAgICBjb25zb2xlLmVycm9yKCclcyAlZDogJXMnLCBzZXQsIHBpZCwgbXNnKTtcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIGRlYnVnc1tzZXRdID0gZnVuY3Rpb24oKSB7fTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGRlYnVnc1tzZXRdO1xufTtcblxuXG4vKipcbiAqIEVjaG9zIHRoZSB2YWx1ZSBvZiBhIHZhbHVlLiBUcnlzIHRvIHByaW50IHRoZSB2YWx1ZSBvdXRcbiAqIGluIHRoZSBiZXN0IHdheSBwb3NzaWJsZSBnaXZlbiB0aGUgZGlmZmVyZW50IHR5cGVzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogVGhlIG9iamVjdCB0byBwcmludCBvdXQuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0cyBPcHRpb25hbCBvcHRpb25zIG9iamVjdCB0aGF0IGFsdGVycyB0aGUgb3V0cHV0LlxuICovXG4vKiBsZWdhY3k6IG9iaiwgc2hvd0hpZGRlbiwgZGVwdGgsIGNvbG9ycyovXG5mdW5jdGlvbiBpbnNwZWN0KG9iaiwgb3B0cykge1xuICAvLyBkZWZhdWx0IG9wdGlvbnNcbiAgdmFyIGN0eCA9IHtcbiAgICBzZWVuOiBbXSxcbiAgICBzdHlsaXplOiBzdHlsaXplTm9Db2xvclxuICB9O1xuICAvLyBsZWdhY3kuLi5cbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPj0gMykgY3R4LmRlcHRoID0gYXJndW1lbnRzWzJdO1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+PSA0KSBjdHguY29sb3JzID0gYXJndW1lbnRzWzNdO1xuICBpZiAoaXNCb29sZWFuKG9wdHMpKSB7XG4gICAgLy8gbGVnYWN5Li4uXG4gICAgY3R4LnNob3dIaWRkZW4gPSBvcHRzO1xuICB9IGVsc2UgaWYgKG9wdHMpIHtcbiAgICAvLyBnb3QgYW4gXCJvcHRpb25zXCIgb2JqZWN0XG4gICAgZXhwb3J0cy5fZXh0ZW5kKGN0eCwgb3B0cyk7XG4gIH1cbiAgLy8gc2V0IGRlZmF1bHQgb3B0aW9uc1xuICBpZiAoaXNVbmRlZmluZWQoY3R4LnNob3dIaWRkZW4pKSBjdHguc2hvd0hpZGRlbiA9IGZhbHNlO1xuICBpZiAoaXNVbmRlZmluZWQoY3R4LmRlcHRoKSkgY3R4LmRlcHRoID0gMjtcbiAgaWYgKGlzVW5kZWZpbmVkKGN0eC5jb2xvcnMpKSBjdHguY29sb3JzID0gZmFsc2U7XG4gIGlmIChpc1VuZGVmaW5lZChjdHguY3VzdG9tSW5zcGVjdCkpIGN0eC5jdXN0b21JbnNwZWN0ID0gdHJ1ZTtcbiAgaWYgKGN0eC5jb2xvcnMpIGN0eC5zdHlsaXplID0gc3R5bGl6ZVdpdGhDb2xvcjtcbiAgcmV0dXJuIGZvcm1hdFZhbHVlKGN0eCwgb2JqLCBjdHguZGVwdGgpO1xufVxuZXhwb3J0cy5pbnNwZWN0ID0gaW5zcGVjdDtcblxuXG4vLyBodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0FOU0lfZXNjYXBlX2NvZGUjZ3JhcGhpY3Ncbmluc3BlY3QuY29sb3JzID0ge1xuICAnYm9sZCcgOiBbMSwgMjJdLFxuICAnaXRhbGljJyA6IFszLCAyM10sXG4gICd1bmRlcmxpbmUnIDogWzQsIDI0XSxcbiAgJ2ludmVyc2UnIDogWzcsIDI3XSxcbiAgJ3doaXRlJyA6IFszNywgMzldLFxuICAnZ3JleScgOiBbOTAsIDM5XSxcbiAgJ2JsYWNrJyA6IFszMCwgMzldLFxuICAnYmx1ZScgOiBbMzQsIDM5XSxcbiAgJ2N5YW4nIDogWzM2LCAzOV0sXG4gICdncmVlbicgOiBbMzIsIDM5XSxcbiAgJ21hZ2VudGEnIDogWzM1LCAzOV0sXG4gICdyZWQnIDogWzMxLCAzOV0sXG4gICd5ZWxsb3cnIDogWzMzLCAzOV1cbn07XG5cbi8vIERvbid0IHVzZSAnYmx1ZScgbm90IHZpc2libGUgb24gY21kLmV4ZVxuaW5zcGVjdC5zdHlsZXMgPSB7XG4gICdzcGVjaWFsJzogJ2N5YW4nLFxuICAnbnVtYmVyJzogJ3llbGxvdycsXG4gICdib29sZWFuJzogJ3llbGxvdycsXG4gICd1bmRlZmluZWQnOiAnZ3JleScsXG4gICdudWxsJzogJ2JvbGQnLFxuICAnc3RyaW5nJzogJ2dyZWVuJyxcbiAgJ2RhdGUnOiAnbWFnZW50YScsXG4gIC8vIFwibmFtZVwiOiBpbnRlbnRpb25hbGx5IG5vdCBzdHlsaW5nXG4gICdyZWdleHAnOiAncmVkJ1xufTtcblxuXG5mdW5jdGlvbiBzdHlsaXplV2l0aENvbG9yKHN0ciwgc3R5bGVUeXBlKSB7XG4gIHZhciBzdHlsZSA9IGluc3BlY3Quc3R5bGVzW3N0eWxlVHlwZV07XG5cbiAgaWYgKHN0eWxlKSB7XG4gICAgcmV0dXJuICdcXHUwMDFiWycgKyBpbnNwZWN0LmNvbG9yc1tzdHlsZV1bMF0gKyAnbScgKyBzdHIgK1xuICAgICAgICAgICAnXFx1MDAxYlsnICsgaW5zcGVjdC5jb2xvcnNbc3R5bGVdWzFdICsgJ20nO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBzdHI7XG4gIH1cbn1cblxuXG5mdW5jdGlvbiBzdHlsaXplTm9Db2xvcihzdHIsIHN0eWxlVHlwZSkge1xuICByZXR1cm4gc3RyO1xufVxuXG5cbmZ1bmN0aW9uIGFycmF5VG9IYXNoKGFycmF5KSB7XG4gIHZhciBoYXNoID0ge307XG5cbiAgYXJyYXkuZm9yRWFjaChmdW5jdGlvbih2YWwsIGlkeCkge1xuICAgIGhhc2hbdmFsXSA9IHRydWU7XG4gIH0pO1xuXG4gIHJldHVybiBoYXNoO1xufVxuXG5cbmZ1bmN0aW9uIGZvcm1hdFZhbHVlKGN0eCwgdmFsdWUsIHJlY3Vyc2VUaW1lcykge1xuICAvLyBQcm92aWRlIGEgaG9vayBmb3IgdXNlci1zcGVjaWZpZWQgaW5zcGVjdCBmdW5jdGlvbnMuXG4gIC8vIENoZWNrIHRoYXQgdmFsdWUgaXMgYW4gb2JqZWN0IHdpdGggYW4gaW5zcGVjdCBmdW5jdGlvbiBvbiBpdFxuICBpZiAoY3R4LmN1c3RvbUluc3BlY3QgJiZcbiAgICAgIHZhbHVlICYmXG4gICAgICBpc0Z1bmN0aW9uKHZhbHVlLmluc3BlY3QpICYmXG4gICAgICAvLyBGaWx0ZXIgb3V0IHRoZSB1dGlsIG1vZHVsZSwgaXQncyBpbnNwZWN0IGZ1bmN0aW9uIGlzIHNwZWNpYWxcbiAgICAgIHZhbHVlLmluc3BlY3QgIT09IGV4cG9ydHMuaW5zcGVjdCAmJlxuICAgICAgLy8gQWxzbyBmaWx0ZXIgb3V0IGFueSBwcm90b3R5cGUgb2JqZWN0cyB1c2luZyB0aGUgY2lyY3VsYXIgY2hlY2suXG4gICAgICAhKHZhbHVlLmNvbnN0cnVjdG9yICYmIHZhbHVlLmNvbnN0cnVjdG9yLnByb3RvdHlwZSA9PT0gdmFsdWUpKSB7XG4gICAgdmFyIHJldCA9IHZhbHVlLmluc3BlY3QocmVjdXJzZVRpbWVzLCBjdHgpO1xuICAgIGlmICghaXNTdHJpbmcocmV0KSkge1xuICAgICAgcmV0ID0gZm9ybWF0VmFsdWUoY3R4LCByZXQsIHJlY3Vyc2VUaW1lcyk7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICAvLyBQcmltaXRpdmUgdHlwZXMgY2Fubm90IGhhdmUgcHJvcGVydGllc1xuICB2YXIgcHJpbWl0aXZlID0gZm9ybWF0UHJpbWl0aXZlKGN0eCwgdmFsdWUpO1xuICBpZiAocHJpbWl0aXZlKSB7XG4gICAgcmV0dXJuIHByaW1pdGl2ZTtcbiAgfVxuXG4gIC8vIExvb2sgdXAgdGhlIGtleXMgb2YgdGhlIG9iamVjdC5cbiAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyh2YWx1ZSk7XG4gIHZhciB2aXNpYmxlS2V5cyA9IGFycmF5VG9IYXNoKGtleXMpO1xuXG4gIGlmIChjdHguc2hvd0hpZGRlbikge1xuICAgIGtleXMgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyh2YWx1ZSk7XG4gIH1cblxuICAvLyBJRSBkb2Vzbid0IG1ha2UgZXJyb3IgZmllbGRzIG5vbi1lbnVtZXJhYmxlXG4gIC8vIGh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20vZW4tdXMvbGlicmFyeS9pZS9kd3c1MnNidCh2PXZzLjk0KS5hc3B4XG4gIGlmIChpc0Vycm9yKHZhbHVlKVxuICAgICAgJiYgKGtleXMuaW5kZXhPZignbWVzc2FnZScpID49IDAgfHwga2V5cy5pbmRleE9mKCdkZXNjcmlwdGlvbicpID49IDApKSB7XG4gICAgcmV0dXJuIGZvcm1hdEVycm9yKHZhbHVlKTtcbiAgfVxuXG4gIC8vIFNvbWUgdHlwZSBvZiBvYmplY3Qgd2l0aG91dCBwcm9wZXJ0aWVzIGNhbiBiZSBzaG9ydGN1dHRlZC5cbiAgaWYgKGtleXMubGVuZ3RoID09PSAwKSB7XG4gICAgaWYgKGlzRnVuY3Rpb24odmFsdWUpKSB7XG4gICAgICB2YXIgbmFtZSA9IHZhbHVlLm5hbWUgPyAnOiAnICsgdmFsdWUubmFtZSA6ICcnO1xuICAgICAgcmV0dXJuIGN0eC5zdHlsaXplKCdbRnVuY3Rpb24nICsgbmFtZSArICddJywgJ3NwZWNpYWwnKTtcbiAgICB9XG4gICAgaWYgKGlzUmVnRXhwKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIGN0eC5zdHlsaXplKFJlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSksICdyZWdleHAnKTtcbiAgICB9XG4gICAgaWYgKGlzRGF0ZSh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiBjdHguc3R5bGl6ZShEYXRlLnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbHVlKSwgJ2RhdGUnKTtcbiAgICB9XG4gICAgaWYgKGlzRXJyb3IodmFsdWUpKSB7XG4gICAgICByZXR1cm4gZm9ybWF0RXJyb3IodmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIHZhciBiYXNlID0gJycsIGFycmF5ID0gZmFsc2UsIGJyYWNlcyA9IFsneycsICd9J107XG5cbiAgLy8gTWFrZSBBcnJheSBzYXkgdGhhdCB0aGV5IGFyZSBBcnJheVxuICBpZiAoaXNBcnJheSh2YWx1ZSkpIHtcbiAgICBhcnJheSA9IHRydWU7XG4gICAgYnJhY2VzID0gWydbJywgJ10nXTtcbiAgfVxuXG4gIC8vIE1ha2UgZnVuY3Rpb25zIHNheSB0aGF0IHRoZXkgYXJlIGZ1bmN0aW9uc1xuICBpZiAoaXNGdW5jdGlvbih2YWx1ZSkpIHtcbiAgICB2YXIgbiA9IHZhbHVlLm5hbWUgPyAnOiAnICsgdmFsdWUubmFtZSA6ICcnO1xuICAgIGJhc2UgPSAnIFtGdW5jdGlvbicgKyBuICsgJ10nO1xuICB9XG5cbiAgLy8gTWFrZSBSZWdFeHBzIHNheSB0aGF0IHRoZXkgYXJlIFJlZ0V4cHNcbiAgaWYgKGlzUmVnRXhwKHZhbHVlKSkge1xuICAgIGJhc2UgPSAnICcgKyBSZWdFeHAucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodmFsdWUpO1xuICB9XG5cbiAgLy8gTWFrZSBkYXRlcyB3aXRoIHByb3BlcnRpZXMgZmlyc3Qgc2F5IHRoZSBkYXRlXG4gIGlmIChpc0RhdGUodmFsdWUpKSB7XG4gICAgYmFzZSA9ICcgJyArIERhdGUucHJvdG90eXBlLnRvVVRDU3RyaW5nLmNhbGwodmFsdWUpO1xuICB9XG5cbiAgLy8gTWFrZSBlcnJvciB3aXRoIG1lc3NhZ2UgZmlyc3Qgc2F5IHRoZSBlcnJvclxuICBpZiAoaXNFcnJvcih2YWx1ZSkpIHtcbiAgICBiYXNlID0gJyAnICsgZm9ybWF0RXJyb3IodmFsdWUpO1xuICB9XG5cbiAgaWYgKGtleXMubGVuZ3RoID09PSAwICYmICghYXJyYXkgfHwgdmFsdWUubGVuZ3RoID09IDApKSB7XG4gICAgcmV0dXJuIGJyYWNlc1swXSArIGJhc2UgKyBicmFjZXNbMV07XG4gIH1cblxuICBpZiAocmVjdXJzZVRpbWVzIDwgMCkge1xuICAgIGlmIChpc1JlZ0V4cCh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiBjdHguc3R5bGl6ZShSZWdFeHAucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodmFsdWUpLCAncmVnZXhwJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBjdHguc3R5bGl6ZSgnW09iamVjdF0nLCAnc3BlY2lhbCcpO1xuICAgIH1cbiAgfVxuXG4gIGN0eC5zZWVuLnB1c2godmFsdWUpO1xuXG4gIHZhciBvdXRwdXQ7XG4gIGlmIChhcnJheSkge1xuICAgIG91dHB1dCA9IGZvcm1hdEFycmF5KGN0eCwgdmFsdWUsIHJlY3Vyc2VUaW1lcywgdmlzaWJsZUtleXMsIGtleXMpO1xuICB9IGVsc2Uge1xuICAgIG91dHB1dCA9IGtleXMubWFwKGZ1bmN0aW9uKGtleSkge1xuICAgICAgcmV0dXJuIGZvcm1hdFByb3BlcnR5KGN0eCwgdmFsdWUsIHJlY3Vyc2VUaW1lcywgdmlzaWJsZUtleXMsIGtleSwgYXJyYXkpO1xuICAgIH0pO1xuICB9XG5cbiAgY3R4LnNlZW4ucG9wKCk7XG5cbiAgcmV0dXJuIHJlZHVjZVRvU2luZ2xlU3RyaW5nKG91dHB1dCwgYmFzZSwgYnJhY2VzKTtcbn1cblxuXG5mdW5jdGlvbiBmb3JtYXRQcmltaXRpdmUoY3R4LCB2YWx1ZSkge1xuICBpZiAoaXNVbmRlZmluZWQodmFsdWUpKVxuICAgIHJldHVybiBjdHguc3R5bGl6ZSgndW5kZWZpbmVkJywgJ3VuZGVmaW5lZCcpO1xuICBpZiAoaXNTdHJpbmcodmFsdWUpKSB7XG4gICAgdmFyIHNpbXBsZSA9ICdcXCcnICsgSlNPTi5zdHJpbmdpZnkodmFsdWUpLnJlcGxhY2UoL15cInxcIiQvZywgJycpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCBcIlxcXFwnXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFxcXFwiL2csICdcIicpICsgJ1xcJyc7XG4gICAgcmV0dXJuIGN0eC5zdHlsaXplKHNpbXBsZSwgJ3N0cmluZycpO1xuICB9XG4gIGlmIChpc051bWJlcih2YWx1ZSkpXG4gICAgcmV0dXJuIGN0eC5zdHlsaXplKCcnICsgdmFsdWUsICdudW1iZXInKTtcbiAgaWYgKGlzQm9vbGVhbih2YWx1ZSkpXG4gICAgcmV0dXJuIGN0eC5zdHlsaXplKCcnICsgdmFsdWUsICdib29sZWFuJyk7XG4gIC8vIEZvciBzb21lIHJlYXNvbiB0eXBlb2YgbnVsbCBpcyBcIm9iamVjdFwiLCBzbyBzcGVjaWFsIGNhc2UgaGVyZS5cbiAgaWYgKGlzTnVsbCh2YWx1ZSkpXG4gICAgcmV0dXJuIGN0eC5zdHlsaXplKCdudWxsJywgJ251bGwnKTtcbn1cblxuXG5mdW5jdGlvbiBmb3JtYXRFcnJvcih2YWx1ZSkge1xuICByZXR1cm4gJ1snICsgRXJyb3IucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodmFsdWUpICsgJ10nO1xufVxuXG5cbmZ1bmN0aW9uIGZvcm1hdEFycmF5KGN0eCwgdmFsdWUsIHJlY3Vyc2VUaW1lcywgdmlzaWJsZUtleXMsIGtleXMpIHtcbiAgdmFyIG91dHB1dCA9IFtdO1xuICBmb3IgKHZhciBpID0gMCwgbCA9IHZhbHVlLmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgIGlmIChoYXNPd25Qcm9wZXJ0eSh2YWx1ZSwgU3RyaW5nKGkpKSkge1xuICAgICAgb3V0cHV0LnB1c2goZm9ybWF0UHJvcGVydHkoY3R4LCB2YWx1ZSwgcmVjdXJzZVRpbWVzLCB2aXNpYmxlS2V5cyxcbiAgICAgICAgICBTdHJpbmcoaSksIHRydWUpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgb3V0cHV0LnB1c2goJycpO1xuICAgIH1cbiAgfVxuICBrZXlzLmZvckVhY2goZnVuY3Rpb24oa2V5KSB7XG4gICAgaWYgKCFrZXkubWF0Y2goL15cXGQrJC8pKSB7XG4gICAgICBvdXRwdXQucHVzaChmb3JtYXRQcm9wZXJ0eShjdHgsIHZhbHVlLCByZWN1cnNlVGltZXMsIHZpc2libGVLZXlzLFxuICAgICAgICAgIGtleSwgdHJ1ZSkpO1xuICAgIH1cbiAgfSk7XG4gIHJldHVybiBvdXRwdXQ7XG59XG5cblxuZnVuY3Rpb24gZm9ybWF0UHJvcGVydHkoY3R4LCB2YWx1ZSwgcmVjdXJzZVRpbWVzLCB2aXNpYmxlS2V5cywga2V5LCBhcnJheSkge1xuICB2YXIgbmFtZSwgc3RyLCBkZXNjO1xuICBkZXNjID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih2YWx1ZSwga2V5KSB8fCB7IHZhbHVlOiB2YWx1ZVtrZXldIH07XG4gIGlmIChkZXNjLmdldCkge1xuICAgIGlmIChkZXNjLnNldCkge1xuICAgICAgc3RyID0gY3R4LnN0eWxpemUoJ1tHZXR0ZXIvU2V0dGVyXScsICdzcGVjaWFsJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN0ciA9IGN0eC5zdHlsaXplKCdbR2V0dGVyXScsICdzcGVjaWFsJyk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGlmIChkZXNjLnNldCkge1xuICAgICAgc3RyID0gY3R4LnN0eWxpemUoJ1tTZXR0ZXJdJywgJ3NwZWNpYWwnKTtcbiAgICB9XG4gIH1cbiAgaWYgKCFoYXNPd25Qcm9wZXJ0eSh2aXNpYmxlS2V5cywga2V5KSkge1xuICAgIG5hbWUgPSAnWycgKyBrZXkgKyAnXSc7XG4gIH1cbiAgaWYgKCFzdHIpIHtcbiAgICBpZiAoY3R4LnNlZW4uaW5kZXhPZihkZXNjLnZhbHVlKSA8IDApIHtcbiAgICAgIGlmIChpc051bGwocmVjdXJzZVRpbWVzKSkge1xuICAgICAgICBzdHIgPSBmb3JtYXRWYWx1ZShjdHgsIGRlc2MudmFsdWUsIG51bGwpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RyID0gZm9ybWF0VmFsdWUoY3R4LCBkZXNjLnZhbHVlLCByZWN1cnNlVGltZXMgLSAxKTtcbiAgICAgIH1cbiAgICAgIGlmIChzdHIuaW5kZXhPZignXFxuJykgPiAtMSkge1xuICAgICAgICBpZiAoYXJyYXkpIHtcbiAgICAgICAgICBzdHIgPSBzdHIuc3BsaXQoJ1xcbicpLm1hcChmdW5jdGlvbihsaW5lKSB7XG4gICAgICAgICAgICByZXR1cm4gJyAgJyArIGxpbmU7XG4gICAgICAgICAgfSkuam9pbignXFxuJykuc3Vic3RyKDIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHN0ciA9ICdcXG4nICsgc3RyLnNwbGl0KCdcXG4nKS5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgICAgICAgICAgcmV0dXJuICcgICAnICsgbGluZTtcbiAgICAgICAgICB9KS5qb2luKCdcXG4nKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBzdHIgPSBjdHguc3R5bGl6ZSgnW0NpcmN1bGFyXScsICdzcGVjaWFsJyk7XG4gICAgfVxuICB9XG4gIGlmIChpc1VuZGVmaW5lZChuYW1lKSkge1xuICAgIGlmIChhcnJheSAmJiBrZXkubWF0Y2goL15cXGQrJC8pKSB7XG4gICAgICByZXR1cm4gc3RyO1xuICAgIH1cbiAgICBuYW1lID0gSlNPTi5zdHJpbmdpZnkoJycgKyBrZXkpO1xuICAgIGlmIChuYW1lLm1hdGNoKC9eXCIoW2EtekEtWl9dW2EtekEtWl8wLTldKilcIiQvKSkge1xuICAgICAgbmFtZSA9IG5hbWUuc3Vic3RyKDEsIG5hbWUubGVuZ3RoIC0gMik7XG4gICAgICBuYW1lID0gY3R4LnN0eWxpemUobmFtZSwgJ25hbWUnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbmFtZSA9IG5hbWUucmVwbGFjZSgvJy9nLCBcIlxcXFwnXCIpXG4gICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXFxcXCIvZywgJ1wiJylcbiAgICAgICAgICAgICAgICAgLnJlcGxhY2UoLyheXCJ8XCIkKS9nLCBcIidcIik7XG4gICAgICBuYW1lID0gY3R4LnN0eWxpemUobmFtZSwgJ3N0cmluZycpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBuYW1lICsgJzogJyArIHN0cjtcbn1cblxuXG5mdW5jdGlvbiByZWR1Y2VUb1NpbmdsZVN0cmluZyhvdXRwdXQsIGJhc2UsIGJyYWNlcykge1xuICB2YXIgbnVtTGluZXNFc3QgPSAwO1xuICB2YXIgbGVuZ3RoID0gb3V0cHV0LnJlZHVjZShmdW5jdGlvbihwcmV2LCBjdXIpIHtcbiAgICBudW1MaW5lc0VzdCsrO1xuICAgIGlmIChjdXIuaW5kZXhPZignXFxuJykgPj0gMCkgbnVtTGluZXNFc3QrKztcbiAgICByZXR1cm4gcHJldiArIGN1ci5yZXBsYWNlKC9cXHUwMDFiXFxbXFxkXFxkP20vZywgJycpLmxlbmd0aCArIDE7XG4gIH0sIDApO1xuXG4gIGlmIChsZW5ndGggPiA2MCkge1xuICAgIHJldHVybiBicmFjZXNbMF0gK1xuICAgICAgICAgICAoYmFzZSA9PT0gJycgPyAnJyA6IGJhc2UgKyAnXFxuICcpICtcbiAgICAgICAgICAgJyAnICtcbiAgICAgICAgICAgb3V0cHV0LmpvaW4oJyxcXG4gICcpICtcbiAgICAgICAgICAgJyAnICtcbiAgICAgICAgICAgYnJhY2VzWzFdO1xuICB9XG5cbiAgcmV0dXJuIGJyYWNlc1swXSArIGJhc2UgKyAnICcgKyBvdXRwdXQuam9pbignLCAnKSArICcgJyArIGJyYWNlc1sxXTtcbn1cblxuXG4vLyBOT1RFOiBUaGVzZSB0eXBlIGNoZWNraW5nIGZ1bmN0aW9ucyBpbnRlbnRpb25hbGx5IGRvbid0IHVzZSBgaW5zdGFuY2VvZmBcbi8vIGJlY2F1c2UgaXQgaXMgZnJhZ2lsZSBhbmQgY2FuIGJlIGVhc2lseSBmYWtlZCB3aXRoIGBPYmplY3QuY3JlYXRlKClgLlxuZnVuY3Rpb24gaXNBcnJheShhcikge1xuICByZXR1cm4gQXJyYXkuaXNBcnJheShhcik7XG59XG5leHBvcnRzLmlzQXJyYXkgPSBpc0FycmF5O1xuXG5mdW5jdGlvbiBpc0Jvb2xlYW4oYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnYm9vbGVhbic7XG59XG5leHBvcnRzLmlzQm9vbGVhbiA9IGlzQm9vbGVhbjtcblxuZnVuY3Rpb24gaXNOdWxsKGFyZykge1xuICByZXR1cm4gYXJnID09PSBudWxsO1xufVxuZXhwb3J0cy5pc051bGwgPSBpc051bGw7XG5cbmZ1bmN0aW9uIGlzTnVsbE9yVW5kZWZpbmVkKGFyZykge1xuICByZXR1cm4gYXJnID09IG51bGw7XG59XG5leHBvcnRzLmlzTnVsbE9yVW5kZWZpbmVkID0gaXNOdWxsT3JVbmRlZmluZWQ7XG5cbmZ1bmN0aW9uIGlzTnVtYmVyKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ251bWJlcic7XG59XG5leHBvcnRzLmlzTnVtYmVyID0gaXNOdW1iZXI7XG5cbmZ1bmN0aW9uIGlzU3RyaW5nKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ3N0cmluZyc7XG59XG5leHBvcnRzLmlzU3RyaW5nID0gaXNTdHJpbmc7XG5cbmZ1bmN0aW9uIGlzU3ltYm9sKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ3N5bWJvbCc7XG59XG5leHBvcnRzLmlzU3ltYm9sID0gaXNTeW1ib2w7XG5cbmZ1bmN0aW9uIGlzVW5kZWZpbmVkKGFyZykge1xuICByZXR1cm4gYXJnID09PSB2b2lkIDA7XG59XG5leHBvcnRzLmlzVW5kZWZpbmVkID0gaXNVbmRlZmluZWQ7XG5cbmZ1bmN0aW9uIGlzUmVnRXhwKHJlKSB7XG4gIHJldHVybiBpc09iamVjdChyZSkgJiYgb2JqZWN0VG9TdHJpbmcocmUpID09PSAnW29iamVjdCBSZWdFeHBdJztcbn1cbmV4cG9ydHMuaXNSZWdFeHAgPSBpc1JlZ0V4cDtcblxuZnVuY3Rpb24gaXNPYmplY3QoYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnb2JqZWN0JyAmJiBhcmcgIT09IG51bGw7XG59XG5leHBvcnRzLmlzT2JqZWN0ID0gaXNPYmplY3Q7XG5cbmZ1bmN0aW9uIGlzRGF0ZShkKSB7XG4gIHJldHVybiBpc09iamVjdChkKSAmJiBvYmplY3RUb1N0cmluZyhkKSA9PT0gJ1tvYmplY3QgRGF0ZV0nO1xufVxuZXhwb3J0cy5pc0RhdGUgPSBpc0RhdGU7XG5cbmZ1bmN0aW9uIGlzRXJyb3IoZSkge1xuICByZXR1cm4gaXNPYmplY3QoZSkgJiZcbiAgICAgIChvYmplY3RUb1N0cmluZyhlKSA9PT0gJ1tvYmplY3QgRXJyb3JdJyB8fCBlIGluc3RhbmNlb2YgRXJyb3IpO1xufVxuZXhwb3J0cy5pc0Vycm9yID0gaXNFcnJvcjtcblxuZnVuY3Rpb24gaXNGdW5jdGlvbihhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdmdW5jdGlvbic7XG59XG5leHBvcnRzLmlzRnVuY3Rpb24gPSBpc0Z1bmN0aW9uO1xuXG5mdW5jdGlvbiBpc1ByaW1pdGl2ZShhcmcpIHtcbiAgcmV0dXJuIGFyZyA9PT0gbnVsbCB8fFxuICAgICAgICAgdHlwZW9mIGFyZyA9PT0gJ2Jvb2xlYW4nIHx8XG4gICAgICAgICB0eXBlb2YgYXJnID09PSAnbnVtYmVyJyB8fFxuICAgICAgICAgdHlwZW9mIGFyZyA9PT0gJ3N0cmluZycgfHxcbiAgICAgICAgIHR5cGVvZiBhcmcgPT09ICdzeW1ib2wnIHx8ICAvLyBFUzYgc3ltYm9sXG4gICAgICAgICB0eXBlb2YgYXJnID09PSAndW5kZWZpbmVkJztcbn1cbmV4cG9ydHMuaXNQcmltaXRpdmUgPSBpc1ByaW1pdGl2ZTtcblxuZXhwb3J0cy5pc0J1ZmZlciA9IHJlcXVpcmUoJy4vc3VwcG9ydC9pc0J1ZmZlcicpO1xuXG5mdW5jdGlvbiBvYmplY3RUb1N0cmluZyhvKSB7XG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwobyk7XG59XG5cblxuZnVuY3Rpb24gcGFkKG4pIHtcbiAgcmV0dXJuIG4gPCAxMCA/ICcwJyArIG4udG9TdHJpbmcoMTApIDogbi50b1N0cmluZygxMCk7XG59XG5cblxudmFyIG1vbnRocyA9IFsnSmFuJywgJ0ZlYicsICdNYXInLCAnQXByJywgJ01heScsICdKdW4nLCAnSnVsJywgJ0F1ZycsICdTZXAnLFxuICAgICAgICAgICAgICAnT2N0JywgJ05vdicsICdEZWMnXTtcblxuLy8gMjYgRmViIDE2OjE5OjM0XG5mdW5jdGlvbiB0aW1lc3RhbXAoKSB7XG4gIHZhciBkID0gbmV3IERhdGUoKTtcbiAgdmFyIHRpbWUgPSBbcGFkKGQuZ2V0SG91cnMoKSksXG4gICAgICAgICAgICAgIHBhZChkLmdldE1pbnV0ZXMoKSksXG4gICAgICAgICAgICAgIHBhZChkLmdldFNlY29uZHMoKSldLmpvaW4oJzonKTtcbiAgcmV0dXJuIFtkLmdldERhdGUoKSwgbW9udGhzW2QuZ2V0TW9udGgoKV0sIHRpbWVdLmpvaW4oJyAnKTtcbn1cblxuXG4vLyBsb2cgaXMganVzdCBhIHRoaW4gd3JhcHBlciB0byBjb25zb2xlLmxvZyB0aGF0IHByZXBlbmRzIGEgdGltZXN0YW1wXG5leHBvcnRzLmxvZyA9IGZ1bmN0aW9uKCkge1xuICBjb25zb2xlLmxvZygnJXMgLSAlcycsIHRpbWVzdGFtcCgpLCBleHBvcnRzLmZvcm1hdC5hcHBseShleHBvcnRzLCBhcmd1bWVudHMpKTtcbn07XG5cblxuLyoqXG4gKiBJbmhlcml0IHRoZSBwcm90b3R5cGUgbWV0aG9kcyBmcm9tIG9uZSBjb25zdHJ1Y3RvciBpbnRvIGFub3RoZXIuXG4gKlxuICogVGhlIEZ1bmN0aW9uLnByb3RvdHlwZS5pbmhlcml0cyBmcm9tIGxhbmcuanMgcmV3cml0dGVuIGFzIGEgc3RhbmRhbG9uZVxuICogZnVuY3Rpb24gKG5vdCBvbiBGdW5jdGlvbi5wcm90b3R5cGUpLiBOT1RFOiBJZiB0aGlzIGZpbGUgaXMgdG8gYmUgbG9hZGVkXG4gKiBkdXJpbmcgYm9vdHN0cmFwcGluZyB0aGlzIGZ1bmN0aW9uIG5lZWRzIHRvIGJlIHJld3JpdHRlbiB1c2luZyBzb21lIG5hdGl2ZVxuICogZnVuY3Rpb25zIGFzIHByb3RvdHlwZSBzZXR1cCB1c2luZyBub3JtYWwgSmF2YVNjcmlwdCBkb2VzIG5vdCB3b3JrIGFzXG4gKiBleHBlY3RlZCBkdXJpbmcgYm9vdHN0cmFwcGluZyAoc2VlIG1pcnJvci5qcyBpbiByMTE0OTAzKS5cbiAqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBjdG9yIENvbnN0cnVjdG9yIGZ1bmN0aW9uIHdoaWNoIG5lZWRzIHRvIGluaGVyaXQgdGhlXG4gKiAgICAgcHJvdG90eXBlLlxuICogQHBhcmFtIHtmdW5jdGlvbn0gc3VwZXJDdG9yIENvbnN0cnVjdG9yIGZ1bmN0aW9uIHRvIGluaGVyaXQgcHJvdG90eXBlIGZyb20uXG4gKi9cbmV4cG9ydHMuaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpO1xuXG5leHBvcnRzLl9leHRlbmQgPSBmdW5jdGlvbihvcmlnaW4sIGFkZCkge1xuICAvLyBEb24ndCBkbyBhbnl0aGluZyBpZiBhZGQgaXNuJ3QgYW4gb2JqZWN0XG4gIGlmICghYWRkIHx8ICFpc09iamVjdChhZGQpKSByZXR1cm4gb3JpZ2luO1xuXG4gIHZhciBrZXlzID0gT2JqZWN0LmtleXMoYWRkKTtcbiAgdmFyIGkgPSBrZXlzLmxlbmd0aDtcbiAgd2hpbGUgKGktLSkge1xuICAgIG9yaWdpbltrZXlzW2ldXSA9IGFkZFtrZXlzW2ldXTtcbiAgfVxuICByZXR1cm4gb3JpZ2luO1xufTtcblxuZnVuY3Rpb24gaGFzT3duUHJvcGVydHkob2JqLCBwcm9wKSB7XG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wKTtcbn1cbiIsIi8qIVxuICogZHVhbC1lbWl0dGVyIDxodHRwczovL2dpdGh1Yi5jb20vdHVubmNrb0NvcmUvZHVhbC1lbWl0dGVyPlxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxNSBDaGFybGlrZSBNaWtlIFJlYWdlbnQgPEB0dW5uY2tvQ29yZT4gKGh0dHA6Ly93d3cudHVubmNrb2NvcmUudGspXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKi9cblxuLyoganNoaW50IGFzaTp0cnVlICovXG5cbid1c2Ugc3RyaWN0J1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJ3V0aWwnKVxuXG4vKipcbiAqIEV4cG9zZSBgRHVhbEVtaXR0ZXJgXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBEdWFsRW1pdHRlclxuXG4vKipcbiAqID4gQ3JlYXRlIGEgbmV3IGluc3RhbmNlIG9mIGBEdWFsRW1pdHRlcmAuXG4gKlxuICogKipFeGFtcGxlKipcbiAqXG4gKiBgYGBqc1xuICogdmFyIER1YWxFbWl0dGVyID0gcmVxdWlyZSgnZHVhbC1lbWl0dGVyJylcbiAqIHZhciBlbWl0dGVyID0gbmV3IER1YWxFbWl0dGVyKClcbiAqIGBgYFxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBgW2V2ZW50c11gIEluaXRpYWxpemUgd2l0aCBkZWZhdWx0IGV2ZW50cy5cbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gRHVhbEVtaXR0ZXIgKGV2ZW50cykge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgRHVhbEVtaXR0ZXIpKSB7XG4gICAgcmV0dXJuIG5ldyBEdWFsRW1pdHRlcihldmVudHMpXG4gIH1cblxuICB0aGlzLl9ldmVudHMgPSBldmVudHMgJiYgdHlwZW9mIGV2ZW50cyA9PT0gJ29iamVjdCcgPyBldmVudHMgOiB7fVxufVxuXG4vKipcbiAqID4gQWRkL2JpbmQgZXZlbnQgbGlzdGVuZXIgdG8gY3VzdG9tIG9yIERPTSBldmVudC5cbiAqIE5vdGljZSB0aGF0IGB0aGlzYCBpbiBldmVudCBoYW5kbGVyIGZ1bmN0aW9uIHZhcnkgLSBpdCBjYW4gYmUgdGhlIERPTSBlbGVtZW50XG4gKiBvciBEdWFsRW1pdHRlciBpbnN0YW5jZS5cbiAqXG4gKiAqKkV4YW1wbGUqKlxuICpcbiAqIGBgYGpzXG4gKiBmdW5jdGlvbiBoYW5kbGVyIChhLCBiKSB7XG4gKiAgIGNvbnNvbGUubG9nKCdoaScsIGEsIGIpIC8vPT4gaGkgMTIzIGJhclxuICogfVxuICpcbiAqIGZ1bmN0aW9uIG9uY2xpY2sgKGV2dCkge1xuICogICBjb25zb2xlLmxvZyhldnQsICdjbGlja2VkJylcbiAqIH1cbiAqXG4gKiB2YXIgZWxlbWVudCA9IGRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvcignYS5saW5rJylcbiAqXG4gKiBlbWl0dGVyLm9uKCdjdXN0b20nLCBoYW5kbGVyKS5lbWl0KCdjdXN0b20nLCAxMjMsICdiYXInKVxuICogZW1pdHRlci5vbignY2xpY2snLCBvbmNsaWNrLCBlbGVtZW50KS5vZmYoJ2NsaWNrJywgb25jbGljaywgZWxlbWVudClcbiAqIGBgYFxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gYDxuYW1lPmAgZXZlbnQgbmFtZVxuICogQHBhcmFtICB7RnVuY3Rpb259IGA8Zm4+YCBldmVudCBoYW5kbGVyXG4gKiBAcGFyYW0gIHtPYmplY3R9IGBbZWxdYCBvcHRpb25hbCBET00gZWxlbWVudFxuICogQHJldHVybiB7RHVhbEVtaXR0ZXJ9IER1YWxFbWl0dGVyIGZvciBjaGFpbmluZ1xuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5EdWFsRW1pdHRlci5wcm90b3R5cGUub24gPSBmdW5jdGlvbiBvbiAobmFtZSwgZm4sIGVsKSB7XG4gIGlmICh0eXBlb2YgbmFtZSAhPT0gJ3N0cmluZycpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdEdWFsRW1pdHRlciNvbiBleHBlY3QgYG5hbWVgIGJlIHN0cmluZycpXG4gIH1cbiAgaWYgKHR5cGVvZiBmbiAhPT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0R1YWxFbWl0dGVyI29uIGV4cGVjdCBgZm5gIGJlIGZ1bmN0aW9uJylcbiAgfVxuXG4gIHRoaXMuX2V2ZW50c1tuYW1lXSA9IHRoaXMuX2hhc093bih0aGlzLl9ldmVudHMsIG5hbWUpID8gdGhpcy5fZXZlbnRzW25hbWVdIDogW11cbiAgdGhpcy5fZXZlbnRzW25hbWVdLnB1c2goZm4pXG5cbiAgaWYgKGVsICYmIHRoaXMuX2lzRG9tKGVsKSkge1xuICAgIGZuLm91dGVySFRNTCA9IGVsLm91dGVySFRNTFxuICAgIHRoaXMuX2VsZW1lbnQgPSBlbFxuICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIgPyBlbC5hZGRFdmVudExpc3RlbmVyKG5hbWUsIGZuLCBmYWxzZSkgOiBlbC5hdHRhY2hFdmVudCgnb24nICsgbmFtZSwgZm4pXG4gIH1cbiAgcmV0dXJuIHRoaXNcbn1cblxuLyoqXG4gKiA+IFJlbW92ZS91bmJpbmQgZXZlbnQgbGlzdGVuZXIgb2YgY3VzdG9tIG9yIERPTSBldmVudC5cbiAqXG4gKiAqKkV4YW1wbGUqKlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgZWxlbWVudCA9IGRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvcignYS5saW5rJylcbiAqIGVtaXR0ZXIub2ZmKCdjdXN0b20nLCBoYW5kbGVyKVxuICogZW1pdHRlci5vZmYoJ2NsaWNrJywgb25jbGljaywgZWxlbWVudClcbiAqIGBgYFxuICpcbiAqIEBwYXJhbSAge1N0cmluZ30gYDxuYW1lPmAgZXZlbnQgbmFtZVxuICogQHBhcmFtICB7RnVuY3Rpb259IGA8Zm4+YCBldmVudCBoYW5kbGVyXG4gKiBAcGFyYW0gIHtPYmplY3R9IGBbZWxdYCBvcHRpb25hbCBET00gZWxlbWVudFxuICogQHJldHVybiB7RHVhbEVtaXR0ZXJ9IER1YWxFbWl0dGVyIGZvciBjaGFpbmluZ1xuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5EdWFsRW1pdHRlci5wcm90b3R5cGUub2ZmID0gZnVuY3Rpb24gb2ZmIChuYW1lLCBmbiwgZWwpIHtcbiAgaWYgKHR5cGVvZiBuYW1lICE9PSAnc3RyaW5nJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0R1YWxFbWl0dGVyI29mZiBleHBlY3QgYG5hbWVgIGJlIHN0cmluZycpXG4gIH1cbiAgaWYgKHR5cGVvZiBmbiAhPT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0R1YWxFbWl0dGVyI29mZiBleHBlY3QgYGZuYCBiZSBmdW5jdGlvbicpXG4gIH1cbiAgaWYgKCF0aGlzLl9oYXNPd24odGhpcy5fZXZlbnRzLCBuYW1lKSkge3JldHVybiB0aGlzfVxuICB0aGlzLl9ldmVudHNbbmFtZV0uc3BsaWNlKHRoaXMuX2V2ZW50c1tuYW1lXS5pbmRleE9mKGZuKSwgMSlcblxuICBpZiAoZWwgJiYgdGhpcy5faXNEb20oZWwpKSB7XG4gICAgZWwucmVtb3ZlRXZlbnRMaXN0ZW5lciA/IGVsLnJlbW92ZUV2ZW50TGlzdGVuZXIobmFtZSwgZm4sIGZhbHNlKSA6IGVsLmRldGFjaEV2ZW50KCdvbicgKyBuYW1lLCBmbilcbiAgfVxuICByZXR1cm4gdGhpc1xufVxuXG4vKipcbiAqID4gQWRkIG9uZS10aW1lIGV2ZW50IGxpc3RlbmVyIHRvIGN1c3RvbSBvciBET00gZXZlbnQuXG4gKiBOb3RpY2UgdGhhdCBgdGhpc2AgaW4gZXZlbnQgaGFuZGxlciBmdW5jdGlvbiB2YXJ5IC0gaXQgY2FuIGJlIHRoZSBET00gZWxlbWVudFxuICogb3IgRHVhbEVtaXR0ZXIgaW5zdGFuY2UuXG4gKlxuICogKipFeGFtcGxlKipcbiAqXG4gKiBgYGBqc1xuICogZW1pdHRlclxuICogICAub25jZSgnY3VzdG9tJywgZnVuY3Rpb24gKCkge1xuICogICAgIGNvbnNvbGUubG9nKCdleGVjdXRlZCBvbmUgdGltZScpXG4gKiAgIH0pXG4gKiAgIC5lbWl0KCdjdXN0b20nKVxuICogICAuZW1pdCgnY3VzdG9tJylcbiAqXG4gKiB2YXIgZWxlbWVudCA9IGRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvcignYS5saW5rJylcbiAqIGVtaXR0ZXIub25jZSgnY2xpY2snLCBmdW5jdGlvbiAoKSB7XG4gKiAgIGNvbnNvbGUubG9nKCdsaXN0ZW4gZm9yIGNsaWNrIGV2ZW50IG9ubHkgb25jZScpXG4gKiB9LCBlbGVtZW50KVxuICogYGBgXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSBgPG5hbWU+YCBldmVudCBuYW1lXG4gKiBAcGFyYW0gIHtGdW5jdGlvbn0gYDxmbj5gIGV2ZW50IGhhbmRsZXJcbiAqIEBwYXJhbSAge09iamVjdH0gYFtlbF1gIG9wdGlvbmFsIERPTSBlbGVtZW50XG4gKiBAcmV0dXJuIHtEdWFsRW1pdHRlcn0gRHVhbEVtaXR0ZXIgZm9yIGNoYWluaW5nXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbkR1YWxFbWl0dGVyLnByb3RvdHlwZS5vbmNlID0gZnVuY3Rpb24gb25jZSAobmFtZSwgZm4sIGVsKSB7XG4gIHZhciBzZWxmID0gdGhpc1xuICBmdW5jdGlvbiBoYW5kbGVyICgpIHtcbiAgICBzZWxmLm9mZihuYW1lLCBoYW5kbGVyLCBlbClcbiAgICByZXR1cm4gZm4uYXBwbHkoZWwsIGFyZ3VtZW50cylcbiAgfVxuICByZXR1cm4gdGhpcy5vbihuYW1lLCBoYW5kbGVyLCBlbClcbn1cblxuLyoqXG4gKiA+IEVtaXQvZXhlY3V0ZSBzb21lIHR5cGUgb2YgZXZlbnQgbGlzdGVuZXIuXG4gKiBZb3UgYWxzbyBjYW4gZW1pdCBET00gZXZlbnRzIGlmIGxhc3QgYXJndW1lbnRcbiAqIGlzIHRoZSBET00gZWxlbWVudCB0aGF0IGhhdmUgYXR0YWNoZWQgZXZlbnQgbGlzdGVuZXIuXG4gKlxuICogKipFeGFtcGxlKipcbiAqXG4gKiBgYGBqc1xuICogdmFyIGkgPSAwXG4gKlxuICogZW1pdHRlclxuICogICAub24oJ2N1c3RvbScsIGZ1bmN0aW9uICgpIHtcbiAqICAgICBjb25zb2xlLmxvZygnaSA9PScsIGkrKywgYXJndW1lbnRzKVxuICogICB9KVxuICogICAuZW1pdCgnY3VzdG9tJylcbiAqICAgLmVtaXQoJ2N1c3RvbScsIDEyMylcbiAqICAgLmVtaXQoJ2N1c3RvbScsICdmb28nLCAnYmFyJywgJ2JheicpXG4gKiAgIC5lbWl0KCdjdXN0b20nLCBbMSwgMiwgM10sIDQsIDUpXG4gKlxuICogLy8gb3IgZXZlbiBlbWl0IERPTSBldmVudHMsIGJ1dCB5b3Ugc2hvdWxkXG4gKiAvLyBnaXZlIHRoZSBlbGVtZW50IGFzIGxhc3QgYXJndW1lbnQgdG8gYC5lbWl0YCBtZXRob2RcbiAqIHZhciBlbGVtZW50ID0gZG9jdW1lbnQuYm9keS5xdWVyeVNlbGVjdG9yKCdhLmxpbmsnKVxuICogdmFyIGNsaWNrcyA9IDBcbiAqXG4gKiBlbWl0dGVyXG4gKiAgIC5vbignY2xpY2snLCBmdW5jdGlvbiAoYSkge1xuICogICAgIGNvbnNvbGUubG9nKGEsICdjbGlja2VkJywgY2xpY2tzKyspXG4gKiAgICAgY29uc29sZS5sb2codGhpcy50ZXh0Q29udGVudCkgLy8gY29udGVudCBvZiA8YT4gdGFnXG4gKiAgIH0sIGVsZW1lbnQpXG4gKiAgIC5lbWl0KCdjbGljaycsIDEyMywgZWxlbWVudClcbiAqICAgLmVtaXQoJ2NsaWNrJywgZWxlbWVudClcbiAqICAgLmVtaXQoJ2NsaWNrJywgZm9vLCBlbGVtZW50KVxuICogYGBgXG4gKlxuICogQHBhcmFtICB7U3RyaW5nfSBgPG5hbWU+YCBldmVudCBuYW1lXG4gKiBAcGFyYW0gIHtNaXhlZH0gYFthcmdzLi4uXWAgY29udGV4dCB0byBwYXNzIHRvIGV2ZW50IGxpc3RlbmVyc1xuICogQHBhcmFtICB7T2JqZWN0fSBgW2VsXWAgb3B0aW9uYWwgRE9NIGVsZW1lbnRcbiAqIEByZXR1cm4ge0R1YWxFbWl0dGVyfSBEdWFsRW1pdHRlciBmb3IgY2hhaW5pbmdcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuRHVhbEVtaXR0ZXIucHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbiBlbWl0IChuYW1lKSB7XG4gIGlmICghdGhpcy5faGFzT3duKHRoaXMuX2V2ZW50cywgbmFtZSkpIHtyZXR1cm4gdGhpc31cbiAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpXG4gIHZhciBlbCA9IGFyZ3NbYXJncy5sZW5ndGggLSAxXVxuICB2YXIgaXNkb20gPSB0aGlzLl9pc0RvbShlbClcbiAgZWwgPSBpc2RvbSA/IGVsIDogdGhpc1xuICBhcmdzID0gaXNkb20gPyBhcmdzLnNsaWNlKDAsIC0xKSA6IGFyZ3NcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuX2V2ZW50c1tuYW1lXS5sZW5ndGg7IGkrKykge1xuICAgIHZhciBmbiA9IHRoaXMuX2V2ZW50c1tuYW1lXVtpXVxuICAgIGlmIChpc2RvbSAmJiBmbi5vdXRlckhUTUwgIT09IGVsLm91dGVySFRNTCkge1xuICAgICAgY29udGludWVcbiAgICB9XG4gICAgZm4uYXBwbHkoZWwsIGFyZ3MpXG4gIH1cbiAgcmV0dXJuIHRoaXNcbn1cblxuLyoqXG4gKiA+IENoZWNrIHRoYXQgZ2l2ZW4gYHZhbGAgaXMgRE9NIGVsZW1lbnQuIFVzZWQgaW50ZXJuYWxseS5cbiAqXG4gKiAqKkV4YW1wbGUqKlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgZWxlbWVudCA9IGRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvcignYS5saW5rJylcbiAqXG4gKiBlbWl0dGVyLl9pc0RvbShlbGVtZW50KSAvLz0+IHRydWVcbiAqIGVtaXR0ZXIuX2lzRG9tKHthOiAnYid9KSAvLz0+IGZhbHNlXG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0gIHtNaXhlZH0gIGB2YWxgXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5EdWFsRW1pdHRlci5wcm90b3R5cGUuX2lzRG9tID0gZnVuY3Rpb24gaXNEb20gKHZhbCkge1xuICB2YWwgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodmFsKS5zbGljZSg4LCAtMSlcbiAgcmV0dXJuIC8oPzpIVE1MKT8oPzouKilFbGVtZW50Ly50ZXN0KHZhbClcbn1cblxuLyoqXG4gKiA+IENoZWNrIHRoYXQgYGtleWAgZXhpc3RzIGluIHRoZSBnaXZlbiBgb2JqYC5cbiAqXG4gKiAqKkV4YW1wbGUqKlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgb2JqID0ge2E6ICdiJ31cbiAqXG4gKiBlbWl0dGVyLl9oYXNPd24ob2JqLCAnYScpIC8vPT4gdHJ1ZVxuICogZW1pdHRlci5faGFzT3duKG9iaiwgJ2ZvbycpIC8vPT4gZmFsc2VcbiAqIGBgYFxuICpcbiAqIEBwYXJhbSAge09iamVjdH0gIGBvYmpgXG4gKiBAcGFyYW0gIHtTdHJpbmd9ICBga2V5YFxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqIEBhcGkgcHVibGljXG4gKi9cblxuRHVhbEVtaXR0ZXIucHJvdG90eXBlLl9oYXNPd24gPSBmdW5jdGlvbiBoYXNPd24gKG9iaiwga2V5KSB7XG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBrZXkpXG59XG5cbi8qKlxuICogU3RhdGljIG1ldGhvZCBmb3IgaW5oZXJpdGluZyBib3RoIHRoZSBwcm90b3R5cGUgYW5kXG4gKiBzdGF0aWMgbWV0aG9kcyBvZiB0aGUgYER1YWxFbWl0dGVyYCBjbGFzcy5cbiAqXG4gKiBgYGBqc1xuICogZnVuY3Rpb24gTXlBcHAob3B0aW9ucykge1xuICogICBEdWFsRW1pdHRlci5jYWxsKHRoaXMpXG4gKiB9XG4gKiBEdWFsRW1pdHRlci5leHRlbmQoTXlBcHApXG4gKlxuICpcbiAqIC8vIE9wdGlvbmFsbHkgcGFzcyBhbm90aGVyIG9iamVjdCB0byBleHRlbmQgb250byBgTXlBcHBgXG4gKiBmdW5jdGlvbiBNeUFwcChvcHRpb25zKSB7XG4gKiAgIER1YWxFbWl0dGVyLmNhbGwodGhpcylcbiAqICAgRm9vLmNhbGwodGhpcywgb3B0aW9ucylcbiAqIH1cbiAqIER1YWxFbWl0dGVyLmV4dGVuZChNeUFwcCwgRm9vLnByb3RvdHlwZSlcbiAqIGBgYFxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGBDdG9yYCBUaGUgY29uc3RydWN0b3IgdG8gZXh0ZW5kLlxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5EdWFsRW1pdHRlci5leHRlbmQgPSBmdW5jdGlvbiAoQ3RvciwgcHJvdG8pIHtcbiAgdXRpbC5pbmhlcml0cyhDdG9yLCBEdWFsRW1pdHRlcilcbiAgZm9yICh2YXIga2V5IGluIER1YWxFbWl0dGVyKSB7XG4gICAgQ3RvcltrZXldID0gRHVhbEVtaXR0ZXJba2V5XVxuICB9XG5cbiAgaWYgKHR5cGVvZiBwcm90byA9PT0gJ29iamVjdCcpIHtcbiAgICB2YXIgb2JqID0gT2JqZWN0LmNyZWF0ZShwcm90bylcblxuICAgIGZvciAodmFyIGsgaW4gb2JqKSB7XG4gICAgICBDdG9yLnByb3RvdHlwZVtrXSA9IG9ialtrXVxuICAgIH1cbiAgfVxufVxuIl19 1021 | -------------------------------------------------------------------------------- /dist/dual-emitter.min.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.DualEmitter=e()}}(function(){return function e(t,n,r){function o(u,s){if(!n[u]){if(!t[u]){var c="function"==typeof require&&require;if(!s&&c)return c(u,!0);if(i)return i(u,!0);var f=new Error("Cannot find module '"+u+"'");throw f.code="MODULE_NOT_FOUND",f}var a=n[u]={exports:{}};t[u][0].call(a.exports,function(e){var n=t[u][1][e];return o(n?n:e)},a,a.exports,e,t,n,r)}return n[u].exports}for(var i="function"==typeof require&&require,u=0;u1)for(var n=1;n=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),h(t)?r.showHidden=t:t&&n._extend(r,t),O(r.showHidden)&&(r.showHidden=!1),O(r.depth)&&(r.depth=2),O(r.colors)&&(r.colors=!1),O(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=i),c(r,e,r.depth)}function i(e,t){var n=o.styles[t];return n?"["+o.colors[n][0]+"m"+e+"["+o.colors[n][1]+"m":e}function u(e,t){return e}function s(e){var t={};return e.forEach(function(e,n){t[e]=!0}),t}function c(e,t,r){if(e.customInspect&&t&&D(t.inspect)&&t.inspect!==n.inspect&&(!t.constructor||t.constructor.prototype!==t)){var o=t.inspect(r,e);return b(o)||(o=c(e,o,r)),o}var i=f(e,t);if(i)return i;var u=Object.keys(t),h=s(u);if(e.showHidden&&(u=Object.getOwnPropertyNames(t)),j(t)&&(u.indexOf("message")>=0||u.indexOf("description")>=0))return a(t);if(0===u.length){if(D(t)){var d=t.name?": "+t.name:"";return e.stylize("[Function"+d+"]","special")}if(E(t))return e.stylize(RegExp.prototype.toString.call(t),"regexp");if(_(t))return e.stylize(Date.prototype.toString.call(t),"date");if(j(t))return a(t)}var v="",m=!1,w=["{","}"];if(g(t)&&(m=!0,w=["[","]"]),D(t)){var O=t.name?": "+t.name:"";v=" [Function"+O+"]"}if(E(t)&&(v=" "+RegExp.prototype.toString.call(t)),_(t)&&(v=" "+Date.prototype.toUTCString.call(t)),j(t)&&(v=" "+a(t)),0===u.length&&(!m||0==t.length))return w[0]+v+w[1];if(0>r)return E(t)?e.stylize(RegExp.prototype.toString.call(t),"regexp"):e.stylize("[Object]","special");e.seen.push(t);var x;return x=m?p(e,t,r,h,u):u.map(function(n){return l(e,t,r,h,n,m)}),e.seen.pop(),y(x,v,w)}function f(e,t){if(O(t))return e.stylize("undefined","undefined");if(b(t)){var n="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(n,"string")}return m(t)?e.stylize(""+t,"number"):h(t)?e.stylize(""+t,"boolean"):d(t)?e.stylize("null","null"):void 0}function a(e){return"["+Error.prototype.toString.call(e)+"]"}function p(e,t,n,r,o){for(var i=[],u=0,s=t.length;s>u;++u)N(t,String(u))?i.push(l(e,t,n,r,String(u),!0)):i.push("");return o.forEach(function(o){o.match(/^\d+$/)||i.push(l(e,t,n,r,o,!0))}),i}function l(e,t,n,r,o,i){var u,s,f;if(f=Object.getOwnPropertyDescriptor(t,o)||{value:t[o]},f.get?s=f.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):f.set&&(s=e.stylize("[Setter]","special")),N(r,o)||(u="["+o+"]"),s||(e.seen.indexOf(f.value)<0?(s=d(n)?c(e,f.value,null):c(e,f.value,n-1),s.indexOf("\n")>-1&&(s=i?s.split("\n").map(function(e){return" "+e}).join("\n").substr(2):"\n"+s.split("\n").map(function(e){return" "+e}).join("\n"))):s=e.stylize("[Circular]","special")),O(u)){if(i&&o.match(/^\d+$/))return s;u=JSON.stringify(""+o),u.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(u=u.substr(1,u.length-2),u=e.stylize(u,"name")):(u=u.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),u=e.stylize(u,"string"))}return u+": "+s}function y(e,t,n){var r=0,o=e.reduce(function(e,t){return r++,t.indexOf("\n")>=0&&r++,e+t.replace(/\u001b\[\d\d?m/g,"").length+1},0);return o>60?n[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+n[1]:n[0]+t+" "+e.join(", ")+" "+n[1]}function g(e){return Array.isArray(e)}function h(e){return"boolean"==typeof e}function d(e){return null===e}function v(e){return null==e}function m(e){return"number"==typeof e}function b(e){return"string"==typeof e}function w(e){return"symbol"==typeof e}function O(e){return void 0===e}function E(e){return x(e)&&"[object RegExp]"===z(e)}function x(e){return"object"==typeof e&&null!==e}function _(e){return x(e)&&"[object Date]"===z(e)}function j(e){return x(e)&&("[object Error]"===z(e)||e instanceof Error)}function D(e){return"function"==typeof e}function S(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||"undefined"==typeof e}function z(e){return Object.prototype.toString.call(e)}function T(e){return 10>e?"0"+e.toString(10):e.toString(10)}function L(){var e=new Date,t=[T(e.getHours()),T(e.getMinutes()),T(e.getSeconds())].join(":");return[e.getDate(),U[e.getMonth()],t].join(" ")}function N(e,t){return Object.prototype.hasOwnProperty.call(e,t)}var A=/%[sdj%]/g;n.format=function(e){if(!b(e)){for(var t=[],n=0;n=i)return e;switch(e){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(t){return"[Circular]"}default:return e}}),s=r[n];i>n;s=r[++n])u+=d(s)||!x(s)?" "+s:" "+o(s);return u},n.deprecate=function(e,o){function i(){if(!u){if(t.throwDeprecation)throw new Error(o);t.traceDeprecation?console.trace(o):console.error(o),u=!0}return e.apply(this,arguments)}if(O(r.process))return function(){return n.deprecate(e,o).apply(this,arguments)};if(t.noDeprecation===!0)return e;var u=!1;return i};var H,M={};n.debuglog=function(e){if(O(H)&&(H=t.env.NODE_DEBUG||""),e=e.toUpperCase(),!M[e])if(new RegExp("\\b"+e+"\\b","i").test(H)){var r=t.pid;M[e]=function(){var t=n.format.apply(n,arguments);console.error("%s %d: %s",e,r,t)}}else M[e]=function(){};return M[e]},n.inspect=o,o.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},o.styles={special:"cyan",number:"yellow","boolean":"yellow",undefined:"grey","null":"bold",string:"green",date:"magenta",regexp:"red"},n.isArray=g,n.isBoolean=h,n.isNull=d,n.isNullOrUndefined=v,n.isNumber=m,n.isString=b,n.isSymbol=w,n.isUndefined=O,n.isRegExp=E,n.isObject=x,n.isDate=_,n.isError=j,n.isFunction=D,n.isPrimitive=S,n.isBuffer=e("./support/isBuffer");var U=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];n.log=function(){console.log("%s - %s",L(),n.format.apply(n,arguments))},n.inherits=e("inherits"),n._extend=function(e,t){if(!t||!x(t))return e;for(var n=Object.keys(t),r=n.length;r--;)e[n[r]]=t[n[r]];return e}}).call(this,e("_process"),"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./support/isBuffer":3,_process:2,inherits:1}],5:[function(e,t,n){"use strict";function r(e){return this instanceof r?void(this._events=e&&"object"==typeof e?e:{}):new r(e)}var o=e("util");t.exports=r,r.prototype.on=function(e,t,n){if("string"!=typeof e)throw new TypeError("DualEmitter#on expect `name` be string");if("function"!=typeof t)throw new TypeError("DualEmitter#on expect `fn` be function");return this._events[e]=this._hasOwn(this._events,e)?this._events[e]:[],this._events[e].push(t),n&&this._isDom(n)&&(t.outerHTML=n.outerHTML,this._element=n,n.addEventListener?n.addEventListener(e,t,!1):n.attachEvent("on"+e,t)),this},r.prototype.off=function(e,t,n){if("string"!=typeof e)throw new TypeError("DualEmitter#off expect `name` be string");if("function"!=typeof t)throw new TypeError("DualEmitter#off expect `fn` be function");return this._hasOwn(this._events,e)?(this._events[e].splice(this._events[e].indexOf(t),1),n&&this._isDom(n)&&(n.removeEventListener?n.removeEventListener(e,t,!1):n.detachEvent("on"+e,t)),this):this},r.prototype.once=function(e,t,n){function r(){return o.off(e,r,n),t.apply(n,arguments)}var o=this;return this.on(e,r,n)},r.prototype.emit=function(e){if(!this._hasOwn(this._events,e))return this;var t=Array.prototype.slice.call(arguments,1),n=t[t.length-1],r=this._isDom(n);n=r?n:this,t=r?t.slice(0,-1):t;for(var o=0;o 3 | * 4 | * Copyright (c) 2015 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk) 5 | * Released under the MIT license. 6 | */ 7 | 8 | /* jshint asi:true */ 9 | 10 | 'use strict' 11 | 12 | var util = require('util') 13 | 14 | /** 15 | * Expose `DualEmitter` 16 | */ 17 | 18 | module.exports = DualEmitter 19 | 20 | /** 21 | * > Create a new instance of `DualEmitter`. 22 | * 23 | * **Example** 24 | * 25 | * ```js 26 | * var DualEmitter = require('dual-emitter') 27 | * var emitter = new DualEmitter() 28 | * ``` 29 | * 30 | * @param {Object} `[events]` Initialize with default events. 31 | * @api public 32 | */ 33 | 34 | function DualEmitter (events) { 35 | if (!(this instanceof DualEmitter)) { 36 | return new DualEmitter(events) 37 | } 38 | 39 | this._events = events && typeof events === 'object' ? events : {} 40 | } 41 | 42 | /** 43 | * > Add/bind event listener to custom or DOM event. 44 | * Notice that `this` in event handler function vary - it can be the DOM element 45 | * or DualEmitter instance. 46 | * 47 | * **Example** 48 | * 49 | * ```js 50 | * function handler (a, b) { 51 | * console.log('hi', a, b) //=> hi 123 bar 52 | * } 53 | * 54 | * function onclick (evt) { 55 | * console.log(evt, 'clicked') 56 | * } 57 | * 58 | * var element = document.body.querySelector('a.link') 59 | * 60 | * emitter.on('custom', handler).emit('custom', 123, 'bar') 61 | * emitter.on('click', onclick, element).off('click', onclick, element) 62 | * ``` 63 | * 64 | * @param {String} `` event name 65 | * @param {Function} `` event handler 66 | * @param {Object} `[el]` optional DOM element 67 | * @return {DualEmitter} DualEmitter for chaining 68 | * @api public 69 | */ 70 | 71 | DualEmitter.prototype.on = function on (name, fn, el) { 72 | if (typeof name !== 'string') { 73 | throw new TypeError('DualEmitter#on expect `name` be string') 74 | } 75 | if (typeof fn !== 'function') { 76 | throw new TypeError('DualEmitter#on expect `fn` be function') 77 | } 78 | 79 | this._events[name] = this._hasOwn(this._events, name) ? this._events[name] : [] 80 | this._events[name].push(fn) 81 | 82 | if (el && this._isDom(el)) { 83 | fn.outerHTML = el.outerHTML 84 | this._element = el 85 | el.addEventListener ? el.addEventListener(name, fn, false) : el.attachEvent('on' + name, fn) 86 | } 87 | return this 88 | } 89 | 90 | /** 91 | * > Remove/unbind event listener of custom or DOM event. 92 | * 93 | * **Example** 94 | * 95 | * ```js 96 | * var element = document.body.querySelector('a.link') 97 | * emitter.off('custom', handler) 98 | * emitter.off('click', onclick, element) 99 | * ``` 100 | * 101 | * @param {String} `` event name 102 | * @param {Function} `` event handler 103 | * @param {Object} `[el]` optional DOM element 104 | * @return {DualEmitter} DualEmitter for chaining 105 | * @api public 106 | */ 107 | 108 | DualEmitter.prototype.off = function off (name, fn, el) { 109 | if (typeof name !== 'string') { 110 | throw new TypeError('DualEmitter#off expect `name` be string') 111 | } 112 | if (typeof fn !== 'function') { 113 | throw new TypeError('DualEmitter#off expect `fn` be function') 114 | } 115 | if (!this._hasOwn(this._events, name)) {return this} 116 | this._events[name].splice(this._events[name].indexOf(fn), 1) 117 | 118 | if (el && this._isDom(el)) { 119 | el.removeEventListener ? el.removeEventListener(name, fn, false) : el.detachEvent('on' + name, fn) 120 | } 121 | return this 122 | } 123 | 124 | /** 125 | * > Add one-time event listener to custom or DOM event. 126 | * Notice that `this` in event handler function vary - it can be the DOM element 127 | * or DualEmitter instance. 128 | * 129 | * **Example** 130 | * 131 | * ```js 132 | * emitter 133 | * .once('custom', function () { 134 | * console.log('executed one time') 135 | * }) 136 | * .emit('custom') 137 | * .emit('custom') 138 | * 139 | * var element = document.body.querySelector('a.link') 140 | * emitter.once('click', function () { 141 | * console.log('listen for click event only once') 142 | * }, element) 143 | * ``` 144 | * 145 | * @param {String} `` event name 146 | * @param {Function} `` event handler 147 | * @param {Object} `[el]` optional DOM element 148 | * @return {DualEmitter} DualEmitter for chaining 149 | * @api public 150 | */ 151 | 152 | DualEmitter.prototype.once = function once (name, fn, el) { 153 | var self = this 154 | function handler () { 155 | self.off(name, handler, el) 156 | return fn.apply(el, arguments) 157 | } 158 | return this.on(name, handler, el) 159 | } 160 | 161 | /** 162 | * > Emit/execute some type of event listener. 163 | * You also can emit DOM events if last argument 164 | * is the DOM element that have attached event listener. 165 | * 166 | * **Example** 167 | * 168 | * ```js 169 | * var i = 0 170 | * 171 | * emitter 172 | * .on('custom', function () { 173 | * console.log('i ==', i++, arguments) 174 | * }) 175 | * .emit('custom') 176 | * .emit('custom', 123) 177 | * .emit('custom', 'foo', 'bar', 'baz') 178 | * .emit('custom', [1, 2, 3], 4, 5) 179 | * 180 | * // or even emit DOM events, but you should 181 | * // give the element as last argument to `.emit` method 182 | * var element = document.body.querySelector('a.link') 183 | * var clicks = 0 184 | * 185 | * emitter 186 | * .on('click', function (a) { 187 | * console.log(a, 'clicked', clicks++) 188 | * console.log(this.textContent) // content of tag 189 | * }, element) 190 | * .emit('click', 123, element) 191 | * .emit('click', element) 192 | * .emit('click', foo, element) 193 | * ``` 194 | * 195 | * @param {String} `` event name 196 | * @param {Mixed} `[args...]` context to pass to event listeners 197 | * @param {Object} `[el]` optional DOM element 198 | * @return {DualEmitter} DualEmitter for chaining 199 | * @api public 200 | */ 201 | 202 | DualEmitter.prototype.emit = function emit (name) { 203 | if (!this._hasOwn(this._events, name)) {return this} 204 | var args = Array.prototype.slice.call(arguments, 1) 205 | var el = args[args.length - 1] 206 | var isdom = this._isDom(el) 207 | el = isdom ? el : this 208 | args = isdom ? args.slice(0, -1) : args 209 | 210 | for (var i = 0; i < this._events[name].length; i++) { 211 | var fn = this._events[name][i] 212 | if (isdom && fn.outerHTML !== el.outerHTML) { 213 | continue 214 | } 215 | fn.apply(el, args) 216 | } 217 | return this 218 | } 219 | 220 | /** 221 | * > Check that given `val` is DOM element. Used internally. 222 | * 223 | * **Example** 224 | * 225 | * ```js 226 | * var element = document.body.querySelector('a.link') 227 | * 228 | * emitter._isDom(element) //=> true 229 | * emitter._isDom({a: 'b'}) //=> false 230 | * ``` 231 | * 232 | * @param {Mixed} `val` 233 | * @return {Boolean} 234 | * @api public 235 | */ 236 | 237 | DualEmitter.prototype._isDom = function isDom (val) { 238 | val = Object.prototype.toString.call(val).slice(8, -1) 239 | return /(?:HTML)?(?:.*)Element/.test(val) 240 | } 241 | 242 | /** 243 | * > Check that `key` exists in the given `obj`. 244 | * 245 | * **Example** 246 | * 247 | * ```js 248 | * var obj = {a: 'b'} 249 | * 250 | * emitter._hasOwn(obj, 'a') //=> true 251 | * emitter._hasOwn(obj, 'foo') //=> false 252 | * ``` 253 | * 254 | * @param {Object} `obj` 255 | * @param {String} `key` 256 | * @return {Boolean} 257 | * @api public 258 | */ 259 | 260 | DualEmitter.prototype._hasOwn = function hasOwn (obj, key) { 261 | return Object.prototype.hasOwnProperty.call(obj, key) 262 | } 263 | 264 | /** 265 | * Static method for inheriting both the prototype and 266 | * static methods of the `DualEmitter` class. 267 | * 268 | * ```js 269 | * function MyApp(options) { 270 | * DualEmitter.call(this) 271 | * } 272 | * DualEmitter.extend(MyApp) 273 | * 274 | * 275 | * // Optionally pass another object to extend onto `MyApp` 276 | * function MyApp(options) { 277 | * DualEmitter.call(this) 278 | * Foo.call(this, options) 279 | * } 280 | * DualEmitter.extend(MyApp, Foo.prototype) 281 | * ``` 282 | * 283 | * @param {Function} `Ctor` The constructor to extend. 284 | * @api public 285 | */ 286 | 287 | DualEmitter.extend = function (Ctor, proto) { 288 | util.inherits(Ctor, DualEmitter) 289 | for (var key in DualEmitter) { 290 | Ctor[key] = DualEmitter[key] 291 | } 292 | 293 | if (typeof proto === 'object') { 294 | var obj = Object.create(proto) 295 | 296 | for (var k in obj) { 297 | Ctor.prototype[k] = obj[k] 298 | } 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dual-emitter", 3 | "version": "0.7.0", 4 | "description": ":tropical_drink: EventEmitter done right and no dependencies. For nodejs and the browser (>= IE8). Can emit custom or DOM events.", 5 | "repository": "tunnckoCore/dual-emitter", 6 | "author": "Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk)", 7 | "main": "index.js", 8 | "license": "MIT", 9 | "scripts": { 10 | "build": "npm run bundle && npm run minify", 11 | "bundle": "browserify -s DualEmitter -do dist/dual-emitter.js index.js", 12 | "minify": "uglifyjs -m -c -o dist/dual-emitter.min.js dist/dual-emitter.js", 13 | "test": "standard && node test.js" 14 | }, 15 | "dependencies": {}, 16 | "devDependencies": { 17 | "assertit": "^0.1.0", 18 | "browserify": "^11.0.1", 19 | "cheerio": "^0.19.0", 20 | "uglify-js": "^2.4.24" 21 | }, 22 | "keywords": [ 23 | "bind", 24 | "browser", 25 | "chrome", 26 | "chromium", 27 | "cross", 28 | "cross-browser", 29 | "custom", 30 | "dom", 31 | "dual", 32 | "el", 33 | "element", 34 | "elements", 35 | "emit", 36 | "emitter", 37 | "event", 38 | "events", 39 | "explorer", 40 | "firefox", 41 | "ie", 42 | "internet", 43 | "invoke", 44 | "micro", 45 | "microjs", 46 | "mini", 47 | "mozilla", 48 | "node", 49 | "nodejs", 50 | "off", 51 | "on", 52 | "once", 53 | "one", 54 | "onetime", 55 | "trigger", 56 | "unbind" 57 | ], 58 | "standard": { 59 | "ignore": [ 60 | "dist/**" 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * dual-emitter 3 | * 4 | * Copyright (c) 2015 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk) 5 | * Released under the MIT license. 6 | */ 7 | 8 | /* jshint asi:true */ 9 | 10 | 'use strict' 11 | 12 | var test = require('assertit') 13 | var DualEmitter = require('./index') 14 | 15 | test('dual-emitter:', function () { 16 | test('constructor should accept only object', function (done) { 17 | var emitter = new DualEmitter(12345) 18 | 19 | test.deepEqual(emitter._events, {}) 20 | done() 21 | }) 22 | test('should listen `.on` custom event `.emit` few times', function (done) { 23 | var emitter = new DualEmitter() 24 | var count = 0 25 | var results = [] 26 | 27 | emitter 28 | .on('custom', function onCustom (a, b) { 29 | count++ 30 | results.push([a, b]) 31 | }) 32 | .emit('custom', 'foo', 123) 33 | .emit('custom', 'bar') 34 | .emit('custom') 35 | 36 | test.equal(count, 3) 37 | test.deepEqual(results[0], ['foo', 123]) 38 | test.deepEqual(results[1], ['bar', undefined]) 39 | test.deepEqual(results[2], [undefined, undefined]) 40 | done() 41 | }) 42 | test('should listen `.once` custom event `.emit` few times', function (done) { 43 | var emitter = new DualEmitter() 44 | var count = 0 45 | 46 | emitter 47 | .once('custom', function () { 48 | count++ 49 | }) 50 | .emit('custom') 51 | .emit('custom') 52 | .emit('custom') 53 | 54 | test.equal(count, 1) 55 | done() 56 | }) 57 | test('should `.off` event listener after second `.emit`', function (done) { 58 | var emitter = new DualEmitter() 59 | var count = 0 60 | 61 | function handler () { 62 | if (count === 2) { 63 | emitter.off('custom', handler) 64 | return 65 | } 66 | count++ 67 | } 68 | 69 | emitter 70 | .on('custom', handler) 71 | .emit('custom') 72 | .emit('custom') 73 | .emit('custom') 74 | .emit('custom') 75 | 76 | test.equal(count, 2) 77 | done() 78 | }) 79 | test('should `this` at `.on/.once` be DualEmitter when not DOM usage', function (done) { 80 | var emitter = new DualEmitter() 81 | 82 | emitter 83 | .on('custom', function () { 84 | test.equal(typeof this.once, 'function') 85 | done() 86 | }) 87 | .emit('custom') 88 | }) 89 | test('should support multiple `.on` event', function (done) { 90 | var emitter = new DualEmitter() 91 | var count = 0 92 | 93 | function handler () { 94 | count++ 95 | } 96 | 97 | emitter 98 | .on('custom', handler) 99 | .on('custom', handler) 100 | .on('custom', handler) 101 | .emit('custom') 102 | 103 | test.equal(count, 3) 104 | done() 105 | }) 106 | }) 107 | --------------------------------------------------------------------------------