You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by mm...@apache.org on 2019/03/12 16:34:10 UTC

[pulsar-client-node] branch master updated (060a662 -> 2f977b9)

This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-node.git.


    from 060a662  Initialize pulsar-client-node project
     new f866cd6  provide nodejs client
     new 196a69c  change 4 to 2 spaces and reformat
     new 05c9e48  make config inline
     new d4513f7  add compatibility and change version
     new 987578e  set new version
     new 2f977b9  Merge pull request #1 from k2la/provide_nodejs_client

The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .clang-format         |   25 +
 .eslintrc.json        |    9 +
 .gitignore            |    3 +
 Gruntfile.js          |   31 +
 README.md             |   56 +-
 binding.gyp           |   42 +
 examples/consumer.js  |   45 +
 examples/producer.js  |   49 +
 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       |  183 ++++
 src/Consumer.h        |   44 +
 src/ConsumerConfig.cc |  105 ++
 src/ConsumerConfig.h  |   44 +
 src/Message.cc        |  197 ++++
 src/Message.h         |   64 ++
 src/MessageId.cc      |   87 ++
 src/MessageId.h       |   46 +
 src/Producer.cc       |  151 +++
 src/Producer.h        |   42 +
 src/ProducerConfig.cc |  158 +++
 src/ProducerConfig.h  |   38 +
 src/addon.cc          |   35 +
 28 files changed, 4722 insertions(+), 1 deletion(-)
 create mode 100644 .clang-format
 create mode 100644 .eslintrc.json
 create mode 100644 .gitignore
 create mode 100644 Gruntfile.js
 create mode 100644 binding.gyp
 create mode 100644 examples/consumer.js
 create mode 100644 examples/producer.js
 create mode 100644 index.js
 create mode 100644 package-lock.json
 create mode 100644 package.json
 create mode 100644 perf/perf_consumer.js
 create mode 100644 perf/perf_producer.js
 create mode 100644 src/Client.cc
 create mode 100644 src/Client.h
 create mode 100644 src/Consumer.cc
 create mode 100644 src/Consumer.h
 create mode 100644 src/ConsumerConfig.cc
 create mode 100644 src/ConsumerConfig.h
 create mode 100644 src/Message.cc
 create mode 100644 src/Message.h
 create mode 100644 src/MessageId.cc
 create mode 100644 src/MessageId.h
 create mode 100644 src/Producer.cc
 create mode 100644 src/Producer.h
 create mode 100644 src/ProducerConfig.cc
 create mode 100644 src/ProducerConfig.h
 create mode 100644 src/addon.cc


[pulsar-client-node] 07/07: Merge pull request #1 from k2la/provide_nodejs_client

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-node.git

commit 2f977b959c0b5013987a77b9a4ce6d3d79c2c14c
Merge: 060a662 987578e
Author: Matteo Merli <mm...@apache.org>
AuthorDate: Tue Mar 12 09:34:05 2019 -0700

    Merge pull request #1 from k2la/provide_nodejs_client
    
    Provide Node Client Library

 .clang-format         |   25 +
 .eslintrc.json        |    9 +
 .gitignore            |    3 +
 Gruntfile.js          |   31 +
 README.md             |   56 +-
 binding.gyp           |   42 +
 examples/consumer.js  |   45 +
 examples/producer.js  |   49 +
 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       |  183 ++++
 src/Consumer.h        |   44 +
 src/ConsumerConfig.cc |  105 ++
 src/ConsumerConfig.h  |   44 +
 src/Message.cc        |  197 ++++
 src/Message.h         |   64 ++
 src/MessageId.cc      |   87 ++
 src/MessageId.h       |   46 +
 src/Producer.cc       |  151 +++
 src/Producer.h        |   42 +
 src/ProducerConfig.cc |  158 +++
 src/ProducerConfig.h  |   38 +
 src/addon.cc          |   35 +
 28 files changed, 4722 insertions(+), 1 deletion(-)


[pulsar-client-node] 02/07: provide nodejs client

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli 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)


[pulsar-client-node] 01/07: Initialize pulsar-client-node project

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-node.git

commit 060a66246a38a3d9e367f41ba44c4f80db534838
Author: Sijie Guo <si...@apache.org>
AuthorDate: Fri Mar 1 21:47:17 2019 +0800

    Initialize pulsar-client-node project
---
 LICENSE   | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 README.md |   1 +
 2 files changed, 306 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..356931c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,305 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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-common/src/main/java/org/apache/pulsar/common/util/protobuf/ByteBufCoded{Input,Output}Stream.java
+
+Copyright 2014, Google Inc.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+    * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Code generated by the Protocol Buffer compiler is owned by the owner
+of the input file used when generating it.  This code is not
+standalone and requires a support library to be linked with it.  This
+support library is itself covered by the above license.
+
+----------------------------------------------------------------------------------------------------
+
+pulsar-client-cpp/lib/lz4/lz4.{h,c}
+
+LZ4 - Fast LZ compression algorithm
+Copyright (C) 2011-2015, Yann Collet.
+
+BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You can contact the author at :
+- LZ4 source repository : https://github.com/Cyan4973/lz4
+- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+
+----------------------------------------------------------------------------------------------------
+
+pulsar-client-cpp/lib/checksum/crc32c_sw.cc
+
+/* crc32c.c -- compute CRC-32C using the Intel crc32 instruction
+ * Copyright (C) 2013 Mark Adler
+ * Version 1.1  1 Aug 2013  Mark Adler
+ */
+
+/*
+ This software is provided 'as-is', without any express or implied
+ warranty.  In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler
+ madler@alumni.caltech.edu
+ */
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b560743
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# Pulsar Node Client


[pulsar-client-node] 04/07: make config inline

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-node.git

commit 05c9e48f397522395e0411d3c28aad354ac05e9a
Author: yfuruta <yf...@yahoo-corp.jp>
AuthorDate: Tue Mar 12 10:55:19 2019 +0900

    make config inline
---
 examples/consumer.js | 10 ++++------
 examples/producer.js | 10 ++++------
 2 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/examples/consumer.js b/examples/consumer.js
index 7092c6b..c754ac3 100644
--- a/examples/consumer.js
+++ b/examples/consumer.js
@@ -21,19 +21,17 @@ const Pulsar = require('../index.js');
 
 (async () => {
   // Create a client
-  const clientConfig = {
+  const client = new Pulsar.Client({
     serviceUrl: 'pulsar://localhost:6650',
     operationTimeoutSeconds: 30,
-  };
-  const client = new Pulsar.Client(clientConfig);
+  });
 
   // Create a consumer
-  const consumerConfig = {
+  const consumer = await client.subscribe({
     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) {
diff --git a/examples/producer.js b/examples/producer.js
index b1b6856..8730719 100644
--- a/examples/producer.js
+++ b/examples/producer.js
@@ -21,19 +21,17 @@ const Pulsar = require('../index.js');
 
 (async () => {
   // Create a client
-  const clientConfig = {
+  const client = new Pulsar.Client({
     serviceUrl: 'pulsar://localhost:6650',
     operationTimeoutSeconds: 30,
-  };
-  const client = new Pulsar.Client(clientConfig);
+  });
 
   // Create a producer
-  const producerConfig = {
+  const producer = await client.createProducer({
     topic: 'persistent://public/default/my-topic',
     sendTimeoutMs: 30000,
     batchingEnabled: true,
-  };
-  const producer = await client.createProducer(producerConfig);
+  });
 
   // Send messages
   const results = [];


[pulsar-client-node] 03/07: change 4 to 2 spaces and reformat

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-node.git

commit 196a69c30e238e1438f4964b6643bfc4b56ed903
Author: yfuruta <yf...@yahoo-corp.jp>
AuthorDate: Tue Mar 12 10:48:30 2019 +0900

    change 4 to 2 spaces and reformat
---
 .clang-format         |   2 +-
 src/Client.cc         | 194 +++++++++++++++++++-------------------
 src/Client.h          |  20 ++--
 src/Consumer.cc       | 243 ++++++++++++++++++++++++------------------------
 src/Consumer.h        |  26 +++---
 src/ConsumerConfig.cc |  89 +++++++++---------
 src/ConsumerConfig.h  |  24 ++---
 src/Message.cc        | 252 +++++++++++++++++++++++++-------------------------
 src/Message.h         |  60 ++++++------
 src/MessageId.cc      |  64 ++++++-------
 src/MessageId.h       |  28 +++---
 src/Producer.cc       | 194 +++++++++++++++++++-------------------
 src/Producer.h        |  22 ++---
 src/ProducerConfig.cc | 181 ++++++++++++++++++------------------
 src/ProducerConfig.h  |  16 ++--
 src/addon.cc          |  10 +-
 16 files changed, 707 insertions(+), 718 deletions(-)

diff --git a/.clang-format b/.clang-format
index cb40b50..f2d174b 100644
--- a/.clang-format
+++ b/.clang-format
@@ -17,7 +17,7 @@
 
 
 BasedOnStyle: Google
-IndentWidth: 4
+IndentWidth: 2
 ColumnLimit: 110
 SortIncludes: false
 BreakBeforeBraces: Custom
diff --git a/src/Client.cc b/src/Client.cc
index 97fc573..16fb13d 100644
--- a/src/Client.cc
+++ b/src/Client.cc
@@ -38,133 +38,133 @@ 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::HandleScope scope(env);
 
-    Napi::Function func = DefineClass(
-        env, "Client",
-        {InstanceMethod("createProducer", &Client::CreateProducer),
-         InstanceMethod("subscribe", &Client::Subscribe), InstanceMethod("close", &Client::Close)});
+  Napi::Function func =
+      DefineClass(env, "Client",
+                  {InstanceMethod("createProducer", &Client::CreateProducer),
+                   InstanceMethod("subscribe", &Client::Subscribe), InstanceMethod("close", &Client::Close)});
 
-    constructor = Napi::Persistent(func);
-    constructor.SuppressDestruct();
+  constructor = Napi::Persistent(func);
+  constructor.SuppressDestruct();
 
-    exports.Set("Client", func);
-    return exports;
+  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::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();
+  }
+  Napi::String serviceUrl = clientConfig.Get(CFG_SERVICE_URL).ToString();
 
-    pulsar_client_configuration_t *cClientConfig = pulsar_client_configuration_create();
+  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_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_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_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_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);
-        }
+  }
+
+  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);
+  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);
+  return Producer::NewInstance(info, this->cClient);
 }
 
 Napi::Value Client::Subscribe(const Napi::CallbackInfo &info) {
-    return Consumer::NewInstance(info, this->cClient);
+  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;
+ 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();
+  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
index bc92125..63c66f2 100644
--- a/src/Client.h
+++ b/src/Client.h
@@ -24,18 +24,18 @@
 #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();
+ 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;
+ 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);
+  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
index 85e0fbf..db6fab4 100644
--- a/src/Consumer.cc
+++ b/src/Consumer.cc
@@ -26,18 +26,18 @@
 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();
+  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; }
@@ -45,144 +45,139 @@ void Consumer::SetCConsumer(pulsar_consumer_t *cConsumer) { this->cConsumer = cC
 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;
-        }
+ 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;
     }
-    void OnOK() {
-        Napi::Object obj = Consumer::constructor.New({});
-        Consumer *consumer = Consumer::Unwrap(obj);
-        consumer->SetCConsumer(this->cConsumer);
-        this->deferred.Resolve(obj);
+    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;
     }
-    void OnError(const Napi::Error &e) {
-        this->deferred.Reject(Napi::Error::New(Env(), e.Message()).Value());
+    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;
     }
 
-   private:
-    Napi::Promise::Deferred deferred;
-    pulsar_client_t *cClient;
-    ConsumerConfig *consumerConfig;
-    pulsar_consumer_t *cConsumer;
+    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();
+  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);
+ 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 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;
+  }
+  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();
+  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);
+  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);
+  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;
+ 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();
+  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
index 8e77df3..fe68124 100644
--- a/src/Consumer.h
+++ b/src/Consumer.h
@@ -24,21 +24,21 @@
 #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);
+ 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;
+ 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);
+  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
index 78f1605..a98bb69 100644
--- a/src/ConsumerConfig.cc
+++ b/src/ConsumerConfig.cc
@@ -37,64 +37,63 @@ static const std::map<std::string, pulsar_consumer_type> SUBSCRIPTION_TYPE = {
 
 ConsumerConfig::ConsumerConfig(const Napi::Object &consumerConfig)
     : topic(""), subscription(""), ackTimeoutMs(0) {
-    this->cConsumerConfig = pulsar_consumer_configuration_create();
+  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_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) && 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_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_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_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) && 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_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());
-        }
+  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); }
diff --git a/src/ConsumerConfig.h b/src/ConsumerConfig.h
index 00c890e..7070bf9 100644
--- a/src/ConsumerConfig.h
+++ b/src/ConsumerConfig.h
@@ -26,19 +26,19 @@
 #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();
+ 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;
+ 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
index 9a0129e..3c527d5 100644
--- a/src/Message.cc
+++ b/src/Message.cc
@@ -31,29 +31,29 @@ 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::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;
+  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) {}
@@ -61,137 +61,137 @@ Message::Message(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Message>(inf
 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::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::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::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::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::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::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));
+  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;
-    }
+  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;
+  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);
-    }
+  if (this->cMessage != nullptr) {
+    pulsar_message_free(this->cMessage);
+  }
 }
diff --git a/src/Message.h b/src/Message.h
index 8992f9c..42aa9aa 100644
--- a/src/Message.h
+++ b/src/Message.h
@@ -24,41 +24,41 @@
 #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();
+ 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;
+ private:
+  static Napi::FunctionReference constructor;
 
-    pulsar_message_t *cMessage;
+  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);
+  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);
+  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
index 3a95f43..a0b520f 100644
--- a/src/MessageId.cc
+++ b/src/MessageId.cc
@@ -24,64 +24,64 @@
 Napi::FunctionReference MessageId::constructor;
 
 Napi::Object MessageId::Init(Napi::Env env, Napi::Object exports) {
-    Napi::HandleScope scope(env);
+  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),
-                                      });
+  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();
+  constructor = Napi::Persistent(func);
+  constructor.SuppressDestruct();
 
-    exports.Set("MessageId", func);
-    return exports;
+  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::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 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;
+  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::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::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;
+  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));
+  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
index 761f04b..09c59e2 100644
--- a/src/MessageId.h
+++ b/src/MessageId.h
@@ -25,22 +25,22 @@
 #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();
+ 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;
+ private:
+  static Napi::FunctionReference constructor;
+  pulsar_message_id_t *cMessageId;
 
-    Napi::Value ToString(const Napi::CallbackInfo &info);
+  Napi::Value ToString(const Napi::CallbackInfo &info);
 };
 
 #endif
diff --git a/src/Producer.cc b/src/Producer.cc
index 9bdb5d4..a19d828 100644
--- a/src/Producer.cc
+++ b/src/Producer.cc
@@ -25,131 +25,127 @@
 Napi::FunctionReference Producer::constructor;
 
 void Producer::Init(Napi::Env env, Napi::Object exports) {
-    Napi::HandleScope scope(env);
+  Napi::HandleScope scope(env);
 
-    Napi::Function func =
-        DefineClass(env, "Producer",
-                    {InstanceMethod("send", &Producer::Send), InstanceMethod("close", &Producer::Close)});
+  Napi::Function func = DefineClass(
+      env, "Producer", {InstanceMethod("send", &Producer::Send), InstanceMethod("close", &Producer::Close)});
 
-    constructor = Napi::Persistent(func);
-    constructor.SuppressDestruct();
+  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());
+ 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;
     }
 
-   private:
-    Napi::Promise::Deferred deferred;
-    pulsar_client_t *cClient;
-    ProducerConfig *producerConfig;
-    pulsar_producer_t *cProducer;
+    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();
+  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;
+ 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();
+  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;
+ 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();
+  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
index c758ce4..5d31cfc 100644
--- a/src/Producer.h
+++ b/src/Producer.h
@@ -25,18 +25,18 @@
 #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);
+ 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);
+ 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
index 9b94dd2..76fd25c 100644
--- a/src/ProducerConfig.cc
+++ b/src/ProducerConfig.cc
@@ -50,106 +50,105 @@ static std::map<std::string, pulsar_compression_type> COMPRESSION_TYPE = {{"Zlib
                                                                           {"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);
-        }
+  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_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) && 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_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_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_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_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_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());
-        }
+  }
+
+  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); }
diff --git a/src/ProducerConfig.h b/src/ProducerConfig.h
index e2ecad0..c18c813 100644
--- a/src/ProducerConfig.h
+++ b/src/ProducerConfig.h
@@ -24,15 +24,15 @@
 #include <pulsar/c/producer_configuration.h>
 
 class ProducerConfig {
-   public:
-    ProducerConfig(const Napi::Object &producerConfig);
-    ~ProducerConfig();
-    pulsar_producer_configuration_t *GetCProducerConfig();
-    std::string GetTopic();
+ public:
+  ProducerConfig(const Napi::Object &producerConfig);
+  ~ProducerConfig();
+  pulsar_producer_configuration_t *GetCProducerConfig();
+  std::string GetTopic();
 
-   private:
-    pulsar_producer_configuration_t *cProducerConfig;
-    std::string topic;
+ private:
+  pulsar_producer_configuration_t *cProducerConfig;
+  std::string topic;
 };
 
 #endif
diff --git a/src/addon.cc b/src/addon.cc
index abcbb24..9e75d3f 100644
--- a/src/addon.cc
+++ b/src/addon.cc
@@ -25,11 +25,11 @@
 #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);
+  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)


[pulsar-client-node] 06/07: set new version

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-node.git

commit 987578e694fceb6788f74224f90b6b8662a61f7a
Author: yfuruta <yf...@yahoo-corp.jp>
AuthorDate: Tue Mar 12 14:44:20 2019 +0900

    set new version
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index cda8e3c..2455ce6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pulsar-client",
-  "version": "2.3.0",
+  "version": "2.4.0-SNAPSHOT",
   "description": "Pulsar Node.js client",
   "main": "index.js",
   "directories": {


[pulsar-client-node] 05/07: add compatibility and change version

Posted by mm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-node.git

commit d4513f7b3e03df6cd185f3cec3f81a74a5d4fe25
Author: yfuruta <yf...@yahoo-corp.jp>
AuthorDate: Tue Mar 12 12:45:36 2019 +0900

    add compatibility and change version
---
 README.md    | 4 ++++
 package.json | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 90d856f..0418c32 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,10 @@
 
 The Pulsar Node.js client can be used to create Pulsar producers and consumers in Node.js.
 
+## Compatibility
+
+This Node.js client is developed and tested using Apache Pulsar 2.3.0
+
 ## Requirements
 
 Pulsar Node.js client library is based on the C++ client library. Follow the instructions for
diff --git a/package.json b/package.json
index 33b1321..cda8e3c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pulsar-client",
-  "version": "0.0.1",
+  "version": "2.3.0",
   "description": "Pulsar Node.js client",
   "main": "index.js",
   "directories": {