You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by ma...@apache.org on 2019/06/12 02:43:50 UTC
[pulsar-client-node] 02/29: provide nodejs client
This is an automated email from the ASF dual-hosted git repository.
massakam pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-node.git
commit f866cd6dd1780763cbee49476b3ae147639eb54f
Author: yfuruta <yf...@yahoo-corp.jp>
AuthorDate: Mon Mar 11 18:15:35 2019 +0900
provide nodejs client
---
.clang-format | 25 +
.eslintrc.json | 9 +
.gitignore | 3 +
Gruntfile.js | 31 +
README.md | 52 +-
binding.gyp | 42 +
examples/consumer.js | 47 +
examples/producer.js | 51 +
index.js | 28 +
package-lock.json | 2762 +++++++++++++++++++++++++++++++++++++++++++++++++
package.json | 46 +
perf/perf_consumer.js | 103 ++
perf/perf_producer.js | 119 +++
src/Client.cc | 170 +++
src/Client.h | 41 +
src/Consumer.cc | 188 ++++
src/Consumer.h | 44 +
src/ConsumerConfig.cc | 106 ++
src/ConsumerConfig.h | 44 +
src/Message.cc | 197 ++++
src/Message.h | 64 ++
src/MessageId.cc | 87 ++
src/MessageId.h | 46 +
src/Producer.cc | 155 +++
src/Producer.h | 42 +
src/ProducerConfig.cc | 159 +++
src/ProducerConfig.h | 38 +
src/addon.cc | 35 +
28 files changed, 4733 insertions(+), 1 deletion(-)
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..cb40b50
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+BasedOnStyle: Google
+IndentWidth: 4
+ColumnLimit: 110
+SortIncludes: false
+BreakBeforeBraces: Custom
+BraceWrapping:
+ AfterEnum: true
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..70e3c60
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,9 @@
+{
+ "extends": "airbnb-base",
+ "rules": {
+ "class-methods-use-this": "warn",
+ "no-await-in-loop": "warn",
+ "no-console": "off",
+ "no-unused-vars": "warn"
+ }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ff60c16
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+build/
+node_modules/
+report/
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..70b901c
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+module.exports = (grunt) => {
+ grunt.loadNpmTasks('grunt-license-report');
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ 'grunt-license-report': {
+ output: {
+ path: './report/licenses',
+ format: 'html',
+ },
+ },
+ });
+};
diff --git a/README.md b/README.md
index b560743..90d856f 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,51 @@
-# Pulsar Node Client
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+# Pulsar Node.js client library
+
+The Pulsar Node.js client can be used to create Pulsar producers and consumers in Node.js.
+
+## Requirements
+
+Pulsar Node.js client library is based on the C++ client library. Follow the instructions for
+[C++ library](https://pulsar.apache.org/docs/en/client-libraries-cpp/) for installing the binaries through
+[RPM](https://pulsar.apache.org/docs/en/client-libraries-cpp/#rpm),
+[Deb](https://pulsar.apache.org/docs/en/client-libraries-cpp/#deb) or
+[Homebrew packages](https://pulsar.apache.org/docs/en/client-libraries-cpp/#macos).
+
+Also, this library works only in Node.js 10.x or later because it uses the
+[node-addon-api](https://github.com/nodejs/node-addon-api) module to wrap the C++ library.
+
+## How to build
+
+### Install dependent npm modules and build Pulsar client library:
+
+```shell
+$ git clone https://github.com/apache/pulsar-client-node.git
+$ cd pulsar-client-node
+$ npm install
+```
+
+### Rebuild Pulsar client library:
+
+```shell
+$ npm run build
+```
diff --git a/binding.gyp b/binding.gyp
new file mode 100644
index 0000000..88a6c70
--- /dev/null
+++ b/binding.gyp
@@ -0,0 +1,42 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+{
+ "targets": [
+ {
+ "target_name": "Pulsar",
+ "cflags!": ["-fno-exceptions"],
+ "cflags_cc!": ["-fno-exceptions"],
+ "include_dirs": ["<!@(node -p \"require('node-addon-api').include\")"],
+ "dependencies": ["<!@(node -p \"require('node-addon-api').gyp\")"],
+ "defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"],
+ "sources": [
+ "src/addon.cc",
+ "src/Message.cc",
+ "src/Client.cc",
+ "src/Producer.cc",
+ "src/ProducerConfig.cc",
+ "src/Consumer.cc",
+ "src/ConsumerConfig.cc",
+ "src/MessageId.cc",
+ ],
+ "libraries": ["-lpulsar"],
+ }
+ ]
+}
diff --git a/examples/consumer.js b/examples/consumer.js
new file mode 100644
index 0000000..7092c6b
--- /dev/null
+++ b/examples/consumer.js
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const Pulsar = require('../index.js');
+
+(async () => {
+ // Create a client
+ const clientConfig = {
+ serviceUrl: 'pulsar://localhost:6650',
+ operationTimeoutSeconds: 30,
+ };
+ const client = new Pulsar.Client(clientConfig);
+
+ // Create a consumer
+ const consumerConfig = {
+ topic: 'persistent://public/default/my-topic',
+ subscription: 'sub1',
+ ackTimeoutMs: 10000,
+ };
+ const consumer = await client.subscribe(consumerConfig);
+
+ // Receive messages
+ for (let i = 0; i < 10; i += 1) {
+ const msg = await consumer.receive();
+ console.log(msg.getData().toString());
+ consumer.acknowledge(msg);
+ }
+
+ await consumer.close();
+ await client.close();
+})();
diff --git a/examples/producer.js b/examples/producer.js
new file mode 100644
index 0000000..b1b6856
--- /dev/null
+++ b/examples/producer.js
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const Pulsar = require('../index.js');
+
+(async () => {
+ // Create a client
+ const clientConfig = {
+ serviceUrl: 'pulsar://localhost:6650',
+ operationTimeoutSeconds: 30,
+ };
+ const client = new Pulsar.Client(clientConfig);
+
+ // Create a producer
+ const producerConfig = {
+ topic: 'persistent://public/default/my-topic',
+ sendTimeoutMs: 30000,
+ batchingEnabled: true,
+ };
+ const producer = await client.createProducer(producerConfig);
+
+ // Send messages
+ const results = [];
+ for (let i = 0; i < 10; i += 1) {
+ const msg = `my-message-${i}`;
+ results.push(producer.send({
+ data: Buffer.from(msg),
+ }));
+ console.log(`Sent message: ${msg}`);
+ }
+ await Promise.all(results);
+
+ await producer.close();
+ await client.close();
+})();
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..03f3a08
--- /dev/null
+++ b/index.js
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const PulsarBinding = require('bindings')('Pulsar');
+
+const Pulsar = {
+ Client: PulsarBinding.Client,
+ Message: PulsarBinding.Message,
+ MessageId: PulsarBinding.MessageId,
+};
+
+module.exports = Pulsar;
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..25d495e
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,2762 @@
+{
+ "name": "pulsar-client",
+ "version": "0.0.1",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
+ "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.0.0"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
+ "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "acorn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz",
+ "integrity": "sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz",
+ "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==",
+ "dev": true
+ },
+ "ajv": {
+ "version": "6.6.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz",
+ "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ansi-escapes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
+ "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+ "dev": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "dev": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "array-find-index": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+ "dev": true
+ },
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
+ "dev": true
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ },
+ "astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+ "dev": true
+ },
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true
+ },
+ "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=",
+ "dev": true
+ },
+ "aws4": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
+ "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
+ },
+ "base64-js": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
+ "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dev": true,
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "bindings": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.1.tgz",
+ "integrity": "sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew=="
+ },
+ "block-stream": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
+ "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
+ "dev": true,
+ "requires": {
+ "inherits": "~2.0.0"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "builtin-modules": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+ "dev": true
+ },
+ "callsites": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz",
+ "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+ "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
+ "dev": true
+ },
+ "camelcase-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+ "dev": true,
+ "requires": {
+ "camelcase": "^2.0.0",
+ "map-obj": "^1.0.0"
+ }
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
+ },
+ "circular-json": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+ "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
+ "dev": true
+ },
+ "clang-format": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/clang-format/-/clang-format-1.2.4.tgz",
+ "integrity": "sha512-sw+nrGUp3hvmANd1qF8vZPuezSYQAiXgGBiEtkXTtJnnu6b00fCqkkDIsnRKrNgg4nv6NYZE92ejvOMIXZoejw==",
+ "dev": true,
+ "requires": {
+ "async": "^1.5.2",
+ "glob": "^7.0.0",
+ "resolve": "^1.1.6"
+ }
+ },
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^2.0.0"
+ }
+ },
+ "cli-width": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+ "dev": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+ "dev": true
+ },
+ "coffeescript": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz",
+ "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=",
+ "dev": true
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "colors": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+ "dev": true
+ },
+ "combined-stream": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
+ "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
+ "dev": true,
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
+ "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg=="
+ },
+ "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
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+ "dev": true
+ },
+ "contains-path": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
+ "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=",
+ "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=",
+ "dev": true
+ },
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "dev": true,
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "currently-unhandled": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+ "dev": true,
+ "requires": {
+ "array-find-index": "^1.0.1"
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "dateformat": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
+ "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=",
+ "dev": true,
+ "requires": {
+ "get-stdin": "^4.0.1",
+ "meow": "^3.3.0"
+ }
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "debuglog": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz",
+ "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+ "dev": true,
+ "requires": {
+ "object-keys": "^1.0.12"
+ }
+ },
+ "delay": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/delay/-/delay-4.1.0.tgz",
+ "integrity": "sha512-8Hea6/aOu3bPdDBQhSRUEUzF0QwuWmSPuIK+sxNdvcJtSfzb6HXrTd9DFJBCJcV9o83fFECqTgllqdnmUfq9+w=="
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+ "dev": true
+ },
+ "dezalgo": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
+ "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
+ "dev": true,
+ "requires": {
+ "asap": "^2.0.0",
+ "wrappy": "1"
+ }
+ },
+ "doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "dev": true,
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz",
+ "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.0",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "is-callable": "^1.1.4",
+ "is-regex": "^1.0.4",
+ "object-keys": "^1.0.12"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
+ "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
+ "dev": true,
+ "requires": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ }
+ },
+ "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
+ },
+ "eslint": {
+ "version": "5.12.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.12.0.tgz",
+ "integrity": "sha512-LntwyPxtOHrsJdcSwyQKVtHofPHdv+4+mFwEe91r2V13vqpM8yLr7b1sW+Oo/yheOPkWYsYlYJCkzlFAt8KV7g==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "ajv": "^6.5.3",
+ "chalk": "^2.1.0",
+ "cross-spawn": "^6.0.5",
+ "debug": "^4.0.1",
+ "doctrine": "^2.1.0",
+ "eslint-scope": "^4.0.0",
+ "eslint-utils": "^1.3.1",
+ "eslint-visitor-keys": "^1.0.0",
+ "espree": "^5.0.0",
+ "esquery": "^1.0.1",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^2.0.0",
+ "functional-red-black-tree": "^1.0.1",
+ "glob": "^7.1.2",
+ "globals": "^11.7.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^6.1.0",
+ "js-yaml": "^3.12.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.5",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "path-is-inside": "^1.0.2",
+ "pluralize": "^7.0.0",
+ "progress": "^2.0.0",
+ "regexpp": "^2.0.1",
+ "semver": "^5.5.1",
+ "strip-ansi": "^4.0.0",
+ "strip-json-comments": "^2.0.1",
+ "table": "^5.0.2",
+ "text-table": "^0.2.0"
+ }
+ },
+ "eslint-config-airbnb-base": {
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz",
+ "integrity": "sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw==",
+ "dev": true,
+ "requires": {
+ "eslint-restricted-globals": "^0.1.1",
+ "object.assign": "^4.1.0",
+ "object.entries": "^1.0.4"
+ }
+ },
+ "eslint-import-resolver-node": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz",
+ "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==",
+ "dev": true,
+ "requires": {
+ "debug": "^2.6.9",
+ "resolve": "^1.5.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "eslint-module-utils": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz",
+ "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=",
+ "dev": true,
+ "requires": {
+ "debug": "^2.6.8",
+ "pkg-dir": "^1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "eslint-plugin-import": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz",
+ "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==",
+ "dev": true,
+ "requires": {
+ "contains-path": "^0.1.0",
+ "debug": "^2.6.8",
+ "doctrine": "1.5.0",
+ "eslint-import-resolver-node": "^0.3.1",
+ "eslint-module-utils": "^2.2.0",
+ "has": "^1.0.1",
+ "lodash": "^4.17.4",
+ "minimatch": "^3.0.3",
+ "read-pkg-up": "^2.0.0",
+ "resolve": "^1.6.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "doctrine": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
+ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2",
+ "isarray": "^1.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "eslint-restricted-globals": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz",
+ "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=",
+ "dev": true
+ },
+ "eslint-scope": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
+ "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
+ "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
+ "dev": true
+ },
+ "eslint-visitor-keys": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
+ "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==",
+ "dev": true
+ },
+ "espree": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.0.tgz",
+ "integrity": "sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA==",
+ "dev": true,
+ "requires": {
+ "acorn": "^6.0.2",
+ "acorn-jsx": "^5.0.0",
+ "eslint-visitor-keys": "^1.0.0"
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "esquery": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^4.0.0"
+ }
+ },
+ "esrecurse": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^4.1.0"
+ }
+ },
+ "estraverse": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+ "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.14",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
+ "dev": true
+ },
+ "exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+ "dev": true
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "external-editor": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
+ "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
+ "dev": true,
+ "requires": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ }
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+ "dev": true
+ },
+ "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=",
+ "dev": true
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-entry-cache": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^1.2.1",
+ "object-assign": "^4.0.1"
+ }
+ },
+ "find-up": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+ "dev": true,
+ "requires": {
+ "path-exists": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "findup-sync": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
+ "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
+ "dev": true,
+ "requires": {
+ "glob": "~5.0.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "dev": true,
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
+ }
+ },
+ "flat-cache": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz",
+ "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==",
+ "dev": true,
+ "requires": {
+ "circular-json": "^0.3.1",
+ "graceful-fs": "^4.1.2",
+ "rimraf": "~2.6.2",
+ "write": "^0.2.1"
+ }
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "fstream": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
+ "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "inherits": "~2.0.0",
+ "mkdirp": ">=0.5 0",
+ "rimraf": "2"
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "dev": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "dev": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "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.0.0"
+ }
+ }
+ }
+ },
+ "get-stdin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+ "dev": true
+ },
+ "getobject": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
+ "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
+ "dev": true
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "github-url-from-git": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/github-url-from-git/-/github-url-from-git-1.5.0.tgz",
+ "integrity": "sha1-+YX+3MCpqledyI16/waNVcxiUaA=",
+ "dev": true
+ },
+ "github-url-from-username-repo": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/github-url-from-username-repo/-/github-url-from-username-repo-1.0.2.tgz",
+ "integrity": "sha1-fdeTMNKr5pwQws73lxTJchV5Hfo=",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "globals": {
+ "version": "11.10.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.10.0.tgz",
+ "integrity": "sha512-0GZF1RiPKU97IHUO5TORo9w1PwrH/NBPl+fS7oMLdaTRiYmYbwK4NWoZWrAdd0/abG9R2BU+OiwyQpTpE6pdfQ==",
+ "dev": true
+ },
+ "graceful-fs": {
+ "version": "4.1.15",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "dev": true
+ },
+ "grunt": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.3.tgz",
+ "integrity": "sha512-/JzmZNPfKorlCrrmxWqQO4JVodO+DVd5XX4DkocL/1WlLlKVLE9+SdEIempOAxDhWPysLle6afvn/hg7Ck2k9g==",
+ "dev": true,
+ "requires": {
+ "coffeescript": "~1.10.0",
+ "dateformat": "~1.0.12",
+ "eventemitter2": "~0.4.13",
+ "exit": "~0.1.1",
+ "findup-sync": "~0.3.0",
+ "glob": "~7.0.0",
+ "grunt-cli": "~1.2.0",
+ "grunt-known-options": "~1.1.0",
+ "grunt-legacy-log": "~2.0.0",
+ "grunt-legacy-util": "~1.1.1",
+ "iconv-lite": "~0.4.13",
+ "js-yaml": "~3.5.2",
+ "minimatch": "~3.0.2",
+ "mkdirp": "~0.5.1",
+ "nopt": "~3.0.6",
+ "path-is-absolute": "~1.0.0",
+ "rimraf": "~2.6.2"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
+ "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.2",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "grunt-cli": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz",
+ "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=",
+ "dev": true,
+ "requires": {
+ "findup-sync": "~0.3.0",
+ "grunt-known-options": "~1.1.0",
+ "nopt": "~3.0.6",
+ "resolve": "~1.1.0"
+ }
+ },
+ "js-yaml": {
+ "version": "3.5.5",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz",
+ "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.2",
+ "esprima": "^2.6.0"
+ }
+ },
+ "resolve": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-known-options": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz",
+ "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==",
+ "dev": true
+ },
+ "grunt-legacy-log": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz",
+ "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==",
+ "dev": true,
+ "requires": {
+ "colors": "~1.1.2",
+ "grunt-legacy-log-utils": "~2.0.0",
+ "hooker": "~0.2.3",
+ "lodash": "~4.17.5"
+ }
+ },
+ "grunt-legacy-log-utils": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz",
+ "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==",
+ "dev": true,
+ "requires": {
+ "chalk": "~2.4.1",
+ "lodash": "~4.17.10"
+ }
+ },
+ "grunt-legacy-util": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz",
+ "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==",
+ "dev": true,
+ "requires": {
+ "async": "~1.5.2",
+ "exit": "~0.1.1",
+ "getobject": "~0.1.0",
+ "hooker": "~0.2.3",
+ "lodash": "~4.17.10",
+ "underscore.string": "~3.3.4",
+ "which": "~1.3.0"
+ }
+ },
+ "grunt-license-report": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/grunt-license-report/-/grunt-license-report-0.0.8.tgz",
+ "integrity": "sha1-/gn4e+ddPgBpj4MGAF2PkzsPNv4=",
+ "dev": true,
+ "requires": {
+ "license-checker": "2.0.1"
+ }
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-ansi": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
+ "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^0.2.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz",
+ "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=",
+ "dev": true
+ }
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "has-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
+ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
+ "dev": true
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+ "dev": true
+ },
+ "hdr-histogram-js": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-1.1.4.tgz",
+ "integrity": "sha1-dBNAJdGuHP711/ESfrdWDeKgp3M=",
+ "requires": {
+ "base64-js": "^1.2.0",
+ "pako": "^1.0.3"
+ }
+ },
+ "hooker": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
+ "dev": true
+ },
+ "hosted-git-info": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
+ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
+ "dev": true
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz",
+ "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+ "dev": true,
+ "requires": {
+ "repeating": "^2.0.0"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "inquirer": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz",
+ "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^3.0.0",
+ "chalk": "^2.0.0",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^3.0.0",
+ "figures": "^2.0.0",
+ "lodash": "^4.17.10",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rxjs": "^6.1.0",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^5.0.0",
+ "through": "^2.3.6"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz",
+ "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz",
+ "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.0.0"
+ }
+ }
+ }
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "is-builtin-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
+ "dev": true,
+ "requires": {
+ "builtin-modules": "^1.0.0"
+ }
+ },
+ "is-callable": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
+ "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
+ "dev": true
+ },
+ "is-date-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
+ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
+ "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.0"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true
+ },
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+ "dev": true
+ },
+ "is-regex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
+ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.1"
+ }
+ },
+ "is-symbol": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
+ "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.0"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
+ },
+ "jju": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
+ "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.12.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz",
+ "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true
+ },
+ "json-parse-helpfulerror": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz",
+ "integrity": "sha1-E/FM4C7tTpgSl7ZOueO5MuLdE9w=",
+ "dev": true,
+ "requires": {
+ "jju": "^1.1.0"
+ }
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "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=",
+ "dev": true
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "license-checker": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-2.0.1.tgz",
+ "integrity": "sha1-mrCsHX5FfvsLuXp3PoPBbOfyIvI=",
+ "dev": true,
+ "requires": {
+ "chalk": "~0.5.1",
+ "mkdirp": "^0.3.5",
+ "nopt": "^2.2.0",
+ "read-installed": "~3.1.3",
+ "treeify": "^1.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz",
+ "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz",
+ "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz",
+ "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^1.1.0",
+ "escape-string-regexp": "^1.0.0",
+ "has-ansi": "^0.1.0",
+ "strip-ansi": "^0.3.0",
+ "supports-color": "^0.2.0"
+ }
+ },
+ "mkdirp": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
+ "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=",
+ "dev": true
+ },
+ "nopt": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz",
+ "integrity": "sha1-KqCbfRdoSHs7ianFqlIzW/8Lrqc=",
+ "dev": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "strip-ansi": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
+ "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^0.2.1"
+ }
+ },
+ "supports-color": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz",
+ "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=",
+ "dev": true
+ }
+ }
+ },
+ "load-json-file": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
+ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "dependencies": {
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ }
+ }
+ },
+ "lodash": {
+ "version": "4.17.11",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+ "dev": true
+ },
+ "loud-rejection": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+ "dev": true,
+ "requires": {
+ "currently-unhandled": "^0.4.1",
+ "signal-exit": "^3.0.0"
+ }
+ },
+ "map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+ "dev": true
+ },
+ "meow": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+ "dev": true,
+ "requires": {
+ "camelcase-keys": "^2.0.0",
+ "decamelize": "^1.1.2",
+ "loud-rejection": "^1.0.0",
+ "map-obj": "^1.0.1",
+ "minimist": "^1.1.3",
+ "normalize-package-data": "^2.3.4",
+ "object-assign": "^4.0.1",
+ "read-pkg-up": "^1.0.1",
+ "redent": "^1.0.0",
+ "trim-newlines": "^1.0.0"
+ },
+ "dependencies": {
+ "load-json-file": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "strip-bom": "^2.0.0"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ },
+ "path-type": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "read-pkg": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^1.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^1.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+ "dev": true,
+ "requires": {
+ "find-up": "^1.0.0",
+ "read-pkg": "^1.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+ "dev": true,
+ "requires": {
+ "is-utf8": "^0.2.0"
+ }
+ }
+ }
+ },
+ "mime-db": {
+ "version": "1.37.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
+ "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.21",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
+ "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
+ "dev": true,
+ "requires": {
+ "mime-db": "~1.37.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "dev": true
+ },
+ "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.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "dev": true
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+ "dev": true
+ },
+ "natives": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz",
+ "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==",
+ "dev": true,
+ "optional": true
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+ "dev": true
+ },
+ "node-addon-api": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.6.2.tgz",
+ "integrity": "sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA==",
+ "dev": true
+ },
+ "node-gyp": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
+ "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
+ "dev": true,
+ "requires": {
+ "fstream": "^1.0.0",
+ "glob": "^7.0.3",
+ "graceful-fs": "^4.1.2",
+ "mkdirp": "^0.5.0",
+ "nopt": "2 || 3",
+ "npmlog": "0 || 1 || 2 || 3 || 4",
+ "osenv": "0",
+ "request": "^2.87.0",
+ "rimraf": "2",
+ "semver": "~5.3.0",
+ "tar": "^2.0.0",
+ "which": "1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+ "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+ "dev": true
+ }
+ }
+ },
+ "nopt": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+ "dev": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "normalize-package-data": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "is-builtin-module": "^1.0.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "dev": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "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.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true
+ },
+ "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-keys": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
+ "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
+ "dev": true
+ },
+ "object.assign": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "function-bind": "^1.1.1",
+ "has-symbols": "^1.0.0",
+ "object-keys": "^1.0.11"
+ }
+ },
+ "object.entries": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz",
+ "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.12.0",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "optionator": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+ "dev": true,
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.4",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "wordwrap": "~1.0.0"
+ }
+ },
+ "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
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+ "dev": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "dev": true,
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+ "dev": true
+ },
+ "pako": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz",
+ "integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA=="
+ },
+ "parent-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.0.tgz",
+ "integrity": "sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.2.0"
+ }
+ },
+ "path-exists": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+ "dev": true,
+ "requires": {
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "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
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+ "dev": true
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "path-type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
+ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
+ "dev": true,
+ "requires": {
+ "pify": "^2.0.0"
+ }
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "pkg-dir": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
+ "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
+ "dev": true,
+ "requires": {
+ "find-up": "^1.0.0"
+ }
+ },
+ "pluralize": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
+ "dev": true
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+ "dev": true
+ },
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true
+ },
+ "psl": {
+ "version": "1.1.31",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
+ "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==",
+ "dev": true
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "dev": true
+ },
+ "read-installed": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-3.1.5.tgz",
+ "integrity": "sha1-SuNgga/T4iBNwuJ5gHqqUsMMjAw=",
+ "dev": true,
+ "requires": {
+ "debuglog": "^1.0.1",
+ "graceful-fs": "2 || 3",
+ "read-package-json": "1",
+ "readdir-scoped-modules": "^1.0.0",
+ "semver": "2 || 3 || 4",
+ "slide": "~1.1.3",
+ "util-extend": "^1.0.1"
+ },
+ "dependencies": {
+ "graceful-fs": {
+ "version": "3.0.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz",
+ "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "natives": "^1.1.0"
+ }
+ },
+ "semver": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
+ "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=",
+ "dev": true
+ }
+ }
+ },
+ "read-package-json": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-1.3.3.tgz",
+ "integrity": "sha1-73nf2kbhZTdu6KV++/7dTRsCm6Q=",
+ "dev": true,
+ "requires": {
+ "glob": "^5.0.3",
+ "graceful-fs": "2 || 3",
+ "json-parse-helpfulerror": "^1.0.2",
+ "normalize-package-data": "^1.0.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "dev": true,
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "graceful-fs": {
+ "version": "3.0.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz",
+ "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "natives": "^1.1.0"
+ }
+ },
+ "normalize-package-data": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-1.0.3.tgz",
+ "integrity": "sha1-i+lVuJB6+XXxpFhOqLubQUkjEvU=",
+ "dev": true,
+ "requires": {
+ "github-url-from-git": "^1.3.0",
+ "github-url-from-username-repo": "^1.0.0",
+ "semver": "2 || 3 || 4"
+ }
+ },
+ "semver": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
+ "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=",
+ "dev": true
+ }
+ }
+ },
+ "read-pkg": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
+ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^2.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^2.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
+ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
+ "dev": true,
+ "requires": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^2.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "dev": true,
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdir-scoped-modules": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz",
+ "integrity": "sha1-n6+jfShr5dksuuve4DDcm19AZ0c=",
+ "dev": true,
+ "requires": {
+ "debuglog": "^1.0.1",
+ "dezalgo": "^1.0.0",
+ "graceful-fs": "^4.1.2",
+ "once": "^1.3.0"
+ }
+ },
+ "redent": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+ "dev": true,
+ "requires": {
+ "indent-string": "^2.1.0",
+ "strip-indent": "^1.0.1"
+ }
+ },
+ "regexpp": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
+ "dev": 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.0"
+ }
+ },
+ "request": {
+ "version": "2.88.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "dev": true,
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ }
+ },
+ "resolve": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz",
+ "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "dev": true,
+ "requires": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "run-async": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+ "dev": true,
+ "requires": {
+ "is-promise": "^2.1.0"
+ }
+ },
+ "rxjs": {
+ "version": "6.3.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
+ "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+ "dev": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.0.0.tgz",
+ "integrity": "sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ }
+ },
+ "slide": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
+ "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=",
+ "dev": true
+ },
+ "spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz",
+ "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==",
+ "dev": true
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "sshpk": {
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.0.tgz",
+ "integrity": "sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==",
+ "dev": true,
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true
+ },
+ "strip-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+ "dev": true,
+ "requires": {
+ "get-stdin": "^4.0.1"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "table": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.1.1.tgz",
+ "integrity": "sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.6.1",
+ "lodash": "^4.17.11",
+ "slice-ansi": "2.0.0",
+ "string-width": "^2.1.1"
+ }
+ },
+ "tar": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
+ "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
+ "dev": true,
+ "requires": {
+ "block-stream": "*",
+ "fstream": "^1.0.2",
+ "inherits": "2"
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "dev": true,
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ }
+ }
+ },
+ "treeify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz",
+ "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==",
+ "dev": true
+ },
+ "trim-newlines": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+ "dev": true
+ },
+ "tslib": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
+ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
+ "dev": true
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "underscore.string": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz",
+ "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "^1.0.3",
+ "util-deprecate": "^1.0.2"
+ }
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "util-extend": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz",
+ "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=",
+ "dev": true
+ },
+ "uuid": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
+ "dev": true
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+ "dev": true
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "write": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+ "dev": true,
+ "requires": {
+ "mkdirp": "^0.5.1"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..33b1321
--- /dev/null
+++ b/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "pulsar-client",
+ "version": "0.0.1",
+ "description": "Pulsar Node.js client",
+ "main": "index.js",
+ "directories": {
+ "src": "src",
+ "example": "examples"
+ },
+ "scripts": {
+ "clean": "node-gyp clean",
+ "configure": "node-gyp configure",
+ "lint": "eslint --ext .js .",
+ "format": "clang-format -i --verbose src/* && eslint --fix --ext .js .",
+ "build": "npm run format && node-gyp rebuild",
+ "build:debug": "npm run format && node-gyp rebuild --debug",
+ "license:report": "mkdir -p report && grunt grunt-license-report",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/apache/pulsar-client-node.git"
+ },
+ "author": "Apache Software Foundation",
+ "license": "Apache-2.0",
+ "gypfile": true,
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "devDependencies": {
+ "clang-format": "^1.2.4",
+ "eslint": "^5.12.0",
+ "eslint-config-airbnb-base": "^13.1.0",
+ "eslint-plugin-import": "^2.14.0",
+ "grunt": "^1.0.3",
+ "grunt-license-report": "^0.0.8",
+ "node-addon-api": "^1.6.2",
+ "node-gyp": "^3.8.0"
+ },
+ "dependencies": {
+ "bindings": "^1.3.1",
+ "commander": "^2.19.0",
+ "delay": "^4.1.0",
+ "hdr-histogram-js": "^1.1.4"
+ }
+}
diff --git a/perf/perf_consumer.js b/perf/perf_consumer.js
new file mode 100644
index 0000000..717eb45
--- /dev/null
+++ b/perf/perf_consumer.js
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const commander = require('commander');
+const delay = require('delay');
+const {
+ performance,
+} = require('perf_hooks');
+const Pulsar = require('../index.js');
+
+// Parse args
+(() => {
+ commander
+ .option('-s, --subscription [subscription]', 'Subscription')
+ .option('-u, --url [url]', 'Pulsar Service URL')
+ .option('-t, --topic [topic]', 'Topic Name')
+ .option('-m, --messages [messages]', 'Number of Messages', 1000)
+ .option('-i, --iteration [iteration]', 'Iteration of Measure', 3, parseInt)
+ .on('--help', () => {
+ console.log('');
+ console.log('Examples:');
+ console.log(' $ node perf/perf_consumer.js --subscription sub1 --url pulsar://localhost:6650 --topic persistent://public/default/my-topic');
+ })
+ .parse(process.argv);
+
+ if (typeof commander.subscription === 'undefined') {
+ console.error('no subscription given!');
+ process.exit(1);
+ }
+ if (typeof commander.url === 'undefined') {
+ console.error('no URL given!');
+ process.exit(1);
+ }
+ if (typeof commander.topic === 'undefined') {
+ console.error('no topic name given!');
+ process.exit(1);
+ }
+
+ console.log('----------------------');
+ commander.options.forEach((option) => {
+ const optionName = (option.long).replace('--', '');
+ console.log(`${optionName}: ${commander[optionName]}`);
+ });
+ console.log('----------------------');
+})();
+
+(async () => {
+ // Create a client
+ const clientConfig = {
+ serviceUrl: commander.url,
+ };
+ const client = new Pulsar.Client(clientConfig);
+
+ // Create a consumer
+ const consumerConfig = {
+ topic: commander.topic,
+ subscription: commander.subscription,
+ };
+ const consumer = await client.subscribe(consumerConfig);
+
+ const numOfMessages = parseInt(commander.messages, 10);
+ for (let i = 0; i < commander.iteration; i += 1) {
+ // measure
+ await delay(1000);
+ const startTimeMilliSeconds = performance.now();
+ const results = [];
+ for (let mi = 0; mi < numOfMessages; mi += 1) {
+ results.push(new Promise((resolve) => {
+ consumer.receive().then((msg) => {
+ consumer.acknowledge(msg);
+ resolve(msg.getData().length);
+ });
+ }));
+ }
+ const messageSizes = await Promise.all(results);
+ const endTimeMilliSeconds = performance.now();
+
+ // result
+ const durationSeconds = (endTimeMilliSeconds - startTimeMilliSeconds) / 1000.0;
+ const rate = numOfMessages / durationSeconds;
+ const totalMessageSize = messageSizes.reduce((a, b) => a + b);
+ const throuhputMbit = (totalMessageSize / 1024 / 1024 * 8) / durationSeconds;
+ console.log('Throughput received: %f msg/s --- %f Mbit/s', rate.toFixed(3), throuhputMbit.toFixed(3));
+ }
+ await consumer.close();
+ await client.close();
+})();
diff --git a/perf/perf_producer.js b/perf/perf_producer.js
new file mode 100644
index 0000000..19f251c
--- /dev/null
+++ b/perf/perf_producer.js
@@ -0,0 +1,119 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const commander = require('commander');
+const delay = require('delay');
+const hdr = require('hdr-histogram-js');
+const {
+ performance,
+} = require('perf_hooks');
+
+const Pulsar = require('../index.js');
+
+// Parse args
+(() => {
+ commander
+ .option('-s, --size [size]', 'Message Size', 1024, parseInt)
+ .option('-u, --url [url]', 'Pulsar Service URL')
+ .option('-t, --topic [topic]', 'Topic Name')
+ .option('-i, --iteration [iteration]', 'Iteration of Measure', 3, parseInt)
+ .option('-m, --messages [messages]', 'Number of Messages', 1000, parseInt)
+ .on('--help', () => {
+ console.log('');
+ console.log('Examples:');
+ console.log(' $ node perf/perf_producer.js --url pulsar://localhost:6650 --topic persistent://public/default/my-topic');
+ })
+ .parse(process.argv);
+
+ if (typeof commander.url === 'undefined') {
+ console.error('no URL given!');
+ process.exit(1);
+ }
+ if (typeof commander.topic === 'undefined') {
+ console.error('no topic name given!');
+ process.exit(1);
+ }
+
+ console.log('----------------------');
+ commander.options.forEach((option) => {
+ const optionName = (option.long).replace('--', '');
+ console.log(`${optionName}: ${commander[optionName]}`);
+ });
+ console.log('----------------------');
+})();
+
+// Produce
+(async () => {
+ // Create a client
+ const clientConfig = {
+ serviceUrl: commander.url,
+ };
+ const client = new Pulsar.Client(clientConfig);
+
+ // Create a producer
+ const producerConfig = {
+ topic: commander.topic,
+ };
+ const producer = await client.createProducer(producerConfig);
+
+ const sizeOfMessage = commander.size;
+ const message = Buffer.alloc(sizeOfMessage, 1);
+ const numOfMessages = commander.messages;
+ for (let i = 0; i < commander.iteration; i += 1) {
+ const histogram = hdr.build({
+ bitBucketSize: 0,
+ highestTrackableValue: 120000 * 1000,
+ numberOfSignificantValueDigits: 5,
+ });
+
+ // measure
+ await delay(1000);
+ const startMeasureTimeMilliSeconds = performance.now();
+ const results = [];
+ for (let mi = 0; mi < numOfMessages; mi += 1) {
+ const startSendTimeMilliSeconds = performance.now();
+ results.push(producer.send({
+ data: message,
+ }).then(() => {
+ // add latency
+ histogram.recordValue((performance.now() - startSendTimeMilliSeconds));
+ }));
+ }
+ await Promise.all(results);
+ const endMeasureTimeMilliSeconds = performance.now();
+
+ // result
+ const elapsedSeconds = (endMeasureTimeMilliSeconds - startMeasureTimeMilliSeconds) / 1000;
+ const rate = numOfMessages / elapsedSeconds;
+ const throuhputMbit = (sizeOfMessage * numOfMessages / 1024 / 1024 * 8) / elapsedSeconds;
+ console.log('Throughput produced: %f msg/s --- %f Mbit/s --- Latency: mean: %f ms - med: %f - 95pct: %f - 99pct: %f - 99.9pct: %f - 99.99pct: %f - Max: %f',
+ rate.toFixed(3),
+ throuhputMbit.toFixed(3),
+ histogram.getMean(),
+ histogram.getValueAtPercentile(50),
+ histogram.getValueAtPercentile(95),
+ histogram.getValueAtPercentile(99),
+ histogram.getValueAtPercentile(99.9),
+ histogram.getValueAtPercentile(99.99),
+ histogram.maxValue);
+ }
+
+ await producer.close();
+ await client.close();
+})();
diff --git a/src/Client.cc b/src/Client.cc
new file mode 100644
index 0000000..97fc573
--- /dev/null
+++ b/src/Client.cc
@@ -0,0 +1,170 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "Client.h"
+#include "Consumer.h"
+#include "Producer.h"
+#include <pulsar/c/client.h>
+#include <pulsar/c/client_configuration.h>
+#include <pulsar/c/result.h>
+
+static const std::string CFG_SERVICE_URL = "serviceUrl";
+static const std::string CFG_OP_TIMEOUT = "operationTimeoutSeconds";
+static const std::string CFG_IO_THREADS = "ioThreads";
+static const std::string CFG_LISTENER_THREADS = "messageListenerThreads";
+static const std::string CFG_CONCURRENT_LOOKUP = "concurrentLookupRequest";
+static const std::string CFG_USE_TLS = "useTls";
+static const std::string CFG_TLS_TRUST_CERT = "tlsTrustCertsFilePath";
+static const std::string CFG_TLS_VALIDATE_HOSTNAME = "tlsValidateHostname";
+static const std::string CFG_TLS_ALLOW_INSECURE = "tlsAllowInsecureConnection";
+static const std::string CFG_STATS_INTERVAL = "statsIntervalInSeconds";
+
+Napi::FunctionReference Client::constructor;
+
+Napi::Object Client::Init(Napi::Env env, Napi::Object exports) {
+ Napi::HandleScope scope(env);
+
+ Napi::Function func = DefineClass(
+ env, "Client",
+ {InstanceMethod("createProducer", &Client::CreateProducer),
+ InstanceMethod("subscribe", &Client::Subscribe), InstanceMethod("close", &Client::Close)});
+
+ constructor = Napi::Persistent(func);
+ constructor.SuppressDestruct();
+
+ exports.Set("Client", func);
+ return exports;
+}
+
+Client::Client(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Client>(info) {
+ Napi::Env env = info.Env();
+ Napi::HandleScope scope(env);
+ Napi::Object clientConfig = info[0].As<Napi::Object>();
+
+ if (!clientConfig.Has(CFG_SERVICE_URL) || !clientConfig.Get(CFG_SERVICE_URL).IsString()) {
+ if (clientConfig.Get(CFG_SERVICE_URL).ToString().Utf8Value().empty()) {
+ Napi::Error::New(env, "Service URL is required and must be specified as a string")
+ .ThrowAsJavaScriptException();
+ return;
+ }
+ }
+ Napi::String serviceUrl = clientConfig.Get(CFG_SERVICE_URL).ToString();
+
+ pulsar_client_configuration_t *cClientConfig = pulsar_client_configuration_create();
+
+ if (clientConfig.Has(CFG_OP_TIMEOUT) && clientConfig.Get(CFG_OP_TIMEOUT).IsNumber()) {
+ int32_t operationTimeoutSeconds = clientConfig.Get(CFG_OP_TIMEOUT).ToNumber().Int32Value();
+ if (operationTimeoutSeconds > 0) {
+ pulsar_client_configuration_set_operation_timeout_seconds(cClientConfig, operationTimeoutSeconds);
+ }
+ }
+
+ if (clientConfig.Has(CFG_IO_THREADS) && clientConfig.Get(CFG_IO_THREADS).IsNumber()) {
+ int32_t ioThreads = clientConfig.Get(CFG_IO_THREADS).ToNumber().Int32Value();
+ if (ioThreads > 0) {
+ pulsar_client_configuration_set_io_threads(cClientConfig, ioThreads);
+ }
+ }
+
+ if (clientConfig.Has(CFG_LISTENER_THREADS) && clientConfig.Get(CFG_LISTENER_THREADS).IsNumber()) {
+ int32_t messageListenerThreads = clientConfig.Get(CFG_LISTENER_THREADS).ToNumber().Int32Value();
+ if (messageListenerThreads > 0) {
+ pulsar_client_configuration_set_message_listener_threads(cClientConfig, messageListenerThreads);
+ }
+ }
+
+ if (clientConfig.Has(CFG_CONCURRENT_LOOKUP) && clientConfig.Get(CFG_CONCURRENT_LOOKUP).IsNumber()) {
+ int32_t concurrentLookupRequest = clientConfig.Get(CFG_CONCURRENT_LOOKUP).ToNumber().Int32Value();
+ if (concurrentLookupRequest > 0) {
+ pulsar_client_configuration_set_concurrent_lookup_request(cClientConfig, concurrentLookupRequest);
+ }
+ }
+
+ if (clientConfig.Has(CFG_USE_TLS) && clientConfig.Get(CFG_USE_TLS).IsBoolean()) {
+ Napi::Boolean useTls = clientConfig.Get(CFG_USE_TLS).ToBoolean();
+ pulsar_client_configuration_set_use_tls(cClientConfig, useTls.Value());
+ }
+
+ if (clientConfig.Has(CFG_TLS_TRUST_CERT) && clientConfig.Get(CFG_TLS_TRUST_CERT).IsString()) {
+ Napi::String tlsTrustCertsFilePath = clientConfig.Get(CFG_TLS_TRUST_CERT).ToString();
+ pulsar_client_configuration_set_tls_trust_certs_file_path(cClientConfig,
+ tlsTrustCertsFilePath.Utf8Value().c_str());
+ }
+
+ if (clientConfig.Has(CFG_TLS_VALIDATE_HOSTNAME) &&
+ clientConfig.Get(CFG_TLS_VALIDATE_HOSTNAME).IsBoolean()) {
+ Napi::Boolean tlsValidateHostname = clientConfig.Get(CFG_TLS_VALIDATE_HOSTNAME).ToBoolean();
+ pulsar_client_configuration_set_validate_hostname(cClientConfig, tlsValidateHostname.Value());
+ }
+
+ if (clientConfig.Has(CFG_TLS_ALLOW_INSECURE) && clientConfig.Get(CFG_TLS_ALLOW_INSECURE).IsBoolean()) {
+ Napi::Boolean tlsAllowInsecureConnection = clientConfig.Get(CFG_TLS_ALLOW_INSECURE).ToBoolean();
+ pulsar_client_configuration_set_tls_allow_insecure_connection(cClientConfig,
+ tlsAllowInsecureConnection.Value());
+ }
+
+ if (clientConfig.Has(CFG_STATS_INTERVAL) && clientConfig.Get(CFG_STATS_INTERVAL).IsNumber()) {
+ uint32_t statsIntervalInSeconds = clientConfig.Get(CFG_STATS_INTERVAL).ToNumber().Uint32Value();
+ if (statsIntervalInSeconds > 0) {
+ pulsar_client_configuration_set_stats_interval_in_seconds(cClientConfig, statsIntervalInSeconds);
+ }
+ }
+
+ this->cClient = pulsar_client_create(serviceUrl.Utf8Value().c_str(), cClientConfig);
+ pulsar_client_configuration_free(cClientConfig);
+}
+
+Client::~Client() { pulsar_client_free(this->cClient); }
+
+Napi::Value Client::CreateProducer(const Napi::CallbackInfo &info) {
+ return Producer::NewInstance(info, this->cClient);
+}
+
+Napi::Value Client::Subscribe(const Napi::CallbackInfo &info) {
+ return Consumer::NewInstance(info, this->cClient);
+}
+
+class ClientCloseWorker : public Napi::AsyncWorker {
+ public:
+ ClientCloseWorker(const Napi::Promise::Deferred &deferred, pulsar_client_t *cClient)
+ : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
+ deferred(deferred),
+ cClient(cClient) {}
+ ~ClientCloseWorker() {}
+ void Execute() {
+ pulsar_result result = pulsar_client_close(this->cClient);
+ if (result != pulsar_result_Ok) SetError(pulsar_result_str(result));
+ }
+ void OnOK() { this->deferred.Resolve(Env().Null()); }
+ void OnError(const Napi::Error &e) {
+ this->deferred.Reject(
+ Napi::Error::New(Env(), std::string("Failed to close client: ") + e.Message()).Value());
+ }
+
+ private:
+ Napi::Promise::Deferred deferred;
+ pulsar_client_t *cClient;
+};
+
+Napi::Value Client::Close(const Napi::CallbackInfo &info) {
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
+ ClientCloseWorker *wk = new ClientCloseWorker(deferred, this->cClient);
+ wk->Queue();
+ return deferred.Promise();
+}
diff --git a/src/Client.h b/src/Client.h
new file mode 100644
index 0000000..bc92125
--- /dev/null
+++ b/src/Client.h
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include <napi.h>
+#include <pulsar/c/client.h>
+
+class Client : public Napi::ObjectWrap<Client> {
+ public:
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
+ Client(const Napi::CallbackInfo &info);
+ ~Client();
+
+ private:
+ static Napi::FunctionReference constructor;
+ pulsar_client_t *cClient;
+
+ Napi::Value CreateProducer(const Napi::CallbackInfo &info);
+ Napi::Value Subscribe(const Napi::CallbackInfo &info);
+ Napi::Value Close(const Napi::CallbackInfo &info);
+};
+
+#endif
diff --git a/src/Consumer.cc b/src/Consumer.cc
new file mode 100644
index 0000000..85e0fbf
--- /dev/null
+++ b/src/Consumer.cc
@@ -0,0 +1,188 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "Consumer.h"
+#include "ConsumerConfig.h"
+#include "Message.h"
+#include "MessageId.h"
+#include <pulsar/c/result.h>
+
+Napi::FunctionReference Consumer::constructor;
+
+void Consumer::Init(Napi::Env env, Napi::Object exports) {
+ Napi::HandleScope scope(env);
+
+ Napi::Function func = DefineClass(env, "Consumer",
+ {
+ InstanceMethod("receive", &Consumer::Receive),
+ InstanceMethod("acknowledge", &Consumer::Acknowledge),
+ InstanceMethod("acknowledgeId", &Consumer::AcknowledgeId),
+ InstanceMethod("close", &Consumer::Close),
+ });
+
+ constructor = Napi::Persistent(func);
+ constructor.SuppressDestruct();
+}
+
+void Consumer::SetCConsumer(pulsar_consumer_t *cConsumer) { this->cConsumer = cConsumer; }
+
+Consumer::Consumer(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Consumer>(info) {}
+
+class ConsumerNewInstanceWorker : public Napi::AsyncWorker {
+ public:
+ ConsumerNewInstanceWorker(const Napi::Promise::Deferred &deferred, pulsar_client_t *cClient,
+ ConsumerConfig *consumerConfig)
+ : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
+ deferred(deferred),
+ cClient(cClient),
+ consumerConfig(consumerConfig) {}
+ ~ConsumerNewInstanceWorker() {}
+ void Execute() {
+ const std::string &topic = this->consumerConfig->GetTopic();
+ if (topic.empty()) {
+ SetError(
+ std::string("Topic is required and must be specified as a string when creating consumer"));
+ return;
+ }
+ const std::string &subscription = this->consumerConfig->GetSubscription();
+ if (subscription.empty()) {
+ SetError(std::string(
+ "Subscription is required and must be specified as a string when creating consumer"));
+ return;
+ }
+ int32_t ackTimeoutMs = this->consumerConfig->GetAckTimeoutMs();
+ if (ackTimeoutMs != 0 && ackTimeoutMs < MIN_ACK_TIMEOUT_MILLIS) {
+ std::string msg("Ack timeout should be 0 or greater than or equal to " +
+ std::to_string(MIN_ACK_TIMEOUT_MILLIS));
+ SetError(msg);
+ return;
+ }
+
+ pulsar_result result =
+ pulsar_client_subscribe(this->cClient, topic.c_str(), subscription.c_str(),
+ this->consumerConfig->GetCConsumerConfig(), &(this->cConsumer));
+ delete this->consumerConfig;
+ if (result != pulsar_result_Ok) {
+ SetError(std::string("Failed to create consumer: ") + pulsar_result_str(result));
+ return;
+ }
+ }
+ void OnOK() {
+ Napi::Object obj = Consumer::constructor.New({});
+ Consumer *consumer = Consumer::Unwrap(obj);
+ consumer->SetCConsumer(this->cConsumer);
+ this->deferred.Resolve(obj);
+ }
+ void OnError(const Napi::Error &e) {
+ this->deferred.Reject(Napi::Error::New(Env(), e.Message()).Value());
+ }
+
+ private:
+ Napi::Promise::Deferred deferred;
+ pulsar_client_t *cClient;
+ ConsumerConfig *consumerConfig;
+ pulsar_consumer_t *cConsumer;
+};
+
+Napi::Value Consumer::NewInstance(const Napi::CallbackInfo &info, pulsar_client_t *cClient) {
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
+ Napi::Object config = info[0].As<Napi::Object>();
+ ConsumerConfig *consumerConfig = new ConsumerConfig(config);
+ ConsumerNewInstanceWorker *wk = new ConsumerNewInstanceWorker(deferred, cClient, consumerConfig);
+ wk->Queue();
+ return deferred.Promise();
+}
+
+class ConsumerReceiveWorker : public Napi::AsyncWorker {
+ public:
+ ConsumerReceiveWorker(const Napi::Promise::Deferred &deferred, pulsar_consumer_t *cConsumer)
+ : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
+ deferred(deferred),
+ cConsumer(cConsumer) {}
+ ~ConsumerReceiveWorker() {}
+ void Execute() {
+ pulsar_result result = pulsar_consumer_receive(this->cConsumer, &(this->cMessage));
+
+ if (result != pulsar_result_Ok) {
+ SetError(std::string("Failed to received message ") + pulsar_result_str(result));
+ }
+ }
+ void OnOK() {
+ Napi::Object obj = Message::NewInstance({}, this->cMessage);
+ this->deferred.Resolve(obj);
+ }
+ void OnError(const Napi::Error &e) {
+ this->deferred.Reject(Napi::Error::New(Env(), e.Message()).Value());
+ }
+
+ private:
+ Napi::Promise::Deferred deferred;
+ pulsar_consumer_t *cConsumer;
+ pulsar_message_t *cMessage;
+};
+
+Napi::Value Consumer::Receive(const Napi::CallbackInfo &info) {
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
+ ConsumerReceiveWorker *wk = new ConsumerReceiveWorker(deferred, this->cConsumer);
+ wk->Queue();
+ return deferred.Promise();
+}
+
+void Consumer::Acknowledge(const Napi::CallbackInfo &info) {
+ Napi::Object obj = info[0].As<Napi::Object>();
+ Message *msg = Message::Unwrap(obj);
+ pulsar_consumer_acknowledge_async(this->cConsumer, msg->GetCMessage(), NULL, NULL);
+}
+
+void Consumer::AcknowledgeId(const Napi::CallbackInfo &info) {
+ Napi::Object obj = info[0].As<Napi::Object>();
+ MessageId *msgId = MessageId::Unwrap(obj);
+ pulsar_consumer_acknowledge_async_id(this->cConsumer, msgId->GetCMessageId(), NULL, NULL);
+}
+
+class ConsumerCloseWorker : public Napi::AsyncWorker {
+ public:
+ ConsumerCloseWorker(const Napi::Promise::Deferred &deferred, pulsar_consumer_t *cConsumer)
+ : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
+ deferred(deferred),
+ cConsumer(cConsumer) {}
+ ~ConsumerCloseWorker() {}
+ void Execute() {
+ pulsar_result result = pulsar_consumer_close(this->cConsumer);
+ if (result != pulsar_result_Ok) SetError(pulsar_result_str(result));
+ }
+ void OnOK() { this->deferred.Resolve(Env().Null()); }
+ void OnError(const Napi::Error &e) {
+ this->deferred.Reject(
+ Napi::Error::New(Env(), std::string("Failed to close consumer: ") + e.Message()).Value());
+ }
+
+ private:
+ Napi::Promise::Deferred deferred;
+ pulsar_consumer_t *cConsumer;
+};
+
+Napi::Value Consumer::Close(const Napi::CallbackInfo &info) {
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
+ ConsumerCloseWorker *wk = new ConsumerCloseWorker(deferred, this->cConsumer);
+ wk->Queue();
+ return deferred.Promise();
+}
+
+Consumer::~Consumer() { pulsar_consumer_free(this->cConsumer); }
diff --git a/src/Consumer.h b/src/Consumer.h
new file mode 100644
index 0000000..8e77df3
--- /dev/null
+++ b/src/Consumer.h
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef CONSUMER_H
+#define CONSUMER_H
+
+#include <napi.h>
+#include <pulsar/c/client.h>
+
+class Consumer : public Napi::ObjectWrap<Consumer> {
+ public:
+ static void Init(Napi::Env env, Napi::Object exports);
+ static Napi::Value NewInstance(const Napi::CallbackInfo &info, pulsar_client_t *cClient);
+ static Napi::FunctionReference constructor;
+ Consumer(const Napi::CallbackInfo &info);
+ ~Consumer();
+ void SetCConsumer(pulsar_consumer_t *cConsumer);
+
+ private:
+ pulsar_consumer_t *cConsumer;
+
+ Napi::Value Receive(const Napi::CallbackInfo &info);
+ void Acknowledge(const Napi::CallbackInfo &info);
+ void AcknowledgeId(const Napi::CallbackInfo &info);
+ Napi::Value Close(const Napi::CallbackInfo &info);
+};
+
+#endif
diff --git a/src/ConsumerConfig.cc b/src/ConsumerConfig.cc
new file mode 100644
index 0000000..78f1605
--- /dev/null
+++ b/src/ConsumerConfig.cc
@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "ConsumerConfig.h"
+#include <pulsar/c/consumer_configuration.h>
+#include <map>
+
+static const std::string CFG_TOPIC = "topic";
+static const std::string CFG_SUBSCRIPTION = "subscription";
+static const std::string CFG_SUBSCRIPTION_TYPE = "subscriptionType";
+static const std::string CFG_ACK_TIMEOUT = "ackTimeoutMs";
+static const std::string CFG_RECV_QUEUE = "receiverQueueSize";
+static const std::string CFG_RECV_QUEUE_ACROSS_PARTITIONS = "receiverQueueSizeAcrossPartitions";
+static const std::string CFG_CONSUMER_NAME = "consumerName";
+static const std::string CFG_PROPS = "properties";
+
+static const std::map<std::string, pulsar_consumer_type> SUBSCRIPTION_TYPE = {
+ {"Exclusive", pulsar_ConsumerExclusive},
+ {"Shared", pulsar_ConsumerShared},
+ {"Failover", pulsar_ConsumerFailover}};
+
+ConsumerConfig::ConsumerConfig(const Napi::Object &consumerConfig)
+ : topic(""), subscription(""), ackTimeoutMs(0) {
+ this->cConsumerConfig = pulsar_consumer_configuration_create();
+
+ if (consumerConfig.Has(CFG_TOPIC) && consumerConfig.Get(CFG_TOPIC).IsString()) {
+ this->topic = consumerConfig.Get(CFG_TOPIC).ToString().Utf8Value();
+ }
+
+ if (consumerConfig.Has(CFG_SUBSCRIPTION) && consumerConfig.Get(CFG_SUBSCRIPTION).IsString()) {
+ this->subscription = consumerConfig.Get(CFG_SUBSCRIPTION).ToString().Utf8Value();
+ }
+
+ if (consumerConfig.Has(CFG_SUBSCRIPTION_TYPE) && consumerConfig.Get(CFG_SUBSCRIPTION_TYPE).IsString()) {
+ std::string subscriptionType = consumerConfig.Get(CFG_SUBSCRIPTION_TYPE).ToString().Utf8Value();
+ if (SUBSCRIPTION_TYPE.count(subscriptionType)) {
+ pulsar_consumer_configuration_set_consumer_type(this->cConsumerConfig,
+ SUBSCRIPTION_TYPE.at(subscriptionType));
+ }
+ }
+
+ if (consumerConfig.Has(CFG_CONSUMER_NAME) && consumerConfig.Get(CFG_CONSUMER_NAME).IsString()) {
+ std::string consumerName = consumerConfig.Get(CFG_CONSUMER_NAME).ToString().Utf8Value();
+ if (!consumerName.empty())
+ pulsar_consumer_set_consumer_name(this->cConsumerConfig, consumerName.c_str());
+ }
+
+ if (consumerConfig.Has(CFG_ACK_TIMEOUT) && consumerConfig.Get(CFG_ACK_TIMEOUT).IsNumber()) {
+ this->ackTimeoutMs = consumerConfig.Get(CFG_ACK_TIMEOUT).ToNumber().Int64Value();
+ if (this->ackTimeoutMs == 0 || this->ackTimeoutMs >= MIN_ACK_TIMEOUT_MILLIS) {
+ pulsar_consumer_set_unacked_messages_timeout_ms(this->cConsumerConfig, this->ackTimeoutMs);
+ }
+ }
+
+ if (consumerConfig.Has(CFG_RECV_QUEUE) && consumerConfig.Get(CFG_RECV_QUEUE).IsNumber()) {
+ int32_t receiverQueueSize = consumerConfig.Get(CFG_RECV_QUEUE).ToNumber().Int32Value();
+ if (receiverQueueSize >= 0) {
+ pulsar_consumer_configuration_set_receiver_queue_size(this->cConsumerConfig, receiverQueueSize);
+ }
+ }
+
+ if (consumerConfig.Has(CFG_RECV_QUEUE_ACROSS_PARTITIONS) &&
+ consumerConfig.Get(CFG_RECV_QUEUE_ACROSS_PARTITIONS).IsNumber()) {
+ int32_t receiverQueueSizeAcrossPartitions =
+ consumerConfig.Get(CFG_RECV_QUEUE_ACROSS_PARTITIONS).ToNumber().Int32Value();
+ if (receiverQueueSizeAcrossPartitions >= 0) {
+ pulsar_consumer_set_max_total_receiver_queue_size_across_partitions(
+ this->cConsumerConfig, receiverQueueSizeAcrossPartitions);
+ }
+ }
+
+ if (consumerConfig.Has(CFG_PROPS) && consumerConfig.Get(CFG_PROPS).IsObject()) {
+ Napi::Object propObj = consumerConfig.Get(CFG_PROPS).ToObject();
+ Napi::Array arr = propObj.GetPropertyNames();
+ int size = arr.Length();
+ for (int i = 0; i < size; i++) {
+ std::string key = arr.Get(i).ToString().Utf8Value();
+ std::string value = propObj.Get(key).ToString().Utf8Value();
+ pulsar_consumer_configuration_set_property(this->cConsumerConfig, key.c_str(), value.c_str());
+ }
+ }
+}
+
+ConsumerConfig::~ConsumerConfig() { pulsar_consumer_configuration_free(this->cConsumerConfig); }
+
+pulsar_consumer_configuration_t *ConsumerConfig::GetCConsumerConfig() { return this->cConsumerConfig; }
+
+std::string ConsumerConfig::GetTopic() { return this->topic; }
+std::string ConsumerConfig::GetSubscription() { return this->subscription; }
+int64_t ConsumerConfig::GetAckTimeoutMs() { return this->ackTimeoutMs; }
diff --git a/src/ConsumerConfig.h b/src/ConsumerConfig.h
new file mode 100644
index 0000000..00c890e
--- /dev/null
+++ b/src/ConsumerConfig.h
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef CONSUMER_CONFIG_H
+#define CONSUMER_CONFIG_H
+
+#include <napi.h>
+#include <pulsar/c/consumer_configuration.h>
+
+#define MIN_ACK_TIMEOUT_MILLIS 10000
+
+class ConsumerConfig {
+ public:
+ ConsumerConfig(const Napi::Object &consumerConfig);
+ ~ConsumerConfig();
+ pulsar_consumer_configuration_t *GetCConsumerConfig();
+ std::string GetTopic();
+ std::string GetSubscription();
+ int64_t GetAckTimeoutMs();
+
+ private:
+ pulsar_consumer_configuration_t *cConsumerConfig;
+ std::string topic;
+ std::string subscription;
+ int64_t ackTimeoutMs;
+};
+
+#endif
diff --git a/src/Message.cc b/src/Message.cc
new file mode 100644
index 0000000..9a0129e
--- /dev/null
+++ b/src/Message.cc
@@ -0,0 +1,197 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "Message.h"
+#include "MessageId.h"
+#include <pulsar/c/message.h>
+
+static const std::string CFG_DATA = "data";
+static const std::string CFG_PROPS = "properties";
+static const std::string CFG_EVENT_TIME = "eventTimestamp";
+static const std::string CFG_SEQUENCE_ID = "sequenceId";
+static const std::string CFG_PARTITION_KEY = "partitionKey";
+static const std::string CFG_REPL_CLUSTERS = "replicationClusters";
+
+Napi::FunctionReference Message::constructor;
+
+Napi::Object Message::Init(Napi::Env env, Napi::Object exports) {
+ Napi::HandleScope scope(env);
+
+ Napi::Function func = DefineClass(
+ env, "Message",
+ {InstanceMethod("getTopicName", &Message::GetTopicName),
+ InstanceMethod("getProperties", &Message::GetProperties),
+ InstanceMethod("getData", &Message::GetData), InstanceMethod("getMessageId", &Message::GetMessageId),
+ InstanceMethod("getPublishTimestamp", &Message::GetPublishTimestamp),
+ InstanceMethod("getEventTimestamp", &Message::GetEventTimestamp),
+ InstanceMethod("getPartitionKey", &Message::GetPartitionKey)});
+
+ constructor = Napi::Persistent(func);
+ constructor.SuppressDestruct();
+
+ exports.Set("Message", func);
+ return exports;
+}
+
+Napi::Object Message::NewInstance(Napi::Value arg, pulsar_message_t *cMessage) {
+ Napi::Object obj = constructor.New({});
+ Message *msg = Unwrap(obj);
+ msg->cMessage = cMessage;
+ return obj;
+}
+
+Message::Message(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Message>(info), cMessage(nullptr) {}
+
+pulsar_message_t *Message::GetCMessage() { return this->cMessage; }
+
+Napi::Value Message::GetTopicName(const Napi::CallbackInfo &info) {
+ Napi::Env env = info.Env();
+ if (!ValidateCMessage(env)) {
+ return env.Null();
+ }
+ return Napi::String::New(env, pulsar_message_get_topic_name(this->cMessage));
+}
+
+Napi::Value Message::GetProperties(const Napi::CallbackInfo &info) {
+ Napi::Env env = info.Env();
+ if (!ValidateCMessage(env)) {
+ return env.Null();
+ }
+ Napi::Array arr = Napi::Array::New(env);
+ pulsar_string_map_t *cProperties = pulsar_message_get_properties(this->cMessage);
+ int size = pulsar_string_map_size(cProperties);
+ for (int i = 0; i < size; i++) {
+ arr.Set(pulsar_string_map_get_key(cProperties, i), pulsar_string_map_get_value(cProperties, i));
+ }
+ return arr;
+}
+
+Napi::Value Message::GetData(const Napi::CallbackInfo &info) {
+ Napi::Env env = info.Env();
+ if (!ValidateCMessage(env)) {
+ return env.Null();
+ }
+ void *data = const_cast<void *>(pulsar_message_get_data(this->cMessage));
+ size_t size = (size_t)pulsar_message_get_length(this->cMessage);
+ return Napi::Buffer<char>::New(env, (char *)data, size);
+}
+
+Napi::Value Message::GetMessageId(const Napi::CallbackInfo &info) {
+ Napi::Env env = info.Env();
+ if (!ValidateCMessage(env)) {
+ return env.Null();
+ }
+ return MessageId::NewInstanceFromMessage(info, this->cMessage);
+}
+
+Napi::Value Message::GetEventTimestamp(const Napi::CallbackInfo &info) {
+ Napi::Env env = info.Env();
+ if (!ValidateCMessage(env)) {
+ return env.Null();
+ }
+ return Napi::Number::New(env, pulsar_message_get_event_timestamp(this->cMessage));
+}
+
+Napi::Value Message::GetPublishTimestamp(const Napi::CallbackInfo &info) {
+ Napi::Env env = info.Env();
+ if (!ValidateCMessage(env)) {
+ return env.Null();
+ }
+ return Napi::Number::New(env, pulsar_message_get_publish_timestamp(this->cMessage));
+}
+
+Napi::Value Message::GetPartitionKey(const Napi::CallbackInfo &info) {
+ Napi::Env env = info.Env();
+ if (!ValidateCMessage(env)) {
+ return env.Null();
+ }
+ return Napi::String::New(env, pulsar_message_get_partitionKey(this->cMessage));
+}
+
+bool Message::ValidateCMessage(Napi::Env env) {
+ if (this->cMessage) {
+ return true;
+ } else {
+ Napi::Error::New(env, "Message has not been built").ThrowAsJavaScriptException();
+ return false;
+ }
+}
+
+pulsar_message_t *Message::BuildMessage(Napi::Object conf) {
+ pulsar_message_t *cMessage = pulsar_message_create();
+
+ if (conf.Has(CFG_DATA) && conf.Get(CFG_DATA).IsBuffer()) {
+ Napi::Buffer<char> buf = conf.Get(CFG_DATA).As<Napi::Buffer<char>>();
+ char *data = buf.Data();
+ pulsar_message_set_content(cMessage, data, buf.Length());
+ }
+
+ if (conf.Has(CFG_PROPS) && conf.Get(CFG_PROPS).IsObject()) {
+ Napi::Object propObj = conf.Get(CFG_PROPS).ToObject();
+ Napi::Array arr = propObj.GetPropertyNames();
+ int size = arr.Length();
+ for (int i = 0; i < size; i++) {
+ Napi::String key = arr.Get(i).ToString();
+ Napi::String value = propObj.Get(key).ToString();
+ pulsar_message_set_property(cMessage, key.Utf8Value().c_str(), value.Utf8Value().c_str());
+ }
+ }
+
+ if (conf.Has(CFG_EVENT_TIME) && conf.Get(CFG_EVENT_TIME).IsNumber()) {
+ int64_t eventTimestamp = conf.Get(CFG_EVENT_TIME).ToNumber().Int64Value();
+ if (eventTimestamp >= 0) {
+ pulsar_message_set_event_timestamp(cMessage, eventTimestamp);
+ }
+ }
+
+ if (conf.Has(CFG_SEQUENCE_ID) && conf.Get(CFG_SEQUENCE_ID).IsNumber()) {
+ Napi::Number sequenceId = conf.Get(CFG_SEQUENCE_ID).ToNumber();
+ pulsar_message_set_sequence_id(cMessage, sequenceId.Int64Value());
+ }
+
+ if (conf.Has(CFG_PARTITION_KEY) && conf.Get(CFG_PARTITION_KEY).IsString()) {
+ Napi::String partitionKey = conf.Get(CFG_PARTITION_KEY).ToString();
+ pulsar_message_set_partition_key(cMessage, partitionKey.Utf8Value().c_str());
+ }
+
+ if (conf.Has(CFG_REPL_CLUSTERS) && conf.Get(CFG_REPL_CLUSTERS).IsArray()) {
+ Napi::Array clusters = conf.Get(CFG_REPL_CLUSTERS).As<Napi::Array>();
+ // Empty list means to disable replication
+ int length = clusters.Length();
+ if (length == 0) {
+ pulsar_message_disable_replication(cMessage, 1);
+ } else {
+ char **arr = NewStringArray(length);
+ for (int i = 0; i < length; i++) {
+ SetString(arr, clusters.Get(i).ToString().Utf8Value().c_str(), i);
+ }
+ // TODO: temoporalily commented out unless 2.3.1 which includes interface change of
+ // pulsar_message_set_replication_clusters (#3729) is released
+ // pulsar_message_set_replication_clusters(cMessage, (const char **)arr, length);
+ FreeStringArray(arr, length);
+ }
+ }
+ return cMessage;
+}
+
+Message::~Message() {
+ if (this->cMessage != nullptr) {
+ pulsar_message_free(this->cMessage);
+ }
+}
diff --git a/src/Message.h b/src/Message.h
new file mode 100644
index 0000000..8992f9c
--- /dev/null
+++ b/src/Message.h
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef MESSAGE_H
+#define MESSAGE_H
+
+#include <napi.h>
+#include <pulsar/c/message.h>
+
+class Message : public Napi::ObjectWrap<Message> {
+ public:
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
+ static Napi::Object NewInstance(Napi::Value arg, pulsar_message_t *cMessage);
+ static pulsar_message_t *BuildMessage(Napi::Object conf);
+ Message(const Napi::CallbackInfo &info);
+ ~Message();
+ pulsar_message_t *GetCMessage();
+
+ private:
+ static Napi::FunctionReference constructor;
+
+ pulsar_message_t *cMessage;
+
+ Napi::Value GetTopicName(const Napi::CallbackInfo &info);
+ Napi::Value GetProperties(const Napi::CallbackInfo &info);
+ Napi::Value GetData(const Napi::CallbackInfo &info);
+ Napi::Value GetMessageId(const Napi::CallbackInfo &info);
+ Napi::Value GetPublishTimestamp(const Napi::CallbackInfo &info);
+ Napi::Value GetEventTimestamp(const Napi::CallbackInfo &info);
+ Napi::Value GetPartitionKey(const Napi::CallbackInfo &info);
+ bool ValidateCMessage(Napi::Env env);
+
+ static char **NewStringArray(int size) { return (char **)calloc(sizeof(char *), size); }
+ static void SetString(char **array, const char *str, int n) {
+ char *copied = (char *)calloc(strlen(str) + 1, sizeof(char));
+ strcpy(copied, str);
+ array[n] = copied;
+ }
+ static void FreeStringArray(char **array, int size) {
+ int i;
+ for (i = 0; i < size; i++) {
+ free(array[i]);
+ }
+ free(array);
+ }
+};
+
+#endif
diff --git a/src/MessageId.cc b/src/MessageId.cc
new file mode 100644
index 0000000..3a95f43
--- /dev/null
+++ b/src/MessageId.cc
@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "MessageId.h"
+#include <pulsar/c/message.h>
+#include <pulsar/c/message_id.h>
+
+Napi::FunctionReference MessageId::constructor;
+
+Napi::Object MessageId::Init(Napi::Env env, Napi::Object exports) {
+ Napi::HandleScope scope(env);
+
+ Napi::Function func = DefineClass(env, "MessageId",
+ {
+ StaticMethod("earliest", &MessageId::Earliest, napi_static),
+ StaticMethod("latest", &MessageId::Latest, napi_static),
+ StaticMethod("finalize", &MessageId::Finalize, napi_static),
+ InstanceMethod("toString", &MessageId::ToString),
+ });
+
+ constructor = Napi::Persistent(func);
+ constructor.SuppressDestruct();
+
+ exports.Set("MessageId", func);
+ return exports;
+}
+
+MessageId::MessageId(const Napi::CallbackInfo &info) : Napi::ObjectWrap<MessageId>(info) {
+ Napi::Env env = info.Env();
+ Napi::HandleScope scope(env);
+}
+
+Napi::Object MessageId::NewInstanceFromMessage(const Napi::CallbackInfo &info, pulsar_message_t *cMessage) {
+ Napi::Object obj = NewInstance(info[0]);
+ MessageId *msgId = Unwrap(obj);
+ msgId->cMessageId = pulsar_message_get_message_id(cMessage);
+ return obj;
+}
+
+Napi::Object MessageId::NewInstance(Napi::Value arg) {
+ Napi::Object obj = constructor.New({arg});
+ return obj;
+}
+
+void MessageId::Finalize(const Napi::CallbackInfo &info) {
+ Napi::Object obj = info[0].As<Napi::Object>();
+ MessageId *msgId = Unwrap(obj);
+ pulsar_message_id_free(msgId->cMessageId);
+}
+
+Napi::Value MessageId::Earliest(const Napi::CallbackInfo &info) {
+ Napi::Object obj = NewInstance(info[0]);
+ MessageId *msgId = Unwrap(obj);
+ msgId->cMessageId = (pulsar_message_id_t *)pulsar_message_id_earliest();
+ return obj;
+}
+
+Napi::Value MessageId::Latest(const Napi::CallbackInfo &info) {
+ Napi::Object obj = NewInstance(info[0]);
+ MessageId *msgId = Unwrap(obj);
+ msgId->cMessageId = (pulsar_message_id_t *)pulsar_message_id_latest();
+ return obj;
+}
+
+pulsar_message_id_t *MessageId::GetCMessageId() { return this->cMessageId; }
+
+Napi::Value MessageId::ToString(const Napi::CallbackInfo &info) {
+ return Napi::String::New(info.Env(), pulsar_message_id_str(this->cMessageId));
+}
+
+MessageId::~MessageId() { pulsar_message_id_free(this->cMessageId); }
diff --git a/src/MessageId.h b/src/MessageId.h
new file mode 100644
index 0000000..761f04b
--- /dev/null
+++ b/src/MessageId.h
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef MESSAGE_ID_H
+#define MESSAGE_ID_H
+
+#include <napi.h>
+#include <pulsar/c/message.h>
+#include <pulsar/c/message_id.h>
+
+class MessageId : public Napi::ObjectWrap<MessageId> {
+ public:
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
+ static Napi::Object NewInstance(Napi::Value arg);
+ static Napi::Object NewInstanceFromMessage(const Napi::CallbackInfo &info, pulsar_message_t *cMessage);
+ static Napi::Value Earliest(const Napi::CallbackInfo &info);
+ static Napi::Value Latest(const Napi::CallbackInfo &info);
+ static void Finalize(const Napi::CallbackInfo &info);
+ MessageId(const Napi::CallbackInfo &info);
+ ~MessageId();
+ pulsar_message_id_t *GetCMessageId();
+
+ private:
+ static Napi::FunctionReference constructor;
+ pulsar_message_id_t *cMessageId;
+
+ Napi::Value ToString(const Napi::CallbackInfo &info);
+};
+
+#endif
diff --git a/src/Producer.cc b/src/Producer.cc
new file mode 100644
index 0000000..9bdb5d4
--- /dev/null
+++ b/src/Producer.cc
@@ -0,0 +1,155 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "Producer.h"
+#include "ProducerConfig.h"
+#include "Message.h"
+#include <pulsar/c/result.h>
+#include <memory>
+Napi::FunctionReference Producer::constructor;
+
+void Producer::Init(Napi::Env env, Napi::Object exports) {
+ Napi::HandleScope scope(env);
+
+ Napi::Function func =
+ DefineClass(env, "Producer",
+ {InstanceMethod("send", &Producer::Send), InstanceMethod("close", &Producer::Close)});
+
+ constructor = Napi::Persistent(func);
+ constructor.SuppressDestruct();
+}
+
+void Producer::SetCProducer(pulsar_producer_t *cProducer) { this->cProducer = cProducer; }
+
+class ProducerNewInstanceWorker : public Napi::AsyncWorker {
+ public:
+ ProducerNewInstanceWorker(const Napi::Promise::Deferred &deferred, pulsar_client_t *cClient,
+ ProducerConfig *producerConfig)
+ : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
+ deferred(deferred),
+ cClient(cClient),
+ producerConfig(producerConfig) {}
+ ~ProducerNewInstanceWorker() {}
+ void Execute() {
+ const std::string &topic = this->producerConfig->GetTopic();
+ if (topic.empty()) {
+ SetError(
+ std::string("Topic is required and must be specified as a string when creating producer"));
+ return;
+ }
+
+ pulsar_result result = pulsar_client_create_producer(
+ this->cClient, topic.c_str(), this->producerConfig->GetCProducerConfig(), &(this->cProducer));
+ delete this->producerConfig;
+ if (result != pulsar_result_Ok) {
+ SetError(std::string("Failed to create producer: ") + pulsar_result_str(result));
+ return;
+ }
+ }
+ void OnOK() {
+ Napi::Object obj = Producer::constructor.New({});
+ Producer *producer = Producer::Unwrap(obj);
+ producer->SetCProducer(this->cProducer);
+ this->deferred.Resolve(obj);
+ }
+ void OnError(const Napi::Error &e) {
+ this->deferred.Reject(Napi::Error::New(Env(), e.Message()).Value());
+ }
+
+ private:
+ Napi::Promise::Deferred deferred;
+ pulsar_client_t *cClient;
+ ProducerConfig *producerConfig;
+ pulsar_producer_t *cProducer;
+};
+
+Napi::Value Producer::NewInstance(const Napi::CallbackInfo &info, pulsar_client_t *cClient) {
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
+ Napi::Object config = info[0].As<Napi::Object>();
+ ProducerConfig *producerConfig = new ProducerConfig(config);
+ ProducerNewInstanceWorker *wk = new ProducerNewInstanceWorker(deferred, cClient, producerConfig);
+ wk->Queue();
+ return deferred.Promise();
+}
+
+Producer::Producer(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Producer>(info) {}
+
+class ProducerSendWorker : public Napi::AsyncWorker {
+ public:
+ ProducerSendWorker(const Napi::Promise::Deferred &deferred, pulsar_producer_t *cProducer,
+ pulsar_message_t *cMessage)
+ : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
+ deferred(deferred),
+ cProducer(cProducer),
+ cMessage(cMessage) {}
+ ~ProducerSendWorker() { pulsar_message_free(this->cMessage); }
+ void Execute() {
+ pulsar_result result = pulsar_producer_send(this->cProducer, this->cMessage);
+ if (result != pulsar_result_Ok) SetError(pulsar_result_str(result));
+ }
+ void OnOK() { this->deferred.Resolve(Env().Null()); }
+ void OnError(const Napi::Error &e) {
+ this->deferred.Reject(
+ Napi::Error::New(Env(), std::string("Failed to send message: ") + e.Message()).Value());
+ }
+
+ private:
+ Napi::Promise::Deferred deferred;
+ pulsar_producer_t *cProducer;
+ pulsar_message_t *cMessage;
+};
+
+Napi::Value Producer::Send(const Napi::CallbackInfo &info) {
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
+ pulsar_message_t *cMessage = Message::BuildMessage(info[0].As<Napi::Object>());
+ ProducerSendWorker *wk = new ProducerSendWorker(deferred, this->cProducer, cMessage);
+ wk->Queue();
+ return deferred.Promise();
+}
+
+class ProducerCloseWorker : public Napi::AsyncWorker {
+ public:
+ ProducerCloseWorker(const Napi::Promise::Deferred &deferred, pulsar_producer_t *cProducer)
+ : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
+ deferred(deferred),
+ cProducer(cProducer) {}
+ ~ProducerCloseWorker() {}
+ void Execute() {
+ pulsar_result result = pulsar_producer_close(this->cProducer);
+ if (result != pulsar_result_Ok) SetError(pulsar_result_str(result));
+ }
+ void OnOK() { this->deferred.Resolve(Env().Null()); }
+ void OnError(const Napi::Error &e) {
+ this->deferred.Reject(
+ Napi::Error::New(Env(), std::string("Failed to close producer: ") + e.Message()).Value());
+ }
+
+ private:
+ Napi::Promise::Deferred deferred;
+ pulsar_producer_t *cProducer;
+};
+
+Napi::Value Producer::Close(const Napi::CallbackInfo &info) {
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
+ ProducerCloseWorker *wk = new ProducerCloseWorker(deferred, this->cProducer);
+ wk->Queue();
+ return deferred.Promise();
+}
+
+Producer::~Producer() { pulsar_producer_free(this->cProducer); }
diff --git a/src/Producer.h b/src/Producer.h
new file mode 100644
index 0000000..c758ce4
--- /dev/null
+++ b/src/Producer.h
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef PRODUCER_H
+#define PRODUCER_H
+
+#include <napi.h>
+#include <pulsar/c/client.h>
+#include <pulsar/c/producer.h>
+
+class Producer : public Napi::ObjectWrap<Producer> {
+ public:
+ static void Init(Napi::Env env, Napi::Object exports);
+ static Napi::Value NewInstance(const Napi::CallbackInfo &info, pulsar_client_t *cClient);
+ static Napi::FunctionReference constructor;
+ Producer(const Napi::CallbackInfo &info);
+ ~Producer();
+ void SetCProducer(pulsar_producer_t *cProducer);
+
+ private:
+ pulsar_producer_t *cProducer;
+ Napi::Value Send(const Napi::CallbackInfo &info);
+ Napi::Value Close(const Napi::CallbackInfo &info);
+};
+
+#endif
diff --git a/src/ProducerConfig.cc b/src/ProducerConfig.cc
new file mode 100644
index 0000000..9b94dd2
--- /dev/null
+++ b/src/ProducerConfig.cc
@@ -0,0 +1,159 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "ProducerConfig.h"
+#include <map>
+
+static const std::string CFG_TOPIC = "topic";
+static const std::string CFG_PRODUCER_NAME = "producerName";
+static const std::string CFG_SEND_TIMEOUT = "sendTimeoutMs";
+static const std::string CFG_INIT_SEQUENCE_ID = "initialSequenceId";
+static const std::string CFG_MAX_PENDING = "maxPendingMessages";
+static const std::string CFG_MAX_PENDING_ACROSS_PARTITIONS = "maxPendingMessagesAcrossPartitions";
+static const std::string CFG_BLOCK_IF_QUEUE_FULL = "blockIfQueueFull";
+static const std::string CFG_ROUTING_MODE = "messageRoutingMode";
+static const std::string CFG_HASH_SCHEME = "hashingScheme";
+static const std::string CFG_COMPRESS_TYPE = "compressionType";
+static const std::string CFG_BATCH_ENABLED = "batchingEnabled";
+static const std::string CFG_BATCH_MAX_DELAY = "batchingMaxPublishDelayMs";
+static const std::string CFG_BATCH_MAX_MSG = "batchingMaxMessages";
+static const std::string CFG_PROPS = "properties";
+
+static const std::map<std::string, pulsar_partitions_routing_mode> MESSAGE_ROUTING_MODE = {
+ {"UseSinglePartition", pulsar_UseSinglePartition},
+ {"RoundRobinDistribution", pulsar_RoundRobinDistribution},
+ {"CustomPartition", pulsar_CustomPartition}};
+
+static const std::map<std::string, pulsar_hashing_scheme> HASHING_SCHEME = {
+ {"Murmur3_32Hash", pulsar_Murmur3_32Hash},
+ {"BoostHash", pulsar_BoostHash},
+ {"JavaStringHash", pulsar_JavaStringHash},
+};
+
+static std::map<std::string, pulsar_compression_type> COMPRESSION_TYPE = {{"Zlib", pulsar_CompressionZLib},
+ {"LZ4", pulsar_CompressionLZ4}};
+
+ProducerConfig::ProducerConfig(const Napi::Object& producerConfig) : topic("") {
+ this->cProducerConfig = pulsar_producer_configuration_create();
+
+ if (producerConfig.Has(CFG_TOPIC) && producerConfig.Get(CFG_TOPIC).IsString()) {
+ this->topic = producerConfig.Get(CFG_TOPIC).ToString().Utf8Value();
+ }
+
+ if (producerConfig.Has(CFG_PRODUCER_NAME) && producerConfig.Get(CFG_PRODUCER_NAME).IsString()) {
+ std::string producerName = producerConfig.Get(CFG_PRODUCER_NAME).ToString().Utf8Value();
+ if (!producerName.empty())
+ pulsar_producer_configuration_set_producer_name(this->cProducerConfig, producerName.c_str());
+ }
+
+ if (producerConfig.Has(CFG_SEND_TIMEOUT) && producerConfig.Get(CFG_SEND_TIMEOUT).IsNumber()) {
+ int32_t sendTimeoutMs = producerConfig.Get(CFG_SEND_TIMEOUT).ToNumber().Int32Value();
+ if (sendTimeoutMs > 0) {
+ pulsar_producer_configuration_set_send_timeout(this->cProducerConfig, sendTimeoutMs);
+ }
+ }
+
+ if (producerConfig.Has(CFG_INIT_SEQUENCE_ID) && producerConfig.Get(CFG_INIT_SEQUENCE_ID).IsNumber()) {
+ int64_t initialSequenceId = producerConfig.Get(CFG_INIT_SEQUENCE_ID).ToNumber().Int64Value();
+ pulsar_producer_configuration_set_initial_sequence_id(this->cProducerConfig, initialSequenceId);
+ }
+
+ if (producerConfig.Has(CFG_MAX_PENDING) && producerConfig.Get(CFG_MAX_PENDING).IsNumber()) {
+ int32_t maxPendingMessages = producerConfig.Get(CFG_MAX_PENDING).ToNumber().Int32Value();
+ if (maxPendingMessages > 0) {
+ pulsar_producer_configuration_set_max_pending_messages(this->cProducerConfig, maxPendingMessages);
+ }
+ }
+
+ if (producerConfig.Has(CFG_MAX_PENDING_ACROSS_PARTITIONS) &&
+ producerConfig.Get(CFG_MAX_PENDING_ACROSS_PARTITIONS).IsNumber()) {
+ int32_t maxPendingMessagesAcrossPartitions =
+ producerConfig.Get(CFG_MAX_PENDING_ACROSS_PARTITIONS).ToNumber().Int32Value();
+ if (maxPendingMessagesAcrossPartitions > 0) {
+ pulsar_producer_configuration_set_max_pending_messages(this->cProducerConfig,
+ maxPendingMessagesAcrossPartitions);
+ }
+ }
+
+ if (producerConfig.Has(CFG_BLOCK_IF_QUEUE_FULL) &&
+ producerConfig.Get(CFG_BLOCK_IF_QUEUE_FULL).IsBoolean()) {
+ bool blockIfQueueFull = producerConfig.Get(CFG_BLOCK_IF_QUEUE_FULL).ToBoolean().Value();
+ pulsar_producer_configuration_set_block_if_queue_full(this->cProducerConfig, blockIfQueueFull);
+ }
+
+ if (producerConfig.Has(CFG_ROUTING_MODE) && producerConfig.Get(CFG_ROUTING_MODE).IsString()) {
+ std::string messageRoutingMode = producerConfig.Get(CFG_ROUTING_MODE).ToString().Utf8Value();
+ if (MESSAGE_ROUTING_MODE.count(messageRoutingMode))
+ pulsar_producer_configuration_set_partitions_routing_mode(
+ this->cProducerConfig, MESSAGE_ROUTING_MODE.at(messageRoutingMode));
+ }
+
+ if (producerConfig.Has(CFG_HASH_SCHEME) && producerConfig.Get(CFG_HASH_SCHEME).IsString()) {
+ std::string hashingScheme = producerConfig.Get(CFG_HASH_SCHEME).ToString().Utf8Value();
+ if (HASHING_SCHEME.count(hashingScheme))
+ pulsar_producer_configuration_set_hashing_scheme(this->cProducerConfig,
+ HASHING_SCHEME.at(hashingScheme));
+ }
+
+ if (producerConfig.Has(CFG_COMPRESS_TYPE) && producerConfig.Get(CFG_COMPRESS_TYPE).IsString()) {
+ std::string compressionType = producerConfig.Get(CFG_COMPRESS_TYPE).ToString().Utf8Value();
+ if (COMPRESSION_TYPE.count(compressionType))
+ pulsar_producer_configuration_set_compression_type(this->cProducerConfig,
+ COMPRESSION_TYPE.at(compressionType));
+ }
+
+ if (producerConfig.Has(CFG_BATCH_ENABLED) && producerConfig.Get(CFG_BATCH_ENABLED).IsBoolean()) {
+ bool batchingEnabled = producerConfig.Get(CFG_BATCH_ENABLED).ToBoolean().Value();
+ pulsar_producer_configuration_set_batching_enabled(this->cProducerConfig, batchingEnabled);
+ }
+
+ if (producerConfig.Has(CFG_BATCH_MAX_DELAY) && producerConfig.Get(CFG_BATCH_MAX_DELAY).IsNumber()) {
+ int64_t batchingMaxPublishDelayMs = producerConfig.Get(CFG_BATCH_MAX_DELAY).ToNumber().Int64Value();
+ if (batchingMaxPublishDelayMs > 0) {
+ pulsar_producer_configuration_set_batching_max_publish_delay_ms(this->cProducerConfig,
+ (long)batchingMaxPublishDelayMs);
+ }
+ }
+
+ if (producerConfig.Has(CFG_BATCH_MAX_MSG) && producerConfig.Get(CFG_BATCH_MAX_MSG).IsNumber()) {
+ uint32_t batchingMaxMessages = producerConfig.Get(CFG_BATCH_MAX_MSG).ToNumber().Uint32Value();
+ if (batchingMaxMessages > 0) {
+ pulsar_producer_configuration_set_batching_max_messages(this->cProducerConfig,
+ batchingMaxMessages);
+ }
+ }
+
+ if (producerConfig.Has(CFG_PROPS) && producerConfig.Get(CFG_PROPS).IsObject()) {
+ Napi::Object propObj = producerConfig.Get(CFG_PROPS).ToObject();
+ Napi::Array arr = propObj.GetPropertyNames();
+ int size = arr.Length();
+ for (int i = 0; i < size; i++) {
+ Napi::String key = arr.Get(i).ToString();
+ Napi::String value = propObj.Get(key).ToString();
+ pulsar_producer_configuration_set_property(this->cProducerConfig, key.Utf8Value().c_str(),
+ value.Utf8Value().c_str());
+ }
+ }
+}
+
+ProducerConfig::~ProducerConfig() { pulsar_producer_configuration_free(this->cProducerConfig); }
+
+pulsar_producer_configuration_t* ProducerConfig::GetCProducerConfig() { return this->cProducerConfig; }
+
+std::string ProducerConfig::GetTopic() { return this->topic; }
diff --git a/src/ProducerConfig.h b/src/ProducerConfig.h
new file mode 100644
index 0000000..e2ecad0
--- /dev/null
+++ b/src/ProducerConfig.h
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef PRODUCER_CONFIG_H
+#define PRODUCER_CONFIG_H
+
+#include <napi.h>
+#include <pulsar/c/producer_configuration.h>
+
+class ProducerConfig {
+ public:
+ ProducerConfig(const Napi::Object &producerConfig);
+ ~ProducerConfig();
+ pulsar_producer_configuration_t *GetCProducerConfig();
+ std::string GetTopic();
+
+ private:
+ pulsar_producer_configuration_t *cProducerConfig;
+ std::string topic;
+};
+
+#endif
diff --git a/src/addon.cc b/src/addon.cc
new file mode 100644
index 0000000..abcbb24
--- /dev/null
+++ b/src/addon.cc
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "Client.h"
+#include "Consumer.h"
+#include "Message.h"
+#include "MessageId.h"
+#include "Producer.h"
+#include <napi.h>
+
+Napi::Object InitAll(Napi::Env env, Napi::Object exports) {
+ Message::Init(env, exports);
+ MessageId::Init(env, exports);
+ Producer::Init(env, exports);
+ Consumer::Init(env, exports);
+ return Client::Init(env, exports);
+}
+
+NODE_API_MODULE(NODE_GYP_MODULE_NAME, InitAll)