commit 4bbee1160de1453e3377461700ec829dc2578444 Author: Flummi Date: Tue Nov 7 18:22:41 2017 +0100 blah diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..05a66df --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +cfg/ +node_modules/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7e122c --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Modules fick ja \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..19c5d43 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2940 @@ +{ + "name": "keinBotv3", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "optional": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true, + "optional": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "axon": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/axon/-/axon-1.0.0.tgz", + "integrity": "sha1-syN7eLp0kujniZ5tWRjF9uqLz7U=", + "requires": { + "configurable": "0.0.1", + "debug": "2.6.8", + "escape-regexp": "0.0.1" + }, + "dependencies": { + "configurable": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/configurable/-/configurable-0.0.1.tgz", + "integrity": "sha1-R9dbcntRtOuEwdra/j+CQDE4M7E=" + }, + "escape-regexp": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/escape-regexp/-/escape-regexp-0.0.1.tgz", + "integrity": "sha1-9EvaEtRbvfnLf4Yu5+SCez3TIlQ=" + } + } + }, + "babel-cli": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", + "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-polyfill": "6.26.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "chokidar": "1.7.0", + "commander": "2.11.0", + "convert-source-map": "1.5.0", + "fs-readdir-recursive": "1.0.0", + "glob": "7.1.2", + "lodash": "4.17.4", + "output-file-sync": "1.1.2", + "path-is-absolute": "1.0.1", + "slash": "1.0.0", + "source-map": "0.5.7", + "v8flags": "2.1.1" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-core": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", + "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.0", + "debug": "2.6.8", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", + "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-add-module-exports": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz", + "integrity": "sha1-mumh9KjcZ/DN7E9K7aHkOl/2XiU=", + "dev": true + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", + "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "0.10.1" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "core-js": "2.5.1", + "regenerator-runtime": "0.10.5" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + } + } + }, + "babel-preset-es2015": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-regenerator": "6.26.0" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-runtime": "6.26.0", + "core-js": "2.5.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.4" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.8", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "bignumber.js": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.4.tgz", + "integrity": "sha512-LDXpJKVzEx2/OqNbG9mXBNvHuiRL4PzHCGfnANHMJ+fv68Ads3exDVJeGDJws+AoNEuca93bU3q+S0woeUaCdg==" + }, + "binary-extensions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz", + "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=", + "dev": true, + "optional": true + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "optional": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "optional": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "cloudscraper": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cloudscraper/-/cloudscraper-1.4.1.tgz", + "integrity": "sha1-8rRDHzFyhtgZsTVyZso0Y7ES68o=", + "requires": { + "request": "2.81.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "eventemitter2": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.13.tgz", + "integrity": "sha1-Coq5f5wbVjNhuJJ/noBgYndQkVM=" + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "optional": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "optional": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true, + "optional": true + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "optional": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "optional": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "optional": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "forever-monitor": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/forever-monitor/-/forever-monitor-1.7.1.tgz", + "integrity": "sha1-XYIPSjp42y2BriZx8Vi56GoJG7g=", + "requires": { + "broadway": "0.3.6", + "chokidar": "1.7.0", + "minimatch": "3.0.4", + "ps-tree": "0.0.3", + "utile": "0.2.1" + }, + "dependencies": { + "anymatch": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", + "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=", + "requires": { + "arrify": "1.0.1", + "micromatch": "2.3.11" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "binary-extensions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.8.0.tgz", + "integrity": "sha1-SOyNFt9Dd+rl+liEaCSAr02Vx3Q=" + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "broadway": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/broadway/-/broadway-0.3.6.tgz", + "integrity": "sha1-fb7waLlUt5B5Jf1USWO1eKkCuno=", + "requires": { + "cliff": "0.1.9", + "eventemitter2": "0.4.14", + "nconf": "0.6.9", + "utile": "0.2.1", + "winston": "0.8.0" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "requires": { + "anymatch": "1.3.0", + "async-each": "1.0.1", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "cliff": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/cliff/-/cliff-0.1.9.tgz", + "integrity": "sha1-ohHgnGo947oa8n0EnTASUNGIErw=", + "requires": { + "colors": "0.6.2", + "eyes": "0.1.8", + "winston": "0.8.0" + } + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, + "event-stream": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-0.5.3.tgz", + "integrity": "sha1-t3uTCfcQet3+q2PwwOr9jbC9jBw=", + "requires": { + "optimist": "0.2.8" + }, + "dependencies": { + "optimist": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.2.8.tgz", + "integrity": "sha1-6YGrfiaLRXlIWTtVZ0wJmoFcrDE=", + "requires": { + "wordwrap": "0.0.3" + } + } + } + }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "requires": { + "fill-range": "2.2.3" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "1.0.0" + } + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "1.0.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "requires": { + "is-glob": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "i": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.5.tgz", + "integrity": "sha1-HSuFQVjsgWkRPGy39raAHpniEdU=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "1.8.0" + } + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "requires": { + "kind-of": "3.2.2" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.3" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "nconf": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.6.9.tgz", + "integrity": "sha1-lXDvFe1vmuays8jV5xtm0xk81mE=", + "requires": { + "async": "0.2.9", + "ini": "1.3.4", + "optimist": "0.6.0" + }, + "dependencies": { + "async": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.9.tgz", + "integrity": "sha1-32MGD789Myhqdqr21Vophtn/hhk=" + } + } + }, + "ncp": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", + "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=" + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "1.0.2" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.0.tgz", + "integrity": "sha1-aUJIJvNAX3nxQub8PZrljU27kgA=", + "requires": { + "minimist": "0.0.10", + "wordwrap": "0.0.3" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "ps-tree": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-0.0.3.tgz", + "integrity": "sha1-2/jXUqf+Ivp9WGNWiUmWEOknbdw=", + "requires": { + "event-stream": "0.5.3" + } + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.3", + "set-immediate-shim": "1.0.1" + } + }, + "regex-cache": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", + "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", + "requires": { + "is-equal-shallow": "0.1.3", + "is-primitive": "2.0.0" + } + }, + "remove-trailing-separator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", + "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=" + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utile": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/utile/-/utile-0.2.1.tgz", + "integrity": "sha1-kwyI6ZCY1iIINMNWy9mncFItkNc=", + "requires": { + "async": "0.2.10", + "deep-equal": "1.0.1", + "i": "0.3.5", + "mkdirp": "0.5.1", + "ncp": "0.4.2", + "rimraf": "2.6.1" + }, + "dependencies": { + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + } + } + }, + "winston": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-0.8.0.tgz", + "integrity": "sha1-YdCDD6aZcGISIGsKK1ymmpMENmg=", + "requires": { + "async": "0.2.10", + "colors": "0.6.2", + "cycle": "1.0.3", + "eyes": "0.1.8", + "pkginfo": "0.3.1", + "stack-trace": "0.0.10" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs-readdir-recursive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz", + "integrity": "sha1-jNF0XItPiinIyuw5JHaSG6GV9WA=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "optional": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "hashish": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/hashish/-/hashish-0.0.4.tgz", + "integrity": "sha1-bWC8b/r3Ebav1g5CbQd5iAFOZVQ=", + "requires": { + "traverse": "0.6.6" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hh-mm-ss": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hh-mm-ss/-/hh-mm-ss-1.2.0.tgz", + "integrity": "sha512-f4I9Hz1dLpX/3mrEs7yq30+FiuO3tt5NWAqAGeBTaoeoBfB8vhcQ3BphuDc5DjZb/K809agqrAaFlP0jhEU/8w==", + "requires": { + "zero-fill": "2.2.3" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "irc-colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/irc-colors/-/irc-colors-1.4.0.tgz", + "integrity": "sha512-L5JLJsuYDh+deGY/bCes2fBm7ERiYtNHWc/wwmJ64Y0TimyjXthykAJX6Og7khbe4hgz04uUiM2EqXMa1n29zg==" + }, + "irc-message": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/irc-message/-/irc-message-2.0.1.tgz", + "integrity": "sha1-3AJ1lTmgMMlq82rW/I/ukIPffLw=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "1.10.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true, + "optional": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "optional": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "optional": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true, + "optional": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true, + "optional": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "optional": true, + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsprim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + }, + "lodash": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz", + "integrity": "sha1-W3cjA03aTSYuWkb7LFjXzCL3FCA=" + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + } + }, + "mime-db": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + }, + "mime-types": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mysql": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.15.0.tgz", + "integrity": "sha512-C7tjzWtbN5nzkLIV+E8Crnl9bFyc7d3XJcBAvHKEVkjrYjogz3llo22q6s/hw+UcsE4/844pDob9ac+3dVjQSA==", + "requires": { + "bignumber.js": "4.0.4", + "readable-stream": "2.3.3", + "safe-buffer": "5.1.1", + "sqlstring": "2.3.0" + } + }, + "nodejs-mysql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/nodejs-mysql/-/nodejs-mysql-0.1.3.tgz", + "integrity": "sha1-AuncQmi1HT7AvFlDX19JLPkI/Ek=", + "requires": { + "bluebird": "3.5.1", + "mysql": "2.15.0" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "optional": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "output-file-sync": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", + "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1", + "object-assign": "4.1.1" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "optional": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "pause-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/pause-queue/-/pause-queue-0.1.0.tgz", + "integrity": "sha1-iS6rq3jCaoPW71ZQ6Wz3zSNnDKo=" + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true, + "optional": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "dev": true, + "optional": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.3", + "set-immediate-shim": "1.0.1" + } + }, + "regenerate": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", + "dev": true + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.8" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "optional": true, + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "1.3.3", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "optional": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "safe-eval": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/safe-eval/-/safe-eval-0.3.0.tgz", + "integrity": "sha1-Bs4RHuvZwYWrr/AI7A/P/Fxb4Aw=" + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true, + "optional": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "requires": { + "hoek": "2.16.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "sqlstring": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.0.tgz", + "integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg=" + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "streamify": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/streamify/-/streamify-0.2.9.tgz", + "integrity": "sha512-8pUxeLEef9UO1FxtTt5iikAiyzGI4SZRnGuJ3sz8axZ5Xk+/7ezEV5kuJQsMEFxw7AKYw3xp0Ow+20mmSaJbQQ==", + "requires": { + "hashish": "0.0.4" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "requires": { + "punycode": "1.4.1" + } + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + }, + "v8flags": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", + "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "dev": true, + "requires": { + "user-home": "1.1.1" + } + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "requires": { + "extsprintf": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "youtube-dl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/youtube-dl/-/youtube-dl-1.12.2.tgz", + "integrity": "sha512-TDGmUxzEsQCp1Ux3IEkEhJ2LfRlUjBo5AaaGmW5Hqm8uX8jd2sB+Rq37S9vy505qnFhpy05uUSQsBtpvBuQBYA==", + "requires": { + "hh-mm-ss": "1.2.0", + "mkdirp": "0.5.1", + "request": "2.83.0", + "streamify": "0.2.9" + }, + "dependencies": { + "ajv": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", + "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.0" + } + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "5.3.0", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.0", + "sshpk": "1.13.1" + } + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "requires": { + "hoek": "4.2.0" + } + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "1.4.1" + } + } + } + }, + "zero-fill": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/zero-fill/-/zero-fill-2.2.3.tgz", + "integrity": "sha1-o97wa6XjmuZEhQu0yirUEStIVek=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..442043b --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "keinBotv3", + "version": "0.0.1", + "description": "Bot, kennste?", + "main": "index.js", + "scripts": { + "build": "./node_modules/.bin/babel src --presets=es2015 --plugins=add-module-exports --out-dir dist", + "start": "npm run build && node dist/index.js" + }, + "author": "Flummi & jkhsjdhjs", + "license": "WTFPL", + "dependencies": { + "axon": "1.0.0", + "cloudscraper": "^1.4.1", + "eventemitter2": "0.4.13", + "forever-monitor": "^1.7.1", + "irc-colors": "^1.4.0", + "irc-message": "2.0.1", + "irc-socket": "github:ircanywhere/irc-socket", + "json-stringify-safe": "^5.0.0", + "lodash": "2.4.1", + "nodejs-mysql": "^0.1.3", + "pause-queue": "~0.1.0", + "safe-eval": "^0.3.0", + "youtube-dl": "^1.12.2" + }, + "devDependencies": { + "babel-cli": "^6.26.0", + "babel-core": "^6.26.0", + "babel-plugin-add-module-exports": "^0.2.1", + "babel-preset-es2015": "^6.24.1" + } +} diff --git a/src/bot.js b/src/bot.js new file mode 100644 index 0000000..2034273 --- /dev/null +++ b/src/bot.js @@ -0,0 +1,25 @@ +import { cfg, read } from './inc/cfg.js'; + + +read().then(() => { + console.log( cfg ); +}); + + +/*var config = new (require(__dirname+'/inc/cfg'))(); +config.read() + .then( + data => { + config.cfg = data; + var lib = new (require(__dirname+'/inc/lib'))(config.cfg); + lib.events.on('message', function(msg) { + if( msg.event[1] === 'privmsg' ) { + var e = lib.reply(msg); + console.log( `(${e.time}) ${e.network} -> ${e.channel} -> ${e.user.nick}: ${e.message}` ); + } + }); + }, + err => { + console.log( "error! " + err ); + } + )*/ \ No newline at end of file diff --git a/src/inc/cfg.js b/src/inc/cfg.js new file mode 100644 index 0000000..8344d1e --- /dev/null +++ b/src/inc/cfg.js @@ -0,0 +1,38 @@ +import sql from './sql.js'; + +let cfg = { + irc: {}, + main: {}, + websrv: {}, + trigger: {} +}; + +const read = () => new Promise((resolve, reject) => { + sql.exec("select * from `cfg`", (err, rows) => { + if(err || rows.length < 1) + reject({ error: "no cfg" }); + else { + for(let row in rows) { + cfg[rows[row].class ][ rows[row].key] = ((type, value) => { + switch(type) { + case 'string': + return value; + break; + case 'int': + return parseInt(value); + break; + case 'bool': + return (value === 'true')?true:false; + break; + case 'json': + return JSON.parse(value); + break; + } + })(rows[row].type, rows[row].value); + } + resolve(); + } + }); +}); + +export { cfg, read }; \ No newline at end of file diff --git a/src/inc/events.js b/src/inc/events.js new file mode 100644 index 0000000..e69de29 diff --git a/src/inc/events/message.js b/src/inc/events/message.js new file mode 100644 index 0000000..b43e8a4 --- /dev/null +++ b/src/inc/events/message.js @@ -0,0 +1,94 @@ +const safeEval = require('safe-eval'); +const util = require('util'); +const fs = require('fs'); +const ytdl = util.promisify(require('youtube-dl').getInfo); +require('irc-colors').global(); + +module.exports = (lib) => { + lib.events.on('message', function(msg) { + if( msg.event[1] === 'privmsg' ) { // Triggerauswertung und blah + //lib.rpc.emit('call', 'rizon', 'privmsg', [ '#f0ck', JSON.stringify(msg) ]); + var e = lib.reply(msg); + switch(e.message) { + case "1": + e.reply("normal"); + break; + case "2": + e.replyAction("action"); + break; + case "3": + e.replyNotice("notice"); + break; + case "4": + e.reply("Debugzeugs (lib.interfaces.rpc.sock) in die Konsole pfostiert."); + console.log(lib.interfaces.rpc.sock); + break; + case "6": + e.reply("\x02!kick kbotv3\x02"); + break; + case "5": + e.reply("!kick kbotv3"); + break; + case "whois": + lib.rpc.emit('call', e.network, 'raw', [ 'whois', e.user.nick ]); + e.reply(`whois an ${e.user.nick} ist raus!`); + break; + default: + if(e.user.nick === "Flummi" || e.user.nick === "jkhsjdhjs" || e.user.nick === "pFT" || e.user.nick === "mrhanky" || e.user.nick === "gz") { + if(e.message.match(/^\.js /)) { // JS-Sandbox + let args = e.message.substring(3); + var context = { + e: e, + msg: msg, + setInterval: setInterval, + clearInterval: clearInterval + } + try { + var output = safeEval(args, context); + if(typeof output !== undefined && output !== 'undefined' && output) { + let blah = JSON.stringify( output ); + if(blah != "Converting circular structure to JSON") + e.reply( blah.length > 250 ? `holy fuck, Ausgabe wäre viel zu lang! (${blah.length} Zeichen :DDDDDD)` : blah ); + } + } + catch(err) { + e.reply(err.message); + } + } + else if(e.message.match(/https?:\/\/[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?/gi)) { // parser + let links = e.message.match(/https?:\/\/[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?/gi); + const args = [ + //"-j", + //"-q", + "--no-progress", + "--no-warnings", + "--no-check-certificate", + "--max-filesize 500m", + '-o "./tmp/%(title)s.%(ext)s"' + ]; + + Promise.all( links.map( link => checkRepost( link ) ) ) // repostcheck + .then( res => Promise.all( res.map( link => ytdl(link) ) ) ) // get informations + .then( res => { + res.forEach( data => { + e.reply( data.title ); + }); + }); + } + + } + break; + } + } + + if( msg.event === 'metadata' ) + console.log(msg); + }); +}; + + +function checkRepost(link) { + return new Promise((resolve, reject) => { + resolve( link ); + }); +} \ No newline at end of file diff --git a/src/inc/events/sync.js b/src/inc/events/sync.js new file mode 100644 index 0000000..5befc02 --- /dev/null +++ b/src/inc/events/sync.js @@ -0,0 +1,9 @@ +module.exports = (lib) => { + lib.events.on('message', function(msg) { + if( msg.event == 'synchronize' ) { + if( msg.keys.length == 0 ) + setTimeout(lib.loadIRC, 500); + return; + } + }); +}; \ No newline at end of file diff --git a/src/inc/events/whois.js b/src/inc/events/whois.js new file mode 100644 index 0000000..c5d4849 --- /dev/null +++ b/src/inc/events/whois.js @@ -0,0 +1,11 @@ +module.exports = (lib) => { + lib.events.on('message', function(msg) { + if( msg.event[1] === 'whois' || (msg.event[1] === 'unknown' && msg.message.command === 'RPL_WHOISNICKSERVREG') ) { + console.log(msg); + } + + if( msg.event[1] === 'who' ) { + console.log(msg.message.who); + } + }); +}; \ No newline at end of file diff --git a/src/inc/irc/api.js b/src/inc/irc/api.js new file mode 100644 index 0000000..b5dd86a --- /dev/null +++ b/src/inc/irc/api.js @@ -0,0 +1,243 @@ +var child_process, + axon = require('axon'), + _ = require('lodash'), + QueuePool = require(__dirname + '/queuepool').QueuePool, + irc = require(__dirname + '/irc'), + readWriteStream = require(__dirname + '/stub.js').ReadWriteNetStream, + stringify = require('json-stringify-safe'), + Events = irc.Events, + Client = irc.Client, + Clients = {}; + +function Api() { + var self = this; + + this._keepOpen = false; + this._eventQueue = []; + this._rpcClients = 0; + // some internal settings + + process.on('uncaughtException', function(err) { + self.emit('uncaughtException', {message: stringify(err)}); + process.exit(0); + }); +}; + +Api.prototype.getClient = function(key) { + return Clients[key].irc.supported; +} + +Api.prototype.setupServer = function(options) { + var self = this; + + axon.codec.define('json', { + encode: JSON.stringify, + decode: JSON.parse + }); + // setup a json codec + + this._events = axon.socket('push'); + this._events.bind(options.events); + this._events.format('json'); + // setup the events socket + + this._events.on('connect', function() { + self.emit('metadata', {pid: process.pid, incomingPort: options.rpc, outgoingPort: options.events}); + self.emit('synchronize', {keys: _.keys(Clients)}); + }); + // setup some events for our outbound port + + this._rpc = axon.socket('sub-emitter'); + this._rpc.bind(options.rpc); + // we also setup an inbound socket which uses the sub emitter + + this._rpc.on('createClient', function(key, client, dummy) { + self.unhookEvent(key, '*'); + // do this first + + var user = self.createClient(key, client, dummy || false); + // create the client + + if (!user) { + return false; + } + // bail + + self.hookEvent(key, '*', function(object) { + self.emit(this.event, {message: object}); + }); + // we're obviously using the rpc to create clients, so they don't + // have an option to hook events, they just get the lot, and choose what they + // wanna do with them on their incoming pipe + }); + + //this._rpc.on('test', function(key, client, dummy) + + this._rpc.on('destroyClient', function(key) { + self.destroyClient(key); + // delete client + }); + + this._rpc.on('call', function(key, call, params) { + if (!_.has(Clients, key)) { + return false; + } + + var client = Clients[key]; + // get the client object + + if (!_.has(Client.prototype, call)) { + return false; + } + // property is undefined + + if (_.isArray(params) && call !== 'raw') { + Client.prototype[call].apply(client.irc, params); + } else { + Client.prototype[call].call(client.irc, params); + } + // call the function + }); +}; + +Api.prototype.connect = function(options) { + var self = this, + interfaces = { + events: axon.socket('pull'), + rpc: axon.socket('pub-emitter') + }; + // create these so our end-user doesn't have to + + axon.codec.define('json', { + encode: JSON.stringify, + decode: JSON.parse + }); + // setup a json codec + + interfaces.rpc.connect(options.rpc); + // setup our outgoing connection + + interfaces.events.connect(options.events); + interfaces.events.format('json'); + // setup our incoming connection + + if (!options.automaticSetup) { + return interfaces; + } + // just return interfaces if handleErrors is false + + interfaces.events.on('socket error', function(e) { + if (e.syscall === 'connect' && e.code === 'ECONNREFUSED') { + self.setupServer(options); + } + }); + // socket error + + return interfaces; +} + +Api.prototype.emit = function(event, data) { + if (this._events) { + this._events.send(_.extend({event: event}, data)); + } else { + Events.emit(event, data); + } +} +// ======================================== + +// ======================================== +// the following functions let us manage clients by creating +// them, and destroying them + +Api.prototype.createClient = function(key, object, dummy) { + var self = this, + dummy = dummy || false, + socket = (dummy) ? readWriteStream : undefined; + // we can create a dummy client with stub.js for testing purposes + + if (_.has(Clients, key)) { + return false; + } + // check if a client with this key exists, don't bother throwing, too risky to be + // exiting the process over this sort of stuff. + + Clients[key] = { + key: key, + options: object, + dummy: dummy, + irc: new Client(key, object, socket), + events: {} + }; + + this.hookEvent(key, 'failed', function(message) { + setTimeout(function() { + self.destroyClient(key); + }, 1000); + }); + // hook onto a failed event and destroy the client + + this.hookEvent(key, 'throttled', function(message) { + QueuePool.queuePause(object.server); + }); + // hook onto a throttling event + + return Clients[key]; +}; + +Api.prototype.destroyClient = function(key) { + if (!_.has(Clients, key)) { + return false; + } + // no client exists, lets bail + + Clients[key].irc.disconnect(); + // send a disconnect to be nice + + delete Clients[key].irc; + delete Clients[key]; + + return true; +}; +// ======================================== + +// ======================================== +// the following functions handle hooking onto events +// and unhooking them + +Api.prototype.hookEvent = function(key, e, callback, once) { + var once = once || false; + // check for once at the end, if so only apply event once + + if (once) { + Events.once([key, e], callback); + } else { + Events.off([key, e], callback); + Events.on([key, e], callback); + } + // add the hook +}; + +Api.prototype.unhookEvent = function(key, e, callback) { + if (!callback) { + Events.removeAllListeners([key, e]); + } else { + Events.off([key, e], callback); + } + // add the hook +}; +// ======================================== + +Error.prototype.toJSON = function () { + var json = {}; + Object.getOwnPropertyNames(this).forEach(addToJSON, this); + return json; + + function addToJSON(name) { + var pd = Object.getOwnPropertyDescriptor(this, name); + pd.enumerable = true; + Object.defineProperty(json, name, pd); + } +} + +exports.Api = Api; +exports.axon = axon; \ No newline at end of file diff --git a/src/inc/irc/codes.js b/src/inc/irc/codes.js new file mode 100644 index 0000000..57ba1c8 --- /dev/null +++ b/src/inc/irc/codes.js @@ -0,0 +1,330 @@ +module.exports = { + '001': 'RPL_WELCOME', + '002': 'RPL_YOURHOST', // RFC2812 + '003': 'RPL_CREATED', // RFC2812 + '004': 'RPL_MYINFO', // RFC2812 + '005': 'RPL_ISUPPORT', // draft-brocklesby-irc-isupport-03 + '008': 'RPL_SNOMASK', // ircu + '009': 'RPL_STATMEMTOT', // ircu + '010': 'RPL_REDIR', // ratbox + '014': 'RPL_YOURCOOKIE', // IRCnet + '015': 'RPL_MAP', // ircu + '016': 'RPL_MAPMORE', // ircu + '017': 'RPL_MAPEND', // ircu + '020': 'RPL_CONNECTING', // IRCnet + '042': 'RPL_YOURID', // IRCnet + '043': 'RPL_SAVENICK', // IRCnet + '050': 'RPL_ATTEMPTINGJUNC', // aircd + '051': 'RPL_ATTEMPTINGREROUTE', // aircd + + '200': 'RPL_TRACELINK', // RFC1459 + '201': 'RPL_TRACECONNECTING', // RFC1459 + '202': 'RPL_TRACEHANDSHAKE', // RFC1459 + '203': 'RPL_TRACEUNKNOWN', // RFC1459 + '204': 'RPL_TRACEOPERATOR', // RFC1459 + '205': 'RPL_TRACEUSER', // RFC1459 + '206': 'RPL_TRACESERVER', // RFC1459 + '207': 'RPL_TRACECAPTURED', // hybrid (RFC2812 TRACESERVICE) + '208': 'RPL_TRACENEWTYPE', // RFC1459 + '209': 'RPL_TRACECLASS', // RFC2812 + '210': 'RPL_STATS', // aircd (single stats reply) + '211': 'RPL_STATSLINKINFO', // RFC1459 + '212': 'RPL_STATSCOMMANDS', // RFC1459 + '213': 'RPL_STATSCLINE', // RFC1459 + '214': 'RPL_STATSNLINE', // RFC1459 + '215': 'RPL_STATSILINE', // RFC1459 + '216': 'RPL_STATSKLINE', // RFC1459 + '217': 'RPL_STATSQLINE', // RFC1459 + '218': 'RPL_STATSYLINE', // RFC1459 + '219': 'RPL_ENDOFSTATS', // RFC1459 + + '220': 'RPL_STATSPLINE', // hybrid + '221': 'RPL_UMODEIS', // RFC1459 + '222': 'RPL_SQLINE_NICK', // DALnet + '223': 'RPL_STATSGLINE', // Unreal + '224': 'RPL_STATSFLINE', // hybrid + '225': 'RPL_STATSDLINE', // hybrid + '226': 'RPL_STATSALINE', // hybrid + '227': 'RPL_STATSVLINE', // Unreal + '228': 'RPL_STATSCCOUNT', // hybrid + + '231': 'RPL_SERVICEINFO', // RFC1459 + '233': 'RPL_SERVICE', // RFC1459 + '234': 'RPL_SERVLIST', // RFC1459 + '235': 'RPL_SERVLISTEND', // RFC1459 + '239': 'RPL_STATSIAUTH', // IRCnet + + '241': 'RPL_STATSLLINE', // RFC1459 + '242': 'RPL_STATSUPTIME', // RFC1459 + '243': 'RPL_STATSOLINE', // RFC1459 + '244': 'RPL_STATSHLINE', // RFC1459 + '245': 'RPL_STATSSLINE', // Bahamut, IRCnet, hybrid + '247': 'RPL_STATSXLINE', // hybrid + '248': 'RPL_STATSULINE', // hybrid + '249': 'RPL_STATSDEBUG', // hybrid + + '250': 'RPL_STATSCONN', // ircu, Unreal, hybrid + '251': 'RPL_LUSERCLIENT', // RFC1459 + '252': 'RPL_LUSEROP', // RFC1459 + '253': 'RPL_LUSERUNKNOWN', // RFC1459 + '254': 'RPL_LUSERCHANNELS', // RFC1459 + '255': 'RPL_LUSERME', // RFC1459 + '256': 'RPL_ADMINME', // RFC1459 + '257': 'RPL_ADMINLOC1', // RFC1459 + '258': 'RPL_ADMINLOC2', // RFC1459 + '259': 'RPL_ADMINEMAIL', // RFC1459 + + '261': 'RPL_TRACELOG', // RFC1459 + '262': 'RPL_ENDOFTRACE', // hybrid + '263': 'RPL_LOAD2HI', // hybrid + '265': 'RPL_LOCALUSERS', // aircd, Bahamut, hybrid + '266': 'RPL_GLOBALUSERS', // aircd, Bahamut, hybrid + '267': 'RPL_START_NETSTAT', // aircd + '268': 'RPL_NETSTAT', // aircd + '269': 'RPL_END_NETSTAT', // aircd + + '270': 'RPL_PRIVS', // ircu + '271': 'RPL_SILELIST', // ircu + '272': 'RPL_ENDOFSILELIST', // ircu + '275': 'RPL_WHOISSSL', // oftc-hybrid + '276': 'RPL_WHOISCERTFP', // oftc-hybrid + + '280': 'RPL_GLIST', // ircu + '281': 'RPL_ACCEPTLIST', // ratbox/chary + '282': 'RPL_ENDOFACCEPT', // ratbox/chary + + '300': 'RPL_NONE', // RFC1459 + '301': 'RPL_AWAY', // RFC1459 + '302': 'RPL_USERHOST', // RFC1459 + '303': 'RPL_ISON', // RFC1459 + '304': 'RPL_TEXT', // hybrid + '305': 'RPL_UNAWAY', // RFC1459 + '306': 'RPL_NOWAWAY', // RFC1459 + '307': 'RPL_WHOISNICKSERVREG', // An issue of contention. + '308': 'RPL_WHOISADMIN', // hybrid + + '310': 'RPL_WHOISMODES', // Plexus + '311': 'RPL_WHOISUSER', // RFC1459 + '312': 'RPL_WHOISSERVER', // RFC1459 + '313': 'RPL_WHOISOPERATOR', // RFC1459 + '314': 'RPL_WHOWASUSER', // RFC1459 + '315': 'RPL_ENDOFWHO', // RFC1459 + '316': 'RPL_WHOISCHANOP', // reserved in rb/chary + '317': 'RPL_WHOISIDLE', // RFC1459 + '318': 'RPL_ENDOFWHOIS', // RFC1459 + '319': 'RPL_WHOISCHANNELS', // RFC1459 + + '321': 'RPL_LISTSTART', // RFC1459 + '322': 'RPL_LIST', // RFC1459 + '323': 'RPL_LISTEND', // RFC1459 + '324': 'RPL_CHANNELMODEIS', // RFC1459 + '325': 'RPL_CHANNELMLOCK', // sorircd 1.3 + '328': 'RPL_CHANNELURL', // ratbox/chary + '329': 'RPL_CREATIONTIME', // Bahamut + + '330': 'RPL_WHOISLOGGEDIN', // ratbox/chary + '331': 'RPL_NOTOPIC', // RFC1459 + '332': 'RPL_TOPIC', // RFC1459 + '333': 'RPL_TOPICWHOTIME', // ircu + '337': 'RPL_WHOISTEXT', // ratbox/chary + '338': 'RPL_WHOISACTUALLY', // Bahamut, ircu + + '340': 'RPL_USERIP', // ircu + '341': 'RPL_INVITING', // RFC1459 + '342': 'RPL_SUMMONING', // RFC1459 + '345': 'RPL_INVITED', // GameSurge + '346': 'RPL_INVITELIST', // RFC2812 + '347': 'RPL_ENDOFINVITELIST', // RFC2812 + '348': 'RPL_EXCEPTLIST', // RFC2812 + '349': 'RPL_ENDOFEXCEPTLIST', // RFC2812 + + '351': 'RPL_VERSION', // RFC1459 + '352': 'RPL_WHOREPLY', // RFC1459 + '353': 'RPL_NAMREPLY', // RFC1459 + '354': 'RPL_WHOSPCRPL', // ircu + + '360': 'RPL_WHOWASREAL', // ratbox/chary + '361': 'RPL_KILLDONE', // RFC1459 + '362': 'RPL_CLOSING', // RFC1459 + '363': 'RPL_CLOSEEND', // RFC1459 + '364': 'RPL_LINKS', // RFC1459 + '365': 'RPL_ENDOFLINKS', // RFC1459 + '366': 'RPL_ENDOFNAMES', // RFC1459 + '367': 'RPL_BANLIST', // RFC1459 + '368': 'RPL_ENDOFBANLIST', // RFC1459 + '369': 'RPL_ENDOFWHOWAS', // RFC1459 + + '371': 'RPL_INFO', // RFC1459 + '372': 'RPL_MOTD', // RFC1459 + '373': 'RPL_INFOSTART', // RFC1459 + '374': 'RPL_ENDOFINFO', // RFC1459 + '375': 'RPL_MOTDSTART', // RFC1459 + '376': 'RPL_ENDOFMOTD', // RFC1459 + '378': 'RPL_WHOISHOST', // charybdis + + '381': 'RPL_YOUREOPER', // RFC1459 + '382': 'RPL_REHASHING', // RFC1459 + '383': 'RPL_YOURESERVICE', // RFC2812 + '384': 'RPL_MYPORTIS', // RFC1459 + '385': 'RPL_NOTOPERANYMORE', // AustHex, hybrid, Unreal + '386': 'RPL_RSACHALLENGE', // ratbox + + '391': 'RPL_TIME', // RFC1459 + '392': 'RPL_USERSSTART', // RFC1459 + '393': 'RPL_USERS', // RFC1459 + '394': 'RPL_ENDOFUSERS', // RFC1459 + '395': 'RPL_NOUSERS', // RFC1459 + '396': 'RPL_HOSTHIDDEN', // ircu + + '401': 'ERR_NOSUCHNICK', // RFC1459 + '402': 'ERR_NOSUCHSERVER', // RFC1459 + '403': 'ERR_NOSUCHCHANNEL', // RFC1459 + '404': 'ERR_CANNOTSENDTOCHAN', // RFC1459 + '405': 'ERR_TOOMANYCHANNELS', // RFC1459 + '406': 'ERR_WASNOSUCHNICK', // RFC1459 + '407': 'ERR_TOOMANYTARGETS', // RFC1459 + '408': 'ERR_NOSUCHSERVICE', // RFC2812 + '409': 'ERR_NOORIGIN', // RFC1459 + + '410': 'ERR_INVALIDCAPCMD', // hybrid + '411': 'ERR_NORECIPIENT', // RFC1459 + '412': 'ERR_NOTEXTTOSEND', // RFC1459 + '413': 'ERR_NOTOPLEVEL', // RFC1459 + '414': 'ERR_WILDTOPLEVEL', // RFC1459 + '415': 'ERR_BADMASK', // RFC2812 + '416': 'ERR_TOOMANYMATCHES', // ratbox + + '421': 'ERR_UNKNOWNCOMMAND', // RFC1459 + '422': 'ERR_NOMOTD', // RFC1459 + '423': 'ERR_NOADMININFO', // RFC1459 + '424': 'ERR_FILEERROR', // RFC1459 + '425': 'ERR_NOOPERMOTD', // Unreal + '429': 'ERR_TOOMANYAWAY', // Bahamut + + '430': 'ERR_EVENTNICKCHANGE', // AustHex + '431': 'ERR_NONICKNAMEGIVEN', // RFC1459 + '432': 'ERR_ERRONEUSNICKNAME', // RFC1459 + '433': 'ERR_NICKNAMEINUSE', // RFC1459 + '436': 'ERR_NICKCOLLISION', // RFC1459 + '437': 'ERR_UNAVAILRESOURCE', // hybrid + '438': 'ERR_NICKTOOFAST', // hybrid + '439': 'ERR_TARGETTOOFAST', // ircu + + '440': 'ERR_SERVICESDOWN', // Bahamut, Unreal + '441': 'ERR_USERNOTINCHANNEL', // RFC1459 + '442': 'ERR_NOTONCHANNEL', // RFC1459 + '443': 'ERR_USERONCHANNEL', // RFC1459 + '444': 'ERR_NOLOGIN', // RFC1459 + '445': 'ERR_SUMMONDISABLED', // RFC1459 + '446': 'ERR_USERSDISABLED', // RFC1459 + '447': 'ERR_NONICKCHANGE', // Unreal + '449': 'ERR_NOTIMPLEMENTED', // ircu + + '451': 'ERR_NOTREGISTERED', // RFC1459 + '455': 'ERR_HOSTILENAME', // Unreal + '456': 'ERR_ACCEPTFULL', // hybrid + '457': 'ERR_ACCEPTEXIST', // hybrid + '458': 'ERR_ACCEPTNOT', // hybrid + '459': 'ERR_NOHIDING', // Unreal + + '460': 'ERR_NOTFORHALFOPS', // Unreal + '461': 'ERR_NEEDMOREPARAMS', // RFC1459 + '462': 'ERR_ALREADYREGISTRED', // RFC1459 + '463': 'ERR_NOPERMFORHOST', // RFC1459 + '464': 'ERR_PASSWDMISMATCH', // RFC1459 + '465': 'ERR_YOUREBANNEDCREEP', // RFC1459 + '466': 'ERR_YOUWILLBEBANNED', // RFC1459 + '467': 'ERR_KEYSET', // RFC1459 + '469': 'ERR_LINKSET', // Unreal + + '470': 'ERR_LINKCHANNEL', // charybdis + '471': 'ERR_CHANNELISFULL', // RFC1459 + '472': 'ERR_UNKNOWNMODE', // RFC1459 + '473': 'ERR_INVITEONLYCHAN', // RFC1459 + '474': 'ERR_BANNEDFROMCHAN', // RFC1459 + '475': 'ERR_BADCHANNELKEY', // RFC1459 + '476': 'ERR_BADCHANMASK', // RFC2812 + '477': 'ERR_NEEDREGGEDNICK', // ratbox (REGONLYCHAN in hyb7) + '478': 'ERR_BANLISTFULL', // ircu + '479': 'ERR_BADCHANNAME', // hybrid + + '480': 'ERR_SSLONLYCHAN', // ratbox + '481': 'ERR_NOPRIVILEGES', // RFC1459 + '482': 'ERR_CHANOPRIVSNEEDED', // RFC1459 + '483': 'ERR_CANTKILLSERVER', // RFC1459 + '484': 'ERR_ISCHANSERVICE', // ratbox (ERR_RESTRICTED in hyb7) + '485': 'ERR_BANNEDNICK', // ratbox + '488': 'ERR_TSLESSCHAN', // IRCnet + '489': 'ERR_VOICENEEDED', // ircu + + '491': 'ERR_NOOPERHOST', // RFC1459 + '492': 'ERR_NOSERVICEHOST', // RFC1459 + '493': 'ERR_NOFEATURE', // ircu + '494': 'ERR_OWNMODE', // Bahamut + '495': 'ERR_BADLOGTYPE', // ircu + '496': 'ERR_BADLOGSYS', // ircu + '497': 'ERR_BADLOGVALUE', // ircu + '498': 'ERR_ISOPERLCHAN', // ircu + + '501': 'ERR_UMODEUNKNOWNFLAG', // RFC1459 + '502': 'ERR_USERSDONTMATCH', // RFC1459 + '503': 'ERR_GHOSTEDCLIENT', // hybrid + '504': 'ERR_USERNOTONSERV', // hybrid + + '513': 'ERR_WRONGPONG', // hybrid + '517': 'ERR_DISABLED', // ircu + '518': 'ERR_LONGMASK', // ircu + + '521': 'ERR_LISTSYNTAX', // hybrid + '522': 'ERR_WHOSYNTAX', // hybrid + '523': 'ERR_WHOLIMITEXCEEDED', // hybrid + '524': 'ERR_HELPNOTFOUND', // hybrid + + '670': 'RPL_STARTTLS', // ircv3 tls-3.1 + '671': 'RPL_WHOISSECURE', // Unreal + + '691': 'ERR_STARTTLS', // ircv3 tls-3.2 + + '702': 'RPL_MODLIST', // hybrid + '703': 'RPL_ENDOFMODLIST', // hybrid + '704': 'RPL_HELPSTART', // hybrid + '705': 'RPL_HELPTXT', // hybrid + '706': 'RPL_ENDOFHELP', // hybrid + '707': 'ERR_TARGCHANGE', // ratbox + + '710': 'RPL_KNOCK', // hybrid + '711': 'RPL_KNOCKDLVR', // hybrid + '712': 'ERR_TOOMANYKNOCK', // hybrid + '713': 'ERR_CHANOPEN', // hybrid + '714': 'ERR_KNOCKONCHAN', // hybrid + '715': 'ERR_KNOCKDISABLED', // hybrid + '716': 'RPL_TARGUMODEG', // hybrid + '717': 'RPL_TARGNOTIFY', // hybrid + '718': 'RPL_UMODEGMSG', // hybrid + + '720': 'RPL_OMOTDSTART', // hybrid + '721': 'RPL_OMOTD', // hybrid + '722': 'RPL_ENDOFOMOTD', // hybrid + '723': 'ERR_NOPRIVS', // hybrid + '724': 'RPL_TESTMASK', // hybrid + '725': 'RPL_TESTLINE', // hybrid + '726': 'RPL_NOTESTLINE', // hybrid + '727': 'RPL_TESTMASKGECOS', // ratbox + '728': 'RPL_QUIETLIST', // charybdis + '729': 'RPL_ENDOFQUIETLIST', // charybdis + + '730': 'RPL_MONONLINE', // ircv3 monitor ext + '731': 'RPL_MONOFFLINE', // ircv3 monitor ext + '732': 'RPL_MONLIST', // ircv3 monitor ext + '733': 'RPL_ENDOFMONLIST', // ircv3 monitor ext + '734': 'ERR_MONLISTFULL', // ircv3 monitor ext + + '740': 'RPL_RSACHALLENGE2', // ratbox + '741': 'RPL_ENDOFRSACHALLENGE2', // ratbox + + '900': 'RPL_SASLAUTHENTICATED', // charbydis / kiwiirc + '903': 'RPL_SASLLOGGEDIN', // charbydis / kiwiirc + '904': 'ERR_SASLNOTAUTHORISED', // charbydis / kiwiirc + '906': 'ERR_SASLABORTED', // charbydis / kiwiirc + '907': 'ERR_SASLALREADYAUTHED' // charbydis / kiwiirc +}; \ No newline at end of file diff --git a/src/inc/irc/irc.js b/src/inc/irc/irc.js new file mode 100644 index 0000000..79d8909 --- /dev/null +++ b/src/inc/irc/irc.js @@ -0,0 +1,1570 @@ +var IrcSocket = require('irc-socket'), + IrcMessage = require('irc-message').parseMessage, + EventEmitter2 = require('eventemitter2').EventEmitter2, + codes = require(__dirname + '/codes'), + QueuePool = require(__dirname + '/queuepool').QueuePool, + ListCache = require(__dirname + '/listcache').ListCache, + _ = require('lodash'); +// include all our required libraries + +var Events = new EventEmitter2({ + wildcard: true, + newListener: false, + maxListeners: 0 +}); +// we create an event emitter here, but only one, and use it for every irc client we initiate +// that way we don't have 2 event emitters for each client and use an insane amount of memory +// when we scale up to hundreds of clients, we use namespaces for individual clients + +// ======================================== +// These functions don't need to be in the Client namespace anymore +// it's just wasting memory when we have a lot of clients, they can be +// in a helper. + +var Helper = { + // Features supported by the server + // (initial values are RFC 1459 defaults. Zeros signify no default or unlimited value) + defaultSupported: function() { + return { + network: { + name: '', + hostname: '', + ircd: '', + nicklength: 9, + maxtargets: {} + }, + channel: { + idlength: {}, + limit: {}, + length: 200, + modes: 0, + types: '#&', + kicklength: 0, + topiclength: 0 + }, + modes: { + user: '', + channel: '', + param: '', + types: { + a: '', + b: '', + c: '', + d: '' + }, + prefixes: '~&@%+', + prefixmodes: { + q: '~', + a: '&', + o: '@', + h: '%', + v: '+' + }, + maxlist: {} + }, + raw: [] + }; + }, + + parse: function(line) { + var message = IrcMessage(line); + + if (message === null) { + return false; + } + + if (message.prefixIsHostmask()) { + var hostmask = message.parseHostmaskFromPrefix(); + message.nickname = hostmask.nickname; + message.username = hostmask.username; + message.hostname = hostmask.hostname; + } else { + message.server = message.prefix; + } + + if (codes[message.command]) { + message.command = codes[message.command]; + } + + message.raw = line; + // apply the raw line aswell + + return message; + }, + + time: function(enabled, message) { + if (!message || !message.tags || message.tags.length === 0) { + return new Date(); + } + // no time, return a normal date object from now + + var enabled = _.intersection(['server-time', 'znc.in/server-time', 'znc.in/server-time-iso']); + + if (enabled.length > 0) { + var time = message.tags.time || null; + // we have a time capability enabled, lets try find the tag + + if (time === null) { + return new Date(); + // tags.time doesn't exist, strange, never mind just return a new date object + } else if (typeof time === 'string') { + if (time.indexOf('T') > -1) { + return new Date(time); + } else { + return new Date(int(time) * 1000); + } + } else if (typeof time === 'number') { + return new Date(time * 1000); + } + // lets do some checks to see what format it is + } + + return new Date(); + // we've got this far so we have a time, let's check if we have any time capabilities enabled + }, + + col: function(finalstr) { + if (finalstr.indexOf('^') === -1) { + return finalstr; + } + + var colourcodes = finalstr.match(/\\*\^[0-9]{1}[0-5]?,[0-9]{1}[0-5]?|\^((20|1([0-9]?)|[0-9])|[0-9])/g); + // if message contains a colour trigger + + for (var i in colourcodes) { + if (colourcodes[i][0] == '\\') { + finalstr = finalstr.replace(colourcodes[i], colourcodes[i].slice(1)); + break; + } + + var num = colourcodes[i].slice(1).split(','); + // divide it into foreground and background + + if (num.length === 1) { + if (num[0] > 15) { + switch(num[0]) { + case '16': + finalstr = finalstr.replace(colourcodes[i], '\x02'); + break; + // bold + case '17': + finalstr = finalstr.replace(colourcodes[i], '\x09'); + break; + // italic + case '18': + finalstr = finalstr.replace(colourcodes[i], '\x13'); + break; + // strike-through + case '19': + finalstr = finalstr.replace(colourcodes[i], '\x15'); + break; + // underline + case '20': + finalstr = finalstr.replace(colourcodes[i], '\x0f'); + break; + // reset + default: + break; + } + // if this trigger is not a colour + } else { + finalstr = finalstr.replace(colourcodes[i], '\x03' + num[0]); + // otherwise it's a colour + } + } else { + var background = num[1], + foreground = num[2]; + + finalstr = finalstr.replace(colourcodes[i], '\x03' + num[0] + ',' + num[1]); + } + // if background colour + } + + return finalstr; + } +}; +// ======================================== + +function Client(key, options, GenericSocket) { + var self = this, + genericSocket = GenericSocket || undefined; + + self.connection = IrcSocket(options, genericSocket); + self.options = options; + self.supported = Helper.defaultSupported(); + self.key = key; + + self._queueId = QueuePool.queueLength(options.server); + self._nick = options.nick; + self._hostname = options.hostname; + self._user = options.user; + self._oper = false; + self._requestedDisconnect = false; + self._sendRegisteredTimer; + self._pings = 0; + self._retryTimer = null; + self._retryCount = 0; + self._capCount = 0; + self._nickModifier = 0; + self._timedOut = false; + self._pingTimer = null; + self._cap = {}; + self._data = { + user: {}, + channel: {}, + server: {} + }; + // setup a bunch of variables to manage the state of the connection + + self.queueConnect = _.wrap(self.connection.connect, function(fn, qid) { + QueuePool.queueJob(self.options.server, qid, self.key, fn.bind(self.connection)); + }); + // setup queueConnect + + self.queueConnect(self._queueId); + // connect the server + + self.connection.on('connect', self._connectEvent.bind(self)); + self.connection.on('close', self._closeEvent.bind(self)); + self.connection.on('error', function(err) { }); + self.connection.on('data', self._parseLine.bind(self)); + // event handlers +}; + +// ======================================== +// Setup an irc events object, using this over a switch, seems much cleaner +// the huge switch was something I hated about node-irc. + +Client.prototype._parseLine = function (line) { + var message = Helper.parse(line); + + if (!message) { + return false; + } + // irc-message found a bad line + + if (_.isFunction(this._ircEvents[message.command])) { + this._ircEvents[message.command].call(this, message); + } else { + delete message.tags; + message.time = Helper.time(this._cap.enabled, message); + Events.emit([this.key, 'unknown'], message); + } + // we were using a switch here but it's a bit grim + // so we're storing the numerics as functions in _ircEvents and + // calling the nessicary event +}; + +Client.prototype._ircEvents = { + CAP: function(message) { + var capabilities = message.params[2].trim().replace(/(?:^| )[\-~=]/, '').split(' '), + enable = ['away-notify', 'multi-prefix', 'server-time', 'znc.in/server-time-iso', 'znc.in/server-time']; + // which capabilities should we try to enable, for now just away notify, until others are supported + + if (this.options.sasl && this.options.password !== null) { + // we check for sasl AND password, so we can let users put passwords in without + // connecting via sasl, such as genuinely passworded ircds + enable.push('sasl'); + } + + switch(message.params[1]) { + case 'LS': + this._cap = {}; + // reset the object, if we just store it in this, we might end up with repeat values on a reconnect + + this._cap.requested = _.intersection(capabilities, enable); + // we need to figure out if we can enable any of the capabilities the server supports + + if (this._cap.requested.length == 0) { + this.raw(['CAP', 'END']); + this._cap.handshake = false; + } else { + this.raw(['CAP', 'REQ', this._cap.requested.join(' ')]); + this._cap.handshake = true; + } + // here the server is going to tell us what capabilities it supports + break; + case 'ACK': + if (capabilities.length > 0) { + this._cap.enabled = capabilities; + // these are the capabilities that are enabled + this._cap.requested = _.difference(this._cap.requested, capabilities); + } + + if (this._cap.enabled.length > 0) { + if (_.contains(this._cap.enabled, 'sasl')) { + this._cap.sasl = true; + this.raw(['AUTHENTICATE', 'PLAIN']); + // we need to figure out if this is SASL, if not + // we're done and can close the handshake, below; + } else { + this.raw(['CAP', 'END']); + this._cap.handshake = false; + } + } + break; + case 'NAK': + if (capabilities.length > 0) { + this._cap.requested = _.difference(this._cap.requested, capabilities); + } + + if (this._cap.requested.length > 0) { + this.raw(['CAP', 'END']); + this._cap.handshake = false; + } + // we've been denied the request, lets end. + break; + } + }, + + AUTHENTICATE: function(message) { + if (message.params[0] == '+') { + var username = this.options.saslUsername || this._nick, + password = this.options.password, + tmp = new Buffer(username + '\0' + username + '\0' + password).toString('base64'); + // encode the base64 hash to send to the server + + this.raw(['AUTHENTICATE', tmp]); + // we've got the go ahead to attempt to authenticate. + // at the request of Techman (y) I've implemented the ability to sasl auth via + // a different username unlike basically every client out there + // we do this with this.options.saslUsername, if it's not present just use nickname + } else { + this.raw(['CAP', 'END']); + this._cap.handshake = false; + this._cap.sasl = false; + } + }, + + RPL_YOUREOPER: function(message) { + this._oper = true; + }, + + RPL_NOTOPERANYMORE: function(message) { + this._oper = false; + }, + + RPL_SASLAUTHENTICATED: function(message) { + this.raw(['CAP', 'END']); + this._cap.handshake = false; + this._cap.sasl = true; + }, + + RPL_SASLLOGGEDIN: function(message) { + if (!this._cap.handshake) { + this.raw(['CAP', 'END']); + } + }, + + ERR_SASLNOTAUTHORISED: function(message) { + this.raw(['CAP', 'END']); + this._cap.handshake = false; + }, + + AWAY: function(message) { + if (message.params.length !== 0 && message.params[0] !== '') { + Events.emit([this.key, 'away'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + message: message.params[0], + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + } else { + Events.emit([this.key, 'unaway'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + } + }, + + RPL_NOWAWAY: function(message) { + Events.emit([this.key, 'away'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + RPL_UNAWAY: function(message) { + Events.emit([this.key, 'unaway'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + ERR_NICKNAMEINUSE: function(message) { + this._nickModifier++; + var nickname = this._nick + this._nickModifier.toString(); + // create a new nickname + + this.nick(nickname); + }, + + ERR_NOMOTD: function(message) { + var target = message.params[0]; + + this._addData('server', target, 'motd', [message.params[1]]); + this._addData('server', target, 'raw', [message.raw]); + + Events.emit([this.key, 'motd'], this._getData('server', target, message)); + this._clearData('server', target); + }, + + RPL_WELCOME: function(message) { + this.supported = Helper.defaultSupported(); + this._negotiation = true; + this._pings = 0; + this._requestedDisconnect = false; + this._nick = message.params[0]; + // reset variables + + this.supported.raw.push(message.raw); + + clearTimeout(this._sendRegisteredTimer); + this._sendRegisteredTimer = setTimeout(this._sendRegistered.bind(this, message), 10); + }, + + RPL_YOURHOST: function(message) { + this.supported.raw.push(message.raw); + + clearTimeout(this._sendRegisteredTimer); + this._sendRegisteredTimer = setTimeout(this._sendRegistered.bind(this, message), 10); + }, + + RPL_CREATED: function(message) { + this.supported.raw.push(message.raw); + + clearTimeout(this._sendRegisteredTimer); + this._sendRegisteredTimer = setTimeout(this._sendRegistered.bind(this, message), 10); + }, + + RPL_MYINFO: function(message) { + this.supported.network.hostname = message.params[1]; + this.supported.network.ircd = message.params[2] + this.supported.modes.user = message.params[3]; + this.supported.modes.channel = message.params[4]; + this.supported.modes.param = message.params[5]; + this.supported.raw.push(message.raw); + + clearTimeout(this._sendRegisteredTimer); + this._sendRegisteredTimer = setTimeout(this._sendRegistered.bind(this, message), 10); + }, + + RPL_ISUPPORT: function(message) { + for (var argi in message.params) { + var arg = message.params[argi], + match; + + if (match = arg.match(/([A-Z]+)=(.*)/)) { + var param = match[1], + value = match[2]; + + if (param == 'NETWORK') { + this.supported.network.name = value; + } else if (param == 'NICKLEN') { + this.supported.network.nicklength = parseInt(value); + } else if (param == 'TARGMAX') { + var values = value.split(','); + for (var vali in values) { + var val = values[vali].split(':'); + val[1] = (!val[1]) ? 0 : parseInt(val[1]); + this.supported.network.maxtargets[val[0]] = val[1]; + } + } else if (param == 'IDCHAN') { + var values = value.split(','); + for (var vali in values) { + var val = values[vali].split(':'); + this.supported.channel.idlength[val[0]] = val[1]; + } + } else if (param == 'CHANLIMIT') { + var values = value.split(','); + for (var vali in values) { + var val = values[vali].split(':'); + this.supported.channel.limit[val[0]] = parseInt(val[1]); + } + } else if (param == 'CHANNELLEN') { + this.supported.channel.length = parseInt(value); + } else if (param == 'MODES') { + this.supported.channel.modes = parseInt(value); + } else if (param == 'CHANTYPES') { + this.supported.channel.types = value; + } else if (param == 'KICKLEN') { + this.supported.channel.kicklength = parseInt(value); + } else if (param == 'TOPICLEN') { + this.supported.channel.topiclength = parseInt(value); + } else if (param == 'CHANMODES') { + value = value.split(','); + var type = ['a', 'b', 'c', 'd']; + for (var i = 0; i < type.length; i++) { + this.supported.modes.types[type[i]] += value[i]; + } + if (!this.supported.modes.param) { + this.supported.modes.param = this.supported.modes.types.a + this.supported.modes.types.b + this.supported.modes.types.c; + } + } else if (param == 'PREFIX') { + if (match = value.match(/\((.*?)\)(.*)/)) { + match[1] = match[1].split(''); + match[2] = match[2].split(''); + + this.supported.modes.prefixes = ''; + this.supported.modes.prefixmodes = {}; + // overwrite the default if we've got a PREFIX + + while (match[1].length) { + this.supported.modes.types.b += match[1][0]; + this.supported.modes.prefixes += match[2][0]; + this.supported.modes.prefixmodes[match[1].shift()] = match[2].shift(); + } + } + } else if (param == 'MAXLIST') { + var values = value.split(','); + for (var vali in values) { + var val = values[vali].split(':'); + this.supported.modes.maxlist[val[0]] = parseInt(val[1]); + } + } + } + } + + this.supported.raw.push(message.raw); + // append the raw lines + + clearTimeout(this._sendRegisteredTimer); + this._sendRegisteredTimer = setTimeout(this._sendRegistered.bind(this, message), 10); + }, + + RPL_LUSERCLIENT: function(message) { + this._addData('server', message.params[0], 'raw', [message.raw]); + }, + + RPL_LUSEROP: function(message) { + this._addData('server', message.params[0], 'raw', [message.raw]); + }, + + RPL_LUSERUNKNOWN: function(message) { + this._addData('server', message.params[0], 'raw', [message.raw]); + }, + + RPL_LUSERME: function(message) { + this._addData('server', message.params[0], 'raw', [message.raw]); + }, + + RPL_STATSCONN: function(message) { + this._addData('server', message.params[0], 'raw', [message.raw]); + }, + + RPL_LUSERCHANNELS: function(message) { + var target = message.params[0]; + + this._addData('server', target, 'channels', message.params[1]); + this._addData('server', target, 'raw', [message.raw]); + }, + + RPL_LOCALUSERS: function(message) { + var target = message.params[0]; + + this._addData('server', target, 'local', message.params[1]); + this._addData('server', target, 'localmax', message.params[2]); + this._addData('server', target, 'raw', [message.raw]); + }, + + RPL_GLOBALUSERS: function(message) { + var target = message.params[0]; + + this._addData('server', target, 'global', message.params[1]); + this._addData('server', target, 'globalmax', message.params[2]); + this._addData('server', target, 'raw', [message.raw]); + + Events.emit([this.key, 'lusers'], this._getData('server', target, message)); + this._clearData('server', target); + }, + + RPL_ENDOFMOTD: function(message) { + var target = message.params[0]; + + this._addData('server', target, 'motd', [message.params[1]]); + this._addData('server', target, 'raw', [message.raw]); + + Events.emit([this.key, 'motd'], this._getData('server', target, message)); + this._clearData('server', target); + + }, + + RPL_MOTDSTART: function(message) { + this._addData('server', message.params[0], 'motd', [message.params[1]]); + this._addData('server', message.params[0], 'raw', [message.raw]); + }, + + RPL_MOTD: function(message) { + this._addData('server', message.params[0], 'motd', [message.params[1]]); + this._addData('server', message.params[0], 'raw', [message.raw]); + }, + + RPL_HOSTHIDDEN: function(message) { + this._hostname = message.params[1]; + }, + + RPL_NAMREPLY: function(message) { + var target = message.params[2].toLowerCase(); + + this._addData('channel', target, 'names', _.without(message.params[3].split(/ +/), '')); + this._addData('channel', target, 'raw', [message.raw]); + }, + + RPL_ENDOFNAMES: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('channel', target, 'raw', [message.raw]); + + Events.emit([this.key, 'names'], this._getData('channel', target, message)); + this._clearData('channel', target); + }, + + RPL_AWAY: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'away', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISUSER: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'nickname', message.params[1]); + this._addData('user', target, 'username', message.params[2]); + this._addData('user', target, 'hostname', message.params[3]); + this._addData('user', target, 'realname', message.params[5]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISIDLE: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'idle', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISCHANNELS: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'channels', _.without(message.params[2].trim().split(/ +/), '')); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISSERVER: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'server', message.params[2]); + this._addData('user', target, 'serverinfo', message.params[3]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISMODES: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'modes', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISHOST: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'host', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISADMIN: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'operator', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISOPERATOR: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'operator', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISHELPOP: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'helpop', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISBOT: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'bot', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISSPECIAL: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'special', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISACCOUNT: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'account', message.params[2]); + this._addData('user', target, 'accountinfo', message.params[3]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISLOGGEDIN: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'loggedin', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_WHOISSECURE: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('user', target, 'secure', message.params[2]); + this._addData('user', target, 'raw', [message.raw]); + }, + + RPL_ENDOFWHOIS: function(message) { + var target = message.params[1].toLowerCase(); + + Events.emit([this.key, 'whois'], this._getData('user', target, message)); + this._clearData('user', target); + }, + + RPL_WHOREPLY: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('channel', target, 'who', [{ + channel: target, + prefix: message.params[2] + '@' + message.params[3], + nickname: message.params[5], + mode: message.params[6], + extra: message.params[7] || '' + }]); + this._addData('channel', target, 'raw', [message.raw]); + }, + + RPL_WHOSPCRPL: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('channel', target, 'who', [{ + channel: target, + prefix: message.params[3] + '@' + message.params[4], + nickname: message.params[6], + mode: message.params[7], + extra: message.params[9] || '' + }]); + this._addData('channel', target, 'raw', [message.raw]); + }, + + RPL_ENDOFWHO: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('channel', target, 'raw', [message.raw]); + + Events.emit([this.key, 'who'], this._getData('channel', target, message)); + this._clearData('channel', target); + }, + + RPL_LISTSTART: function(message) { + ListCache.createList(this); + }, + + RPL_LIST: function(message) { + ListCache.insertListData(this, message); + }, + + RPL_LISTEND: function(message) { + Events.emit([this.key, 'listend'], {}); + }, + + RPL_LINKS: function(message) { + this._addData('server', message.params[0], 'links', [{ + server: message.params[1], + link: message.params[2], + description: message.params[3] + }]); + this._addData('server', message.params[0], 'raw', [message.raw]); + }, + + RPL_ENDOFLINKS: function(message) { + var target = message.params[0]; + + Events.emit([this.key, 'links'], this._getData('server', target, message)); + this._clearData('server', target); + }, + + RPL_BANLIST: function(message) { + var channel = message.params[1].toLowerCase(); + + this._addData('channel', channel, 'banlist', [{ + channel: channel, + setby: message.params[3], + hostname: message.params[2], + timestamp: message.params[4] + }]); + + this._addData('channel', channel, 'raw', [message.raw]); + }, + + RPL_ENDOFBANLIST: function(message) { + var target = message.params[1].toLowerCase(), + results = this._getData('channel', target, message); + + if (results) { + Events.emit([this.key, 'banlist'], results); + } else { + Events.emit([this.key, 'banlist'], { + channel: target, + banlist: [], + raw: message.raw, + time: Helper.time(this._cap.enabled, message) + }); + } + + this._clearData('channel', target); + }, + + RPL_INVITELIST: function(message) { + var channel = message.params[1].toLowerCase(); + + this._addData('channel', channel, 'invitelist', [{ + channel: channel, + setby: message.params[3], + hostname: message.params[2], + timestamp: message.params[4] + }]); + + this._addData('channel', channel, 'raw', [message.raw]); + }, + + RPL_ENDOFINVITELIST: function(message) { + var target = message.params[1].toLowerCase(), + results = this._getData('channel', target, message); + + if (results) { + Events.emit([this.key, 'invitelist'], results); + } else { + Events.emit([this.key, 'invitelist'], { + channel: target, + invitelist: [], + raw: message.raw, + time: Helper.time(this._cap.enabled, message) + }); + } + + this._clearData('channel', target); + }, + + RPL_EXCEPTLIST: function(message) { + var channel = message.params[1].toLowerCase(); + + this._addData('channel', channel, 'exceptlist', [{ + channel: channel, + setby: message.params[3], + hostname: message.params[2], + timestamp: message.params[4] + }]); + + this._addData('channel', channel, 'raw', [message.raw]); + }, + + RPL_ENDOFEXCEPTLIST: function(message) { + var target = message.params[1].toLowerCase(), + results = this._getData('channel', target, message); + + if (results) { + Events.emit([this.key, 'exceptlist'], results); + } else { + Events.emit([this.key, 'exceptlist'], { + channel: target, + exceptlist: [], + raw: message.raw, + time: Helper.time(this._cap.enabled, message) + }); + } + + this._clearData('channel', target); + }, + + RPL_QUIETLIST: function(message) { + var channel = message.params[1].toLowerCase(); + + this._addData('channel', channel, 'quietlist', [{ + channel: channel, + setby: message.params[3], + hostname: message.params[2], + timestamp: message.params[4] + }]); + + this._addData('channel', channel, 'raw', [message.raw]); + }, + + RPL_ENDOFQUIETLIST: function(message) { + var target = message.params[1].toLowerCase(), + results = this._getData('channel', target, message); + + if (results) { + Events.emit([this.key, 'quietlist'], results); + } else { + Events.emit([this.key, 'quietlist'], { + channel: target, + quietlist: [], + raw: message.raw, + time: Helper.time(this._cap.enabled, message) + }); + } + + this._clearData('channel', target); + }, + + RPL_TOPICWHOTIME: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('channel', target, 'topicBy', message.params[2]); + this._addData('channel', target, 'raw', [message.raw]); + // set topic by, all the other stuff such as topic should be here aswell + + Events.emit([this.key, 'topic'], this._getData('channel', target, message)); + this._clearData('channel', target); + // emit it and clear, we dont output directly cause we need to get properties from earlier + }, + + RPL_TOPIC: function(message) { + var target = message.params[1].toLowerCase(); + + this._addData('channel', target, 'topic', message.params[2]); + this._addData('channel', target, 'raw', [message.raw]); + // set the topic from RPL, usually on JOIN or TOPIC + // we use _addChannelData because we need to store it temporarily between commands :3 + }, + + RPL_NOTOPIC: function(message) { + Events.emit([this.key, 'topic'], { + channel: message.params[0], + topic: '', + topicBy: '', + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + TOPIC: function(message) { + Events.emit([this.key, 'topic_change'], { + channel: message.params[0], + topic: message.params[1], + topicBy: message.nickname + '!' + message.username + '@' + message.hostname, + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + RPL_CHANNELMODEIS: function(message) { + Events.emit([this.key, 'mode'], { + channel: message.params[1], + mode: message.params.slice(2).join(' '), + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + MODE: function(message) { + var target = message.params[0], + mode = message.params.slice(1).join(' '); + + if (target == this._nick || target == this.options.nick) { + Events.emit([this.key, 'usermode'], { + nickname: target, + mode: mode, + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + } else { + Events.emit([this.key, 'mode_change'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + channel: target, + mode: mode, + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + + this._clearData('channel', target); + } + }, + + NICK: function(message) { + if (message.nickname === this._nick) { + this._nick = message.params[0]; + } + // we've changed our own nick, update our internal record + + Events.emit([this.key, 'nick'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + newnick: message.params[0], + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + JOIN: function(message) { + if (message.nickname === this._nick) { + this._hostname = message.hostname; + } + // update our internal record + + Events.emit([this.key, 'join'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + channel: message.params[0], + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + // our node-irc implementation did shit like, checking for netsplits + // i'm not going to add this at the moment, cause it was touchy + }, + + PART: function(message) { + Events.emit([this.key, 'part'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + channel: message.params[0], + message: message.params[1] || '', + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + KICK: function(message) { + Events.emit([this.key, 'kick'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + kicked: message.params[1], + channel: message.params[0], + message: message.params[2] || '', + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + QUIT: function(message) { + Events.emit([this.key, 'quit'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + message: message.params[0] || '', + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + INVITE: function(message) { + Events.emit([this.key, 'invite'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + channel: message.params[1], + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + }, + + NOTICE: function(message) { + if (message.params.length < 2) { + return false; + } + // safeguard against nonsense messages + + var to = message.params[0], + text = message.params[1]; + + if (((text[0] === '+' && text[1] === '\\1') || text[0] === '\\1') && text.lastIndexOf('\\1') > 0) { + this._handleCTCP(message, text, 'NOTICE'); + } else { + Events.emit([this.key, 'notice'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + target: message.params[0], + message: message.params[1], + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + } + // ctcp response or normal notice? + }, + + PRIVMSG: function(message) { + if (message.params.length < 2) { + return false; + } + // safeguard against nonsense messages + + var to = message.params[0], + text = message.params[1]; + + if (((text[0] === '+' && text[1] === '\\1') || text[0] === '\\1') && text.lastIndexOf('\\1') > 0) { + this._handleCTCP(message, text, 'PRIVMSG'); + } else { + Events.emit([this.key, 'privmsg'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + target: message.params[0], + message: message.params[1], + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + } + // ctcp or normal message? + // the + infront of it xchat was sending? Not sure why, but we accomodate for that now. + }, + + PONG: function(message) { + this._lastTime = Math.floor((+new Date()) / 1000); + }, + + ERROR: function(message) { + if (/(.*)(throttled|throttling)(.*)/i.test(message.params[0])) { + Events.emit([this.key, 'throttled'], { + message: message.params[1], + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + } + } +}; + +Client.prototype.raw = function(data) { + if (_.isArray(data)) { + for (var index in data) { + var token = data[index]; + if (typeof token !== 'string') { + data.splice(index, 1); + continue; + } + // ignore and remove none string items. Long standing bug this is.. Fuck nodejs and javascript + + if (token.indexOf('\n') !== -1 || token.indexOf('\r') !== -1) { + data[index] = token.replace('\n', '').replace('\r', ''); + } + } + + // Hack to add an extra ':' when last parameter does not contain spaces + // and starts with a ':' E.g.: ['PRIVMSG', '#smiley-test', ':)'] + // see https://github.com/Havvy/irc-socket/pull/11 + var last = data.length - 1; + if (data[last].indexOf(' ') === -1 && data[last][0] === ':') { + data[last] = ':' + data[last]; + } + this.connection.raw(data); + } else { + this.connection.raw(data); + } +}; + +Client.prototype.nick = function(newnick) { + this.raw(['NICK', newnick]); +}; + +Client.prototype.join = function(channel, password) { + var password = password || ''; + this.raw(['JOIN', channel, password]); +}; + +Client.prototype.part = function(channel, message) { + var message = message || ''; + this.raw(['PART', channel, message]); +}; + +Client.prototype.mode = function() { + var target = arguments[0], + mode = Array.prototype.slice.call(arguments, 1); + + this.raw(['MODE', target].concat(mode)); +}; + +Client.prototype.topic = function(channel, topic) { + var topic = topic || ''; + this.raw(['TOPIC', channel, Helper.col(topic)]); +}; + +Client.prototype.notice = function(target, message, forcePushBack) { + var forcePushBack = forcePushBack || false, + msg = Helper.col(message); + + this.raw(['NOTICE', target, msg]); + + if (forcePushBack) { + this._parseLine(':' + this._nick + '!' + this._user + '@' + this._hostname + ' NOTICE ' + target + ' :' + msg); + } +}; + +Client.prototype.privmsg = function(target, message, forcePushBack) { + forcePushBack = forcePushBack || false; + var rawPrefix = 'PRIVMSG ' + target + ' :', + cutOff = 510 - rawPrefix.length; + + var cutAndSend = function (msgStr) { + var buf = new Buffer(cutOff), + charLen; + + buf.write(msgStr, 0, 'utf8'); + charLen = buf.toString('utf8').length; + + if (charLen < msgStr.length) { + + // split the message + var head = msgStr.substr(0, charLen); + var tail = msgStr.substr(charLen); + + // try to respect word boundaries + var lastWordIndex = head.lastIndexOf(" "); + if (lastWordIndex > 0) { + tail = head.substr(lastWordIndex) + tail; + head = head.substr(0, lastWordIndex); + } + + // send along + send(head.trim()); + // and recurse + cutAndSend(tail.trim()); + } else if (msgStr.indexOf('\n') !== -1) { + // split the message + var parts = msgStr.split(/\n/g); + + // send + send(parts[0]); + + // recurse + if (parts.length > 0) { + parts.shift(); + cutAndSend(parts.join('\n')); + } + } else { + send(msgStr); + } + }; + + /* NOTE: + * forcePushBack is undocumented, and it's to be used to send the final formatted string back + * to the client who sent it, because we don't actually get reciepts for outgoing PRIVMSGs + * most clients fake it or insert it manually into their views. We provide the option to push it + * back into _parseLine so that any client listening for PRIVMSGs will treat it like it's incoming + * and not outgoing. This is in use in the ircanywhere repository for outgoing messages + */ + var send = function (msg) { + this.raw(['PRIVMSG', target, msg]); + + if (forcePushBack) { + this._parseLine(':' + this._nick + '!' + this._user + '@' + this._hostname + ' PRIVMSG ' + target + ' :' + msg); + } + + }.bind(this); + + cutAndSend(Helper.col(message)); +}; + +Client.prototype.me = function(target, message, forcePushBack) { + var forcePushBack = forcePushBack || false, + msg = '\x01ACTION ' + Helper.col(message) + '\x01'; + + this.raw(['PRIVMSG', target, msg]); + + if (forcePushBack) { + this._parseLine(':' + this._nick + '!' + this._user + '@' + this._hostname + ' PRIVMSG ' + target + ' :' + msg); + } +}; + +Client.prototype.ctcp = function(target, type, text, forcePushBack) { + var forcePushBack = forcePushBack || false, + msg = '\x01' + type.toUpperCase() + ' ' + Helper.col(text) + '\x01'; + + this.raw(['NOTICE', target, msg]); + + if (forcePushBack) { + this._parseLine(':' + this._nick + '!' + this._user + '@' + this._hostname + ' NOTICE ' + target + ' :' + msg); + } +}; + +Client.prototype.list = function(search, page, limit) { + var search = search || '*', + page = page || 1, + limit = limit || 50; + // defaults + + search = search.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + regex = search.replace(/\\\*/g, '(.*)'); + // convert '*php*' into regex '(.*)php(.*)' + + ListCache.requestList(this, regex, page, limit); +}; + +Client.prototype.disconnect = function(message) { + this._requestedDisconnect = true; + + if (this.connection.isConnected()) { + this.raw(['QUIT', message || 'Disconnecting']); + // are we still event connected? if so send QUIT + } + + if (this._timedOut) { + this.connection.end(); + this._closeEvent(); + // looks like we've timed out, destroy the connection and emit a close event + } + + clearInterval(this._pingTimer); +}; + +Client.prototype.reconnect = function() { + if (this.connection.isConnected()) { + this.disconnect(); + } + // disconnect if connected + + this._nick = this.options.nick; + + this._nickModifier = 0; + this._cap = {}; + this._data = { + user: {}, + channel: {}, + server: {} + }; + + this.queueConnect(this._queueId); + // connect the server +}; + +Client.prototype.isConnected = function() { + return this.connection.isConnected(); +}; +// ======================================== + +// ======================================== +// the following 3 functions are based on the ones from +// node-irc + +Client.prototype._addData = function(type, name, key, value) { + if (!type || !name || !key || !value) { + return false; + } + // safe guarding parameters + + if (type == 'user') { + var obj = {nickname: name}; + } else if (type == 'channel') { + var obj = {channel: name}; + } else { + var obj = {}; + } + // create a default object template + + name = name.toLowerCase(); + + this._data[type][name] = this._data[type][name] || obj; + + if (key in this._data[type][name] && Array.isArray(this._data[type][name][key])) + this._data[type][name][key].push.apply(this._data[type][name][key], value); + else + this._data[type][name][key] = value; + // we can merge objects together unlike node-irc by passing value in as an array + // which can also have multiple objects in, to save us from looping, let V8 do the work. +}; + +Client.prototype._getData = function(type, name, message) { + if (!type || !name || !message || !this._data[type][name]) { + return false; + } + // safe guarding parameters + + name = name.toLowerCase(); + this._data[type][name].time = Helper.time(this._cap.enabled, message); + + return this._data[type][name]; +}; + +Client.prototype._clearData = function(type, name) { + if (!type || !name || !this._data[type][name]) { + return false; + } + // safe guarding parameters + + name = name.toLowerCase(); + delete this._data[type][name]; +}; +// ======================================== + +// ======================================== +// The below functions are utility functions which handle things like +// handling incoming ctcp methods + +Client.prototype._handleCTCP = function (message, text, type) { + text = (text[0] == '+') ? text.slice(2) : text.slice(1); + text = text.slice(0, text.indexOf('\\1')); + + var parts = _.without(text.split(/ +/), ''), + to = message.params[0]; + + if (type === 'PRIVMSG' && parts[0].toUpperCase() === 'ACTION') { + Events.emit([this.key, 'action'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + target: to, + message: parts.slice(1).join(' '), + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + // handle actions here + } else if (type === 'PRIVMSG' && parts[0].toUpperCase() === 'VERSION') { + Events.emit([this.key, 'ctcp_request'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + type: 'VERSION', + target: to, + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + // handle versions here. We send this to the host and let them reply by sending + // a ctcp reply back like so: Client.ctcp(to, 'VERSION', 'Awesomebot 1.0'); + // we prepend "; irc-factory 0.1.2" to the end in ctcp + } else if (type === 'PRIVMSG') { + Events.emit([this.key, 'ctcp_request'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + target: to, + type: parts[0].toUpperCase(), + message: parts.slice(1).join(' '), + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + // handle all other ctcp requests + } else if (type === 'NOTICE') { + Events.emit([this.key, 'ctcp_response'], { + nickname: message.nickname, + username: message.username, + hostname: message.hostname, + target: to, + type: parts[0].toUpperCase(), + message: parts.slice(1).join(' '), + time: Helper.time(this._cap.enabled, message), + raw: message.raw + }); + // these are ctcp responses from our requests + } +}; + +Client.prototype._sendRegistered = function(message) { + var self = this; + + this._retryCount = 0; + // reset retry count + + self._lastTime = Math.floor((+new Date()) / 1000); + + Events.emit([this.key, 'registered'], { + nickname: this._nick, + capabilities: _.omit(this.supported, 'raw'), + time: Helper.time(this._cap.enabled, message), + raw: this.supported.raw + }); + // this is our final 001-005 stuff coming out + + this._pingTimer = setInterval(function() { + var seconds = Math.floor((+new Date()) / 1000); + if ((seconds - self._lastTime) >= 5 * 60) { + self._timedOut = true; + self.disconnect(); + clearInterval(self._pingTimer); + } else { + self.raw(['PING', new Date().getTime().toString()]); + } + }, 30000); +}; + +Client.prototype._connectEvent = function() { + if (typeof this.connection.impl.localPort === 'undefined') { + return false; + } + + Events.emit([this.key, 'opened'], { + nickname: this._nick, + username: this.options.user, + server: this.options.server, + port: this.options.port, + localPort: this.connection.impl.localPort + }); +}; + +Client.prototype._closeEvent = function() { + var self = this, + count = (this.options.retryCount != null) ? this.options.retryCount : 10, + time = this.options.retryWait || 10000, + reconnect = false; + + if (this._retryCount == count) { + Events.emit([this.key, 'failed'], { + time: Helper.time(self._cap.enabled, {}), + reconnecting: reconnect, + attempts: self._retryCount + }); + + return; + // we're done here, emit failed + } else if (this._retryCount < count || count < 0) { + if (this._requestedDisconnect && !this._timedOut) { + reconnect = false; + // bail now. + } else { + reconnect = true; + } + + self._retryCount++; + + Events.emit([this.key, 'closed'], { + time: Helper.time(self._cap.enabled, {}), + reconnecting: reconnect, + attempts: self._retryCount + }); + // emit a close event + } + + if (reconnect) { + clearTimeout(this._retryTimer); + this._retryTimer = setTimeout(function() { + self.reconnect(); + }, time); + // now lets try a reconnect + } +}; +// ======================================== + +exports.Helper = Helper; +exports.Events = Events; +exports.Client = Client; diff --git a/src/inc/irc/listcache.js b/src/inc/irc/listcache.js new file mode 100644 index 0000000..b1c617b --- /dev/null +++ b/src/inc/irc/listcache.js @@ -0,0 +1,125 @@ +var _ = require('lodash'), + Events = require(__dirname + '/irc').Events; + +function ListCache() { + this.lists = {}; +}; + +// ======================================== +// this object manages list caching, in a normal single client +// scenario, grabbing the list on request is fine, but irc-factory +// isnt really designed for single client usage +// the ircanywhere use case requires lists to be available to all, for +// all networks. + +ListCache.prototype.requestList = function(ircObject, search, page, limit) { + if (!Events) { + Events = require(__dirname + '/irc').Events; + } + + var self = this, + key = ircObject.key; + + if (key === '') { + return false; + } + + if (!this.lists[key]) { + this.createList(ircObject); + ircObject.raw(['LIST']); + + Events.once([ircObject.key, 'listend'], function() { + self.filterList(ircObject, search, page, limit); + }); + // no cache is available? request one and wait to filter it + } else { + self.filterList(ircObject, search, page, limit); + // looks like we already have a cached list, pass it straight to filter + } + + clearTimeout(this.lists[key].deleteTimer); + this.lists[key].deleteTimer = setTimeout(function() { + delete self.lists[key]; + }, 600000); + // lets set a timer to trash this data if its not been requested in a while (10min) + // the only reason we cache it is to prevent people doing /list then /list, then /list + // and blocking the process +}; + +ListCache.prototype.filterList = function(ircObject, search, page, limit) { + var key = ircObject.key, + regex = new RegExp('(' + search + ')', 'i'), + list = this.lists[key]; + + if (key === '' || !list) { + return false; + } + // make sure the list exists + + var output = { + list: [], + raw: [], + search: search.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\$&").replace(/\(\.\*\)/g, '*'), + page: page, + limit: limit, + time: new Date() + }; + + var clone = _.cloneDeep(list.list); + var buffer = _.sortBy(clone, function(channel) { + return 0 - channel.users; + }); + // sort it + + buffer = _.filter(buffer, function(channel) { + return regex.test(channel.channel); + }); + // filter via the search parameters + + buffer = _.take(_.rest(buffer, (page - 1) * limit), limit); + // paginate + + for (var c in buffer) { + var channel = buffer[c]; + output.raw.push(channel.raw); + delete buffer[c].raw; + } + // i don't really like this, but we pull .raw from channel objects + // and push it into the output + + Events.emit([ircObject.key, 'list'], _.extend(output, { + list: buffer + })); + // emit the list event +}; + +ListCache.prototype.createList = function(ircObject) { + var key = ircObject.key; + if (key === '' || this.lists[key]) { + return false; + } + + this.lists[key] = { + key: key, + requestedAt: new Date(), + deleteTimer: null, + list: [] + }; +}; + +ListCache.prototype.insertListData = function(ircObject, message) { + var key = ircObject.key; + if (key !== '' && !this.lists[key]) { + this.createList(key); + } + + this.lists[key].list.push({ + channel: message.params[1], + users: message.params[2], + topic: message.params[3], + raw: message.raw + }); +}; +// ======================================== + +exports.ListCache = new ListCache(); \ No newline at end of file diff --git a/src/inc/irc/queuepool.js b/src/inc/irc/queuepool.js new file mode 100644 index 0000000..de176ad --- /dev/null +++ b/src/inc/irc/queuepool.js @@ -0,0 +1,65 @@ +var pausequeue = require('pause-queue'), + _ = require('lodash'), + api = require(__dirname + '/api').Api, + Queues = {}; + +function QueuePool() { + +}; + +// ======================================== +// these functions provide a way to push a new client into the queue, this means +// we can send 1000 clients to boot up, but in the old code they would do it at once +// which just wouldn't work, we now queue it with time in between. + +QueuePool.prototype.queueJob = function(server, qid, key, fn) { + var queue = this.queueExists(server); + + queue.push({key: key, qid: qid}, fn); + // here we take the server hostname, just directly so irc.freenode.org and chat.freenode.org + // are different. We have individual queues for hostnames so we can pause that queue if we've + // hit the throttling limit for that server or network +}; + +QueuePool.prototype.queueExists = function(server) { + server = server.toLowerCase(); + + if (!Queues[server]) { + Queues[server] = pausequeue(function(task, done) { + setTimeout(done, 1000); + // we don't get to the next item until we wait 1.5 seconds + }, 1); + } + + return Queues[server]; + // checks if a queue exists, creates or returns an existing queue +}; + +QueuePool.prototype.queueLength = function(server) { + return this.queueExists(server).length() + 1; +}; + +QueuePool.prototype.queuePause = function(server) { + var queue = this.queueExists(server); + + if (!queue.paused) { + queue.pause(); + // pause the queue + + setTimeout(function() { + queue.tasks = _.sortBy(queue.tasks, function(task) { + return task.data.qid; + }); + // make sure its re-sorted via the time of insert + + queue.resume(); + }, 30000); + // attempt to try and start again in 30 seconds + // generally we've no idea how long the servers throttle wait is, default is 60 + // but incase of it being less we can just try 30, that way if it is something like + // 30 we're not losing 30 seconds of potential reconnect time + } +}; +// ======================================== + +exports.QueuePool = new QueuePool(); \ No newline at end of file diff --git a/src/inc/irc/stub.js b/src/inc/irc/stub.js new file mode 100644 index 0000000..ddabdb0 --- /dev/null +++ b/src/inc/irc/stub.js @@ -0,0 +1,52 @@ +var events = require('events'), + util = require('util'), + _ = require('lodash'); + +function ReadWriteStream() { + events.EventEmitter.call(this); + this.readable = true; + this.writable = true; +} + +util.inherits(ReadWriteStream, events.EventEmitter); + +['end', 'error', 'close', 'setEncoding', 'pause', 'resume', 'destroy', 'drain', 'write', {name: 'rewrite', event: 'data'}, 'destroySoon'].forEach(function(func) { + ReadWriteStream.prototype[func.name || func] = (function(func) { + var event = func.event || func; + return function() { + var args = Array.prototype.slice.call(arguments); + args.unshift(event); + this.emit.apply(this, args); + }; + }(func)); +}); + +function ReadWriteNetStream(specialTimeout) { + this.specialTimeout = specialTimeout || false; + ReadWriteStream.call(this); + this.bufferSize = 0; + this.remoteAddress = ''; + this.remotePort = ''; + this.bytesRead = ''; + this.bytesWritten = ''; +} + +util.inherits(ReadWriteNetStream, ReadWriteStream); + +// Net.Socket +['connect', 'setSecure', 'setTimeout', 'setNoDelay', 'setKeepAlive', 'address', 'timeout'].forEach(function(funcName) { + ReadWriteNetStream.prototype[funcName.name || funcName] = (function(func) { + var event = funcName.event || func; + return function(a, b) { + if (this.specialTimeout && funcName === 'setTimeout' && _.isFunction(b)) { + this.on('timeout', b); + } + var args = Array.prototype.slice.call(arguments); + args.unshift(event); + this.emit.apply(this, args); + }; + }(funcName)); +}); + +module.exports.ReadWriteStream = ReadWriteStream; +module.exports.ReadWriteNetStream = ReadWriteNetStream; \ No newline at end of file diff --git a/src/inc/lib.js b/src/inc/lib.js new file mode 100644 index 0000000..533060c --- /dev/null +++ b/src/inc/lib.js @@ -0,0 +1,61 @@ +var factory = require(__dirname+'/../inc/api'); +var fs = require('fs'); +var self = Lib.prototype; + +self.api = new factory.Api(); + +var options = { + events: 31920, + rpc: 31930, + automaticSetup: true +}; +self.interfaces = self.api.connect(options); +self.events = self.interfaces.events; +self.rpc = self.interfaces.rpc; + +module.exports = Lib; +function Lib(config) { + self.cfg = config; + self.loadEvents(); +} + +self.loadEvents = () => { + var files = fs.readdirSync(__dirname+'/events/'); + files.forEach(file => { + if(file.substr(-3, 3) === '.js') { + console.log('Loading event', file); + require(__dirname+'/events/' + file)(self); + } + }); +}; + +self.reply = (tmp) => { + return { + network: tmp.event[0], + channel: tmp.message.target, + user: { + nick: tmp.message.nickname, + username: tmp.message.username, + hostname: tmp.message.hostname + }, + message: tmp.message.message, + time: tmp.message.time, + reply: function(msg) { + self.rpc.emit('call', this.event[0], 'privmsg', [ this.message.target, msg ]); + }.bind(tmp), + replyAction: function(msg) { + self.rpc.emit('call', this.event[0], 'privmsg', [ this.message.target, '\u0001' + 'ACTION ' + msg + '\u0001' ]); + }.bind(tmp), + replyNotice: function(msg) { + self.rpc.emit('call', this.event[0], 'notice', [ this.message.target, msg ]); + }.bind(tmp) + }; +}; + +self.loadIRC = () => { + for(let srv in self.cfg.irc) { + self.rpc.emit( 'createClient', srv, self.cfg.irc[srv] ); + console.log('Loading server', srv); + } + console.log('All servers have been loaded successfully'); +}; \ No newline at end of file diff --git a/src/inc/sql.js b/src/inc/sql.js new file mode 100644 index 0000000..419e9ae --- /dev/null +++ b/src/inc/sql.js @@ -0,0 +1,61 @@ +import mysql from 'nodejs-mysql'; + +const sql = mysql.getInstance( require(`${__dirname}/../../cfg/mysql.json`) ); +export default sql; + +/*var mysql = require('mysql'); + +var self = Cfg.prototype; +module.exports = Cfg; + +var haDC = () => { + self.sql = mysql.createConnection(require(__dirname+'/../cfg/mysql.json')); + self.sql.connect(err => { + if(err) setTimeout(haDC, 2000); + }); + self.sql.on('error', (err) => { + if(err.code === 'PROTOCOL_CONNECTION_LOST') haDC(); + }); +}; +haDC(); + + +function Cfg() { + self.cfg = {}; +} + +self.read = (kat, key) => { + return new Promise((resolve, reject) => { + var out = { + irc: {}, + main: {}, + websrv: {}, + trigger: {} + }; + self.sql.query("select * from `cfg`" + (kat?" where `class` = '"+kat+"'"+(key?" && `key` = '"+key+"'":""):""), (err, rows) => { + if(err || rows.length < 1) + reject( err ); + else { + rows.forEach(e => { + out[e.class][e.key] = ((type, value) => { + switch(type) { + case 'string': + return value; + break; + case 'int': + return parseInt(value); + break; + case 'bool': + return (value === 'true')?true:false; + break; + case 'json': + return JSON.parse(value); + break; + } + })(e.type, e.value); + }); + resolve(key?out[kat][key]:out); + } + }); + }); +};*/ \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..5d8741e --- /dev/null +++ b/src/index.js @@ -0,0 +1,31 @@ +const forever = require(__dirname+'/../node_modules/forever-monitor'); + +var child = new (forever.Monitor)(`${__dirname}/bot.js`, { + max: 1, + silent: false, + cwd: __dirname, + args: [], + spinSleepTime: 5000, + watch: true, + watchIgnoreDotFiles: true, + watchIgnorePatterns: [ + 'node_modules/*', + 'tmp/*' + ], + watchDirectory: __dirname +}); + +child.on('watch:restart', info => { + console.log(`Restaring bot because ${info.stat} changed`); +}); +child.on('restart', () => { + console.log(`restarting bot for ${child.times} time`); +}); +child.on('start', () => { + console.log('starting bot'); +}); +child.on('exit:code', code => { + console.log(`detected bot exited with code ${code}`); + //child.restart(); +}); +child.start(); \ No newline at end of file