diff --git a/README.md b/README.md
index e7981a26a..64a59e879 100644
--- a/README.md
+++ b/README.md
@@ -188,12 +188,12 @@ to another project.
sentiment |
🔗 |
Text |
- Sequence-to-regression |
+ Sequence-to-binary-prediction |
LSTM, 1D convnet |
- |
+ Node.js |
Browser |
Layers |
- Loading model converted from Keras |
+ Loading model converted from Keras and tfjs-node |
simple-object-detection |
diff --git a/sentiment/.gitignore b/sentiment/.gitignore
new file mode 100644
index 000000000..ce280bb60
--- /dev/null
+++ b/sentiment/.gitignore
@@ -0,0 +1,4 @@
+*.bin
+*.zip
+model.json
+metadata.json
diff --git a/sentiment/README.md b/sentiment/README.md
index 4dd171b1f..acd817d5c 100644
--- a/sentiment/README.md
+++ b/sentiment/README.md
@@ -24,3 +24,46 @@ yarn watch
```
[See this example live!](https://storage.googleapis.com/tfjs-examples/sentiment/dist/index.html)
+
+## Training your own model in tfjs-node
+
+To train the model using tfjs-node, do
+
+```sh
+yarn
+yarn train
+```
+
+where `MODEL_TYPE` is a required argument that specifies what type of model is to be
+trained. The available options are:
+
+- `flatten`: A model that flattens the embedding vectors of all words in the sequence.
+- `cnn`: A 1D convolutional model.
+- `simpleRNN`: A model that uses a SimpleRNN layer (`tf.layers.simpleRNN`)
+- `lstm`: A model that uses a LSTM laayer (`tf.layers.lstm`)
+- `bidirectionalLSTM`: A model that uses a bidirectional LSTM layer
+ (`tf.layers.bidirectional` and `tf.layers.lstm`)
+
+By default, the training happens on the CPU using the Eigen kernels from tfjs-node.
+You can make the training happen on GPU by adding the `--gpu` flag to the command, e.g.,
+
+```sh
+yarn train --gpu
+```
+
+The training process will download the training data and metadata form the web
+if they haven't been downloaded before. After the model training completes, the model
+will be saved to the `dist/resources` folder, alongside a `metadata.json` file.
+Then when you run `yarn watch`, you will see a "Load local model" button in the web
+page, which allows you to use the locally-trained model for inference in the browser.
+
+Other arguments of the `yarn train` command include:
+
+- `--maxLen` allows you to specify the sequence length.
+- `--numWords` allows you to specify the vocabulary size.
+- `--embeddingSize` allows you to adjust the dimensionality of the embedding vectors.
+- `--epochs`, `--batchSize`, and `--validationSplit` are training-related settings.
+- `--modelSavePath` allows you to specify where to store the model and metadata after
+ training completes.
+
+The detailed code for training are in the file [train.js](./train.js).
diff --git a/sentiment/data.js b/sentiment/data.js
new file mode 100644
index 000000000..4f9aa9c02
--- /dev/null
+++ b/sentiment/data.js
@@ -0,0 +1,216 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * 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.
+ * =============================================================================
+ */
+
+import * as tf from '@tensorflow/tfjs';
+import * as fs from 'fs';
+import * as https from 'https';
+import * as os from 'os';
+import * as path from 'path';
+
+import {OOV_CHAR, PAD_CHAR, padSequences} from './sequence_utils';
+
+// `import` doesn't seem to work with extract-zip.
+const extract = require('extract-zip');
+
+const DATA_ZIP_URL =
+ 'https://storage.googleapis.com/learnjs-data/imdb/imdb_tfjs_data.zip';
+const METADATA_TEMPLATE_URL =
+ 'https://storage.googleapis.com/learnjs-data/imdb/metadata.json.zip';
+
+/**
+ * Load IMDB data features from a local file.
+ *
+ * @param {string} filePath Data file on local filesystem.
+ * @param {string} numWords Number of words in the vocabulary. Word indices
+ * that exceed this limit will be marked as `OOV_CHAR`.
+ * @param {string} maxLen Length of each sequence. Longer sequences will be
+ * pre-truncated; shorter ones will be pre-padded.
+ * @return {tf.Tensor} The dataset represented as a 2D `tf.Tensor` of shape
+ * `[]` and dtype `int32` .
+ */
+function loadFeatures(filePath, numWords, maxLen) {
+ const buffer = fs.readFileSync(filePath);
+ const numBytes = buffer.byteLength;
+
+ let sequences = [];
+ let seq = [];
+ let index = 0;
+
+ while (index < numBytes) {
+ const value = buffer.readInt32LE(index);
+ if (value === 1) {
+ // A new sequence has started.
+ if (index > 0) {
+ sequences.push(seq);
+ }
+ seq = [];
+ } else {
+ // Sequence continues.
+ seq.push(value >= numWords ? OOV_CHAR : value);
+ }
+ index += 4;
+ }
+ if (seq.length > 0) {
+ sequences.push(seq);
+ }
+ const paddedSequences =
+ padSequences(sequences, maxLen, 'pre', 'pre');
+ return tf.tensor2d(
+ paddedSequences, [paddedSequences.length, maxLen], 'int32');
+}
+
+/**
+ * Load IMDB targets from a file.
+ *
+ * @param {string} filePath Path to the binary targets file.
+ * @return {tf.Tensor} The targets as `tf.Tensor` of shape `[numExamples, 1]`
+ * and dtype `float32`. It has 0 or 1 values.
+ */
+function loadTargets(filePath) {
+ const buffer = fs.readFileSync(filePath);
+ const numBytes = buffer.byteLength;
+
+ let ys = [];
+ for (let i = 0; i < numBytes; ++i) {
+ ys.push(buffer.readUInt8(i));
+ }
+ return tf.tensor2d(ys, [ys.length, 1], 'float32');
+}
+
+/**
+ * Get a file by downloading it if necessary.
+ *
+ * @param {string} sourceURL URL to download the file from.
+ * @param {string} destPath Destination file path on local filesystem.
+ */
+async function maybeDownload(sourceURL, destPath) {
+ return new Promise(async (resolve, reject) => {
+ if (!fs.existsSync(destPath) || fs.lstatSync(destPath).size === 0) {
+ const localZipFile = fs.createWriteStream(destPath);
+ console.log(`Downloading file from ${sourceURL} ...`);
+ https.get(sourceURL, response => {
+ response.pipe(localZipFile);
+ localZipFile.on('finish', () => {
+ localZipFile.close(async () => {
+ return resolve();
+ });
+ });
+ localZipFile.on('error', err => {
+ return reject(err);
+ });
+ });
+ } else {
+ return resolve();
+ }
+ });
+}
+
+/**
+ * Get extracted files.
+ *
+ * If the files are already extracted, this will be a no-op.
+ *
+ * @param {string} sourcePath Source zip file path.
+ * @param {string} destDir Extraction destination directory.
+ */
+async function maybeExtract(sourcePath, destDir) {
+ return new Promise((resolve, reject) => {
+ if (fs.existsSync(destDir)) {
+ return resolve();
+ }
+ console.log(`Extracting: ${sourcePath} --> ${destDir}`);
+ extract(sourcePath, {dir: destDir}, err => {
+ if (err == null) {
+ return resolve();
+ } else {
+ return reject(err);
+ }
+ });
+ });
+}
+
+const ZIP_SUFFIX = '.zip';
+
+/**
+ * Get the IMDB data through file downloading and extraction.
+ *
+ * If the files already exist on the local file system, the download and/or
+ * extraction steps will be skipped.
+ */
+async function maybeDownloadAndExtract() {
+ const zipDownloadDest = path.join(os.tmpdir(), path.basename(DATA_ZIP_URL));
+ await maybeDownload(DATA_ZIP_URL, zipDownloadDest);
+
+ const zipExtractDir =
+ zipDownloadDest.slice(0, zipDownloadDest.length - ZIP_SUFFIX.length);
+ await maybeExtract(zipDownloadDest, zipExtractDir);
+ return zipExtractDir;
+}
+
+/**
+ * Load data by downloading and extracting files if necessary.
+ *
+ * @param {number} numWords Number of words to in the vocabulary.
+ * @param {number} len Length of each sequence. Longer sequences will
+ * be pre-truncated and shorter ones will be pre-padded.
+ * @return
+ * xTrain: Training data as a `tf.Tensor` of shape
+ * `[numExamples, len]` and `int32` dtype.
+ * yTrain: Targets for the training data, as a `tf.Tensor` of
+ * `[numExamples, 1]` and `float32` dtype. The values are 0 or 1.
+ * xTest: The same as `xTrain`, but for the test dataset.
+ * yTest: The same as `yTrain`, but for the test dataset.
+ */
+export async function loadData(numWords, len) {
+ const dataDir = await maybeDownloadAndExtract();
+
+ const trainFeaturePath = path.join(dataDir, 'imdb_train_data.bin');
+ const xTrain = loadFeatures(trainFeaturePath, numWords, len);
+ const testFeaturePath = path.join(dataDir, 'imdb_test_data.bin');
+ const xTest = loadFeatures(testFeaturePath, numWords, len);
+ const trainTargetsPath = path.join(dataDir, 'imdb_train_targets.bin');
+ const yTrain = loadTargets(trainTargetsPath);
+ const testTargetsPath = path.join(dataDir, 'imdb_test_targets.bin');
+ const yTest = loadTargets(testTargetsPath);
+
+ tf.util.assert(
+ xTrain.shape[0] === yTrain.shape[0],
+ `Mismatch in number of examples between xTrain and yTrain`);
+ tf.util.assert(
+ xTest.shape[0] === yTest.shape[0],
+ `Mismatch in number of examples between xTest and yTest`);
+ return {xTrain, yTrain, xTest, yTest};
+}
+
+/**
+ * Load a metadata template by downloading and extracting files if necessary.
+ *
+ * @return A JSON object that is the metadata template.
+ */
+export async function loadMetadataTemplate() {
+ const baseName = path.basename(METADATA_TEMPLATE_URL);
+ const zipDownloadDest = path.join(os.tmpdir(), baseName);
+ await maybeDownload(METADATA_TEMPLATE_URL, zipDownloadDest);
+
+ const zipExtractDir =
+ zipDownloadDest.slice(0, zipDownloadDest.length - ZIP_SUFFIX.length);
+ await maybeExtract(zipDownloadDest, zipExtractDir);
+
+ return JSON.parse(fs.readFileSync(
+ path.join(zipExtractDir,
+ baseName.slice(0, baseName.length - ZIP_SUFFIX.length))));
+}
diff --git a/sentiment/index.js b/sentiment/index.js
index 66f47ef34..430fdd70f 100644
--- a/sentiment/index.js
+++ b/sentiment/index.js
@@ -18,7 +18,7 @@
import * as tf from '@tensorflow/tfjs';
import * as loader from './loader';
import * as ui from './ui';
-
+import {OOV_CHAR, padSequences} from './sequence_utils';
const HOSTED_URLS = {
model:
@@ -28,8 +28,8 @@ const HOSTED_URLS = {
};
const LOCAL_URLS = {
- model: 'http://localhost:1235/resources/model.json',
- metadata: 'http://localhost:1235/resources/metadata.json'
+ model: './resources/model.json',
+ metadata: './resources/metadata.json'
};
class SentimentPredictor {
@@ -52,23 +52,27 @@ class SentimentPredictor {
console.log('indexFrom = ' + this.indexFrom);
console.log('maxLen = ' + this.maxLen);
- this.wordIndex = sentimentMetadata['word_index']
+ this.wordIndex = sentimentMetadata['word_index'];
+ this.vocabularySize = sentimentMetadata['vocabulary_size'];
+ console.log('vocabularySize = ', this.vocabularySize);
}
predict(text) {
// Convert to lower case and remove all punctuations.
const inputText =
text.trim().toLowerCase().replace(/(\.|\,|\!)/g, '').split(' ');
- // Look up word indices.
- const inputBuffer = tf.buffer([1, this.maxLen], 'float32');
- for (let i = 0; i < inputText.length; ++i) {
- // TODO(cais): Deal with OOV words.
- const word = inputText[i];
- inputBuffer.set(this.wordIndex[word] + this.indexFrom, 0, i);
- }
- const input = inputBuffer.toTensor();
+ // Convert the words to a sequence of word indices.
+ const sequence = inputText.map(word => {
+ let wordIndex = this.wordIndex[word] + this.indexFrom;
+ if (wordIndex > this.vocabularySize) {
+ wordIndex = OOV_CHAR;
+ }
+ return wordIndex;
+ });
+ // Perform truncation and padding.
+ const paddedSequence = padSequences([sequence], this.maxLen);
+ const input = tf.tensor2d(paddedSequence, [1, this.maxLen]);
- ui.status('Running inference');
const beginMs = performance.now();
const predictOut = this.model.predict(input);
const score = predictOut.dataSync()[0];
@@ -79,7 +83,6 @@ class SentimentPredictor {
}
};
-
/**
* Loads the pretrained model and metadata, and registers the predict
* function with the UI.
diff --git a/sentiment/package.json b/sentiment/package.json
index a0def4bb2..4a63b177e 100644
--- a/sentiment/package.json
+++ b/sentiment/package.json
@@ -9,24 +9,31 @@
"node": ">=8.9.0"
},
"dependencies": {
- "@tensorflow/tfjs": "^0.14.2",
+ "@tensorflow/tfjs": "0.14.2",
"vega-embed": "^3.0.0"
},
"scripts": {
"watch": "./serve.sh",
"build": "cross-env NODE_ENV=production parcel build index.html --no-minify --public-url ./",
"link-local": "yalc link",
- "postinstall": "yarn upgrade --pattern @tensorflow"
+ "postinstall": "yarn upgrade --pattern @tensorflow",
+ "train": "babel-node train.js"
},
"devDependencies": {
+ "@tensorflow/tfjs-node": "0.2.3",
+ "@tensorflow/tfjs-node-gpu": "0.2.3",
+ "argparse": "^1.0.10",
+ "babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-plugin-transform-runtime": "~6.23.0",
"babel-polyfill": "~6.26.0",
"babel-preset-env": "~1.6.1",
"clang-format": "~1.2.2",
"cross-env": "^5.1.6",
+ "extract-zip": "^1.6.7",
"http-server": "~0.10.0",
"parcel-bundler": "~1.10.3",
+ "shelljs": "^0.8.3",
"yalc": "~1.0.0-pre.22"
}
}
diff --git a/sentiment/python/convert_imdb_npz.py b/sentiment/python/convert_imdb_npz.py
new file mode 100644
index 000000000..4823e1ca6
--- /dev/null
+++ b/sentiment/python/convert_imdb_npz.py
@@ -0,0 +1,55 @@
+# Copyright 2018 Google LLC. All Rights Reserved.
+#
+# 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.
+# =============================================================================
+
+"""Converts the IMDB dataset from .npz format into a JavaScript format.
+
+Four files are generated as a result:
+ - imdb_train_data.bin
+ - imdb_train_targets.bin
+ - imdb_test_data.bin
+ - imdb_test_targets.bin
+
+In the *data.bin files, the variable-length sentences are separated by the integer 1
+which labels the beginning of the sentence.
+All the word indices are stored as uint32 values.
+In the *targets.bin files, the binary labels are stored as uint8 values.
+"""
+
+import argparse
+import struct
+
+from keras.datasets import imdb
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('out_prefix', type=str, help='Output path prefix')
+ args = parser.parse_args()
+
+ print('Loading imdb data via keras...')
+ (x_train, y_train), (x_test, y_test) = imdb.load_data()
+
+ for split in ('train', 'test'):
+ data_path = '%s_%s_data.bin' % (args.out_prefix, split)
+ xs = x_train if split == 'train' else x_test
+ print('Writing data to file: %s' % data_path)
+ with open(data_path, 'wb') as f:
+ for sentence in xs:
+ f.write(struct.pack('%di' % len(sentence), *sentence))
+
+ targets_path = '%s_%s_targets.bin' % (args.out_prefix, split)
+ ys = y_train if split == 'train' else y_test
+ print('Writing targets to file: %s' % targets_path)
+ with open(targets_path, 'wb') as f:
+ f.write(struct.pack('%db' % len(ys), *ys))
diff --git a/sentiment/sequence_utils.js b/sentiment/sequence_utils.js
new file mode 100644
index 000000000..54d6169a0
--- /dev/null
+++ b/sentiment/sequence_utils.js
@@ -0,0 +1,64 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * 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.
+ * =============================================================================
+ */
+
+/**
+ * Utilities for sequential data.
+ */
+
+export const PAD_CHAR = 0;
+export const OOV_CHAR = 2;
+
+/**
+ * Pad and truncate all sequences to the same length
+ *
+ * @param {number[][]} sequences The sequences represented as an array of array
+ * of numbers.
+ * @param {number} maxLen Maximum length. Sequences longer than `maxLen` will be
+ * truncated. Sequences shorter than `maxLen` will be padded.
+ * @param {'pre'|'post'} padding Padding type.
+ * @param {'pre'|'post'} truncating Truncation type.
+ * @param {number} value Padding value.
+ */
+export function padSequences(
+ sequences, maxLen, padding = 'pre', truncating = 'pre', value = PAD_CHAR) {
+ // TODO(cais): This perhaps should be refined and moved into tfjs-preproc.
+ return sequences.map(seq => {
+ // Perform truncation.
+ if (seq.length > maxLen) {
+ if (truncating === 'pre') {
+ seq.splice(0, seq.length - maxLen);
+ } else {
+ seq.splice(maxLen, seq.length - maxLen);
+ }
+ }
+
+ // Perform padding.
+ if (seq.length < maxLen) {
+ const pad = [];
+ for (let i = 0; i < maxLen - seq.length; ++i) {
+ pad.push(value);
+ }
+ if (padding === 'pre') {
+ seq = pad.concat(seq);
+ } else {
+ seq = seq.concat(pad);
+ }
+ }
+
+ return seq;
+ });
+}
diff --git a/sentiment/train.js b/sentiment/train.js
new file mode 100644
index 000000000..1458d5a43
--- /dev/null
+++ b/sentiment/train.js
@@ -0,0 +1,185 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * 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.
+ * =============================================================================
+ */
+
+import * as tf from '@tensorflow/tfjs';
+import {ArgumentParser} from 'argparse';
+import * as fs from 'fs';
+import * as path from 'path';
+import * as shelljs from 'shelljs';
+
+import {loadData, loadMetadataTemplate} from './data';
+
+/**
+ * Create a model for IMDB sentiment analysis.
+ *
+ * @param {string} modelType Type of the model to be created.
+ * @param {number} vocabularySize Input vocabulary size.
+ * @param {number} embeddingSize Embedding vector size, used to
+ * configure the embedding layer.
+ * @returns An uncompiled instance of `tf.Model`.
+ */
+function buildModel(modelType, maxLen, vocabularySize, embeddingSize) {
+ // TODO(cais): Bidirectional and dense-only.
+ const model = tf.sequential();
+ model.add(tf.layers.embedding({
+ inputDim: vocabularySize,
+ outputDim: embeddingSize,
+ inputLength: maxLen
+ }));
+ if (modelType === 'flatten') {
+ model.add(tf.layers.flatten());
+ } else if (modelType === 'cnn') {
+ model.add(tf.layers.dropout({rate: 0.2}));
+ model.add(tf.layers.conv1d({
+ filters: 250,
+ kernelSize: 3,
+ strides: 1,
+ padding: 'valid',
+ activation: 'relu'
+ }));
+ model.add(tf.layers.globalMaxPool1d({}));
+ model.add(tf.layers.dense({units: 250, activation: 'relu'}));
+ } else if (modelType === 'simpleRNN') {
+ model.add(tf.layers.simpleRNN({units: 32}));
+ } else if (modelType === 'lstm') {
+ model.add(tf.layers.lstm({units: 32}));
+ } else if (modelType === 'bidirectionalLSTM') {
+ model.add(tf.layers.bidirectional(
+ {layer: tf.layers.lstm({units: 32}), mergeMode: 'concat'}));
+ } else {
+ throw new Error(`Unsupported model type: ${modelType}`);
+ }
+ model.add(tf.layers.dense({units: 1, activation: 'sigmoid'}));
+ return model;
+}
+
+function parseArguments() {
+ const parser = new ArgumentParser(
+ {description: 'Train a model for IMDB sentiment analysis'});
+ parser.addArgument('modelType', {
+ type: 'string',
+ optionStrings: ['flatten', 'cnn', 'simpleRNN', 'lstm', 'bidirectionalLSTM'],
+ help: 'Model type'
+ });
+ parser.addArgument('--numWords', {
+ type: 'int',
+ defaultValue: 10000,
+ help: 'Number of words in the vocabulary'
+ });
+ parser.addArgument('--maxLen', {
+ type: 'int',
+ defaultValue: 100,
+ help: 'Maximum sentence length in number of words. ' +
+ 'Shorter sentences will be padded; longers ones will be truncated.'
+ });
+ parser.addArgument('--embeddingSize', {
+ type: 'int',
+ defaultValue: 32,
+ help: 'Number of word embedding dimensions'
+ });
+ parser.addArgument(
+ '--gpu', {action: 'storeTrue', help: 'Use GPU for training'});
+ parser.addArgument('--optimizer', {
+ type: 'string',
+ defaultValue: 'adam',
+ help: 'Optimizer to be used for model training'
+ });
+ parser.addArgument(
+ '--epochs',
+ {type: 'int', defaultValue: 5, help: 'Number of training epochs'});
+ parser.addArgument(
+ '--batchSize',
+ {type: 'int', defaultValue: 128, help: 'Batch size for training'});
+ parser.addArgument('--validationSplit', {
+ type: 'float',
+ defaultValue: 0.2,
+ help: 'Validation split for training'
+ });
+ parser.addArgument('--modelSaveDir', {
+ type: 'string',
+ defaultValue: 'dist/resources',
+ help: 'Optional path for model saving.'
+ });
+ return parser.parseArgs();
+}
+
+async function main() {
+ const args = parseArguments();
+
+ if (args.gpu) {
+ console.log('Using GPU for training');
+ require('@tensorflow/tfjs-node-gpu');
+ } else {
+ console.log('Using CPU for training');
+ require('@tensorflow/tfjs-node');
+ }
+
+ console.log('Loading data...');
+ const {xTrain, yTrain, xTest, yTest} =
+ await loadData(args.numWords, args.maxLen);
+
+ console.log('Building model...');
+ const model = buildModel(
+ args.modelType, args.maxLen, args.numWords, args.embeddingSize);
+
+ model.compile({
+ loss: 'binaryCrossentropy',
+ optimizer: args.optimizer,
+ metrics: ['acc']
+ });
+ model.summary();
+
+ console.log('Training model...');
+ await model.fit(xTrain, yTrain, {
+ epochs: args.epochs,
+ batchSize: args.batchSize,
+ validationSplit: args.validationSplit
+ });
+
+ console.log('Evaluating model...');
+ const [testLoss, testAcc] =
+ model.evaluate(xTest, yTest, {batchSize: args.batchSize});
+ console.log(`Evaluation loss: ${(await testLoss.data())[0].toFixed(4)}`);
+ console.log(`Evaluation accuracy: ${(await testAcc.data())[0].toFixed(4)}`);
+
+ // Save model.
+ if (args.modelSaveDir != null && args.modelSaveDir.length > 0) {
+ // Create base directory first.
+ shelljs.mkdir('-p', args.modelSaveDir);
+
+ // Load metadata template.
+ console.log('Loading metadata template...');
+ const metadata = await loadMetadataTemplate();
+
+ // Save metadata.
+ metadata.epochs = args.epochs;
+ metadata.embedding_size = args.embeddingSize;
+ metadata.max_len = args.maxLen;
+ metadata.model_type = args.modelType;
+ metadata.batch_size = args.batchSize;
+ metadata.vocabulary_size = args.numWords;
+ const metadataPath = path.join(args.modelSaveDir, 'metadata.json');
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata));
+ console.log(`Saved metadata to ${metadataPath}`);
+
+ // Save model artifacts.
+ await model.save(`file://${args.modelSaveDir}`);
+ console.log(`Saved model to ${args.modelSaveDir}`);
+ }
+}
+
+main();
diff --git a/sentiment/ui.js b/sentiment/ui.js
index 52158e29d..d1ec878ab 100644
--- a/sentiment/ui.js
+++ b/sentiment/ui.js
@@ -54,8 +54,9 @@ function doPredict(predict) {
const reviewText = document.getElementById('review-text');
const result = predict(reviewText.value);
status(
- 'Inference result (0 - negative; 1 - positive): ' + result.score +
- ' (elapsed: ' + result.elapsed + ' ms)');
+ 'Inference result (0 - negative; 1 - positive): ' +
+ result.score.toFixed(6) +
+ ' (elapsed: ' + result.elapsed.toFixed(2) + ' ms)');
}
function setReviewText(text, predict) {
diff --git a/sentiment/yarn.lock b/sentiment/yarn.lock
index 06feffc2b..464dfbf7f 100644
--- a/sentiment/yarn.lock
+++ b/sentiment/yarn.lock
@@ -730,7 +730,35 @@
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-layers/-/tfjs-layers-0.9.2.tgz#f5c1918d1a9660096f259cd1f99f59e689b41b69"
integrity sha512-peB824cEXRBy5IgZPIodd8zpQ/54VGOYbR+zY+Q1Le7v3Np05EoDcL8Z98MtpBHo6jOM7b/3Lf2zjfJVv2qxJA==
-"@tensorflow/tfjs@^0.14.2":
+"@tensorflow/tfjs-node-gpu@0.2.3":
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-node-gpu/-/tfjs-node-gpu-0.2.3.tgz#86de49f7153aa2f814aecffe218f5f4ea9d94fe9"
+ integrity sha512-7J3azNC/gZUbO99oXuJb74ZjoPpK9Oo/IbuNTvGFNGoFUSAx8cm1b7Xe7L12Hf3enSCiO+oPbigRFBu7eg+Mxg==
+ dependencies:
+ "@tensorflow/tfjs" "~0.14.2"
+ adm-zip "^0.4.11"
+ bindings "~1.3.0"
+ https-proxy-agent "^2.2.1"
+ node-fetch "^2.3.0"
+ progress "^2.0.0"
+ rimraf "^2.6.2"
+ tar "^4.4.6"
+
+"@tensorflow/tfjs-node@0.2.3":
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-node/-/tfjs-node-0.2.3.tgz#9408e7162bf27c7f8c59984c30c3141e6d8ec817"
+ integrity sha512-+VXi6GLsVXXido2DhzK2e1Y/qM9MvQNbbA00TFgGuVbGMmeX0ey97t6W23dT8dnDVPZprC2XSFumcpRoKe8ENg==
+ dependencies:
+ "@tensorflow/tfjs" "~0.14.2"
+ adm-zip "^0.4.11"
+ bindings "~1.3.0"
+ https-proxy-agent "^2.2.1"
+ node-fetch "^2.3.0"
+ progress "^2.0.0"
+ rimraf "^2.6.2"
+ tar "^4.4.6"
+
+"@tensorflow/tfjs@0.14.2", "@tensorflow/tfjs@~0.14.2":
version "0.14.2"
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs/-/tfjs-0.14.2.tgz#f38fa572286dadfe981c219f5639defd586c20c4"
integrity sha512-d+kBdhn3L/BOIwwc44V1lUrs0O5s49ujhYXVHT9Hs6y3yq+OqPK10am16H1fNcxeMn12/3gGphebglObTD0/Sg==
@@ -757,15 +785,10 @@
dependencies:
"@types/node" "*"
-"@types/node@*":
- version "10.12.12"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.12.tgz#e15a9d034d9210f00320ef718a50c4a799417c47"
- integrity sha512-Pr+6JRiKkfsFvmU/LK68oBRCQeEg36TyAbPhc2xpez24OOZZCuoIhWGTd39VZy6nGafSbxzGouFPTFD/rR1A0A==
-
-"@types/node@^10.1.0":
- version "10.12.10"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.10.tgz#4fa76e6598b7de3f0cb6ec3abacc4f59e5b3a2ce"
- integrity sha512-8xZEYckCbUVgK8Eg7lf5Iy4COKJ5uXlnIOnePN0WUwSQggy9tolM+tDJf7wMOnT/JT/W9xDYIaYggt3mRV2O5w==
+"@types/node@*", "@types/node@^10.1.0":
+ version "10.12.18"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
+ integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
"@types/node@^10.11.7":
version "10.12.0"
@@ -798,6 +821,18 @@ acorn@^5.0.0:
version "5.7.3"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
+adm-zip@^0.4.11:
+ version "0.4.13"
+ resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a"
+ integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==
+
+agent-base@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
+ integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==
+ dependencies:
+ es6-promisify "^5.0.0"
+
alphanum-sort@^1.0.0, alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
@@ -826,6 +861,14 @@ ansi-to-html@^0.6.4:
dependencies:
entities "^1.1.1"
+anymatch@^1.3.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
+ integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==
+ dependencies:
+ micromatch "^2.1.5"
+ normalize-path "^2.0.0"
+
anymatch@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
@@ -844,17 +887,25 @@ are-we-there-yet@~1.1.2:
delegates "^1.0.0"
readable-stream "^2.0.6"
-argparse@^1.0.7:
+argparse@^1.0.10, argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
dependencies:
sprintf-js "~1.0.2"
+arr-diff@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+ integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=
+ dependencies:
+ arr-flatten "^1.0.1"
+
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
-arr-flatten@^1.1.0:
+arr-flatten@^1.0.1, arr-flatten@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
@@ -872,6 +923,11 @@ array-uniq@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
+array-unique@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+ integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=
+
array-unique@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
@@ -929,6 +985,28 @@ autoprefixer@^6.3.1:
postcss "^5.2.16"
postcss-value-parser "^3.2.3"
+babel-cli@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1"
+ integrity sha1-UCq1SHTX24itALiHoGODzgPQAvE=
+ dependencies:
+ babel-core "^6.26.0"
+ babel-polyfill "^6.26.0"
+ babel-register "^6.26.0"
+ babel-runtime "^6.26.0"
+ commander "^2.11.0"
+ convert-source-map "^1.5.0"
+ fs-readdir-recursive "^1.0.0"
+ glob "^7.1.2"
+ lodash "^4.17.4"
+ output-file-sync "^1.1.2"
+ path-is-absolute "^1.0.1"
+ slash "^1.0.0"
+ source-map "^0.5.6"
+ v8flags "^2.1.1"
+ optionalDependencies:
+ chokidar "^1.6.1"
+
babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -1313,9 +1391,10 @@ babel-plugin-transform-strict-mode@^6.24.1:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
-babel-polyfill@~6.26.0:
+babel-polyfill@^6.26.0, babel-polyfill@~6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153"
+ integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=
dependencies:
babel-runtime "^6.26.0"
core-js "^2.5.0"
@@ -1431,6 +1510,7 @@ balanced-match@^0.4.2:
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+ integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base64-js@^1.0.2:
version "1.3.0"
@@ -1456,6 +1536,11 @@ bindings@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11"
+bindings@~1.3.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.1.tgz#21fc7c6d67c18516ec5aaa2815b145ff77b26ea5"
+ integrity sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==
+
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
version "4.11.8"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
@@ -1467,10 +1552,20 @@ boolbase@^1.0.0, boolbase@~1.0.0:
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
+braces@^1.8.2:
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+ integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=
+ dependencies:
+ expand-range "^1.8.1"
+ preserve "^0.2.0"
+ repeat-element "^1.1.2"
+
braces@^2.3.0, braces@^2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
@@ -1672,6 +1767,22 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.4.1:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
+chokidar@^1.6.1:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+ integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=
+ dependencies:
+ anymatch "^1.3.0"
+ async-each "^1.0.0"
+ glob-parent "^2.0.0"
+ inherits "^2.0.1"
+ is-binary-path "^1.0.0"
+ is-glob "^2.0.0"
+ path-is-absolute "^1.0.0"
+ readdirp "^2.0.0"
+ optionalDependencies:
+ fsevents "^1.0.0"
+
chokidar@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26"
@@ -1691,9 +1802,10 @@ chokidar@^2.0.3:
optionalDependencies:
fsevents "^1.2.2"
-chownr@^1.0.1:
+chownr@^1.0.1, chownr@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
+ integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
@@ -1870,10 +1982,12 @@ component-emitter@^1.2.1:
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-concat-stream@~1.6.0:
+concat-stream@1.6.2, concat-stream@~1.6.0:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+ integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
dependencies:
buffer-from "^1.0.0"
inherits "^2.0.3"
@@ -1901,7 +2015,7 @@ constants-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
-convert-source-map@^1.1.0, convert-source-map@^1.5.1:
+convert-source-map@^1.1.0, convert-source-map@^1.5.0, convert-source-map@^1.5.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
dependencies:
@@ -2297,6 +2411,7 @@ debug@=3.1.0:
debug@^3.1.0:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
+ integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
dependencies:
ms "^2.1.1"
@@ -2540,6 +2655,18 @@ es-to-primitive@^1.1.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
+es6-promise@^4.0.3:
+ version "4.2.5"
+ resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
+ integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==
+
+es6-promisify@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
+ integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
+ dependencies:
+ es6-promise "^4.0.3"
+
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@@ -2638,6 +2765,13 @@ execa@^0.10.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+expand-brackets@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+ integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=
+ dependencies:
+ is-posix-bracket "^0.1.0"
+
expand-brackets@^2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
@@ -2650,6 +2784,13 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
+expand-range@^1.8.1:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+ integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=
+ dependencies:
+ fill-range "^2.1.0"
+
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@@ -2663,6 +2804,13 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
+extglob@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+ integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=
+ dependencies:
+ is-extglob "^1.0.0"
+
extglob@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
@@ -2676,6 +2824,16 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
+extract-zip@^1.6.7:
+ version "1.6.7"
+ resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9"
+ integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=
+ dependencies:
+ concat-stream "1.6.2"
+ debug "2.6.9"
+ mkdirp "0.5.1"
+ yauzl "2.4.1"
+
falafel@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.1.0.tgz#96bb17761daba94f46d001738b3cedf3a67fe06c"
@@ -2700,10 +2858,33 @@ fast-levenshtein@~2.0.4:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+fd-slicer@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
+ integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=
+ dependencies:
+ pend "~1.2.0"
+
+filename-regex@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
+ integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=
+
filesize@^3.6.0:
version "3.6.1"
resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317"
+fill-range@^2.1.0:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565"
+ integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==
+ dependencies:
+ is-number "^2.1.0"
+ isobject "^2.0.0"
+ randomatic "^3.0.0"
+ repeat-element "^1.1.2"
+ repeat-string "^1.5.2"
+
fill-range@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
@@ -2736,10 +2917,17 @@ follow-redirects@^1.0.0:
dependencies:
debug "=3.1.0"
-for-in@^1.0.2:
+for-in@^1.0.1, for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+for-own@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+ integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
+ dependencies:
+ for-in "^1.0.1"
+
foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
@@ -2765,16 +2953,24 @@ fs-extra@^4.0.2:
fs-minipass@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
+ integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==
dependencies:
minipass "^2.2.1"
+fs-readdir-recursive@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27"
+ integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==
+
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-fsevents@^1.2.2:
+fsevents@^1.0.0, fsevents@^1.2.2:
version "1.2.4"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426"
+ integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==
dependencies:
nan "^2.9.2"
node-pre-gyp "^0.10.0"
@@ -2842,6 +3038,21 @@ get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+glob-base@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+ integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=
+ dependencies:
+ glob-parent "^2.0.0"
+ is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+ integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=
+ dependencies:
+ is-glob "^2.0.0"
+
glob-parent@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
@@ -2853,9 +3064,10 @@ glob-to-regexp@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
-glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1:
+glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
+ integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
@@ -2887,6 +3099,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+graceful-fs@^4.1.4:
+ version "4.1.15"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
+ integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
+
grapheme-breaker@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/grapheme-breaker/-/grapheme-breaker-0.3.2.tgz#5b9e6b78c3832452d2ba2bb1cb830f96276410ac"
@@ -3058,6 +3275,14 @@ https-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
+https-proxy-agent@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
+ integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==
+ dependencies:
+ agent-base "^4.1.0"
+ debug "^3.1.0"
+
iconv-lite@0.4, iconv-lite@^0.4.4:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -3089,6 +3314,7 @@ indexof@0.0.1:
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
dependencies:
once "^1.3.0"
wrappy "1"
@@ -3105,6 +3331,11 @@ ini@^1.3.4, ini@~1.3.0:
version "1.3.5"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+interpret@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
+ integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
+
invariant@^2.2.0, invariant@^2.2.2:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@@ -3210,6 +3441,18 @@ is-directory@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
+is-dotfile@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
+ integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=
+
+is-equal-shallow@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+ integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=
+ dependencies:
+ is-primitive "^2.0.0"
+
is-extendable@^0.1.0, is-extendable@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
@@ -3220,6 +3463,11 @@ is-extendable@^1.0.1:
dependencies:
is-plain-object "^2.0.4"
+is-extglob@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+ integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
+
is-extglob@^2.1.0, is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
@@ -3240,6 +3488,13 @@ is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+is-glob@^2.0.0, is-glob@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+ integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=
+ dependencies:
+ is-extglob "^1.0.0"
+
is-glob@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
@@ -3252,12 +3507,24 @@ is-glob@^4.0.0:
dependencies:
is-extglob "^2.1.1"
+is-number@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+ integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=
+ dependencies:
+ kind-of "^3.0.2"
+
is-number@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
dependencies:
kind-of "^3.0.2"
+is-number@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
+ integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
+
is-obj@^1.0.0:
version "1.0.1"
resolved "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
@@ -3288,6 +3555,16 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
dependencies:
isobject "^3.0.1"
+is-posix-bracket@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+ integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=
+
+is-primitive@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+ integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
+
is-regex@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
@@ -3581,6 +3858,11 @@ math-expression-evaluator@^1.2.14:
version "1.2.17"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
+math-random@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac"
+ integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w=
+
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -3611,6 +3893,25 @@ merge2@^1.2.1:
version "1.2.3"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
+micromatch@^2.1.5:
+ version "2.3.11"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+ integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=
+ dependencies:
+ arr-diff "^2.0.0"
+ array-unique "^0.2.1"
+ braces "^1.8.2"
+ expand-brackets "^0.1.4"
+ extglob "^0.3.1"
+ filename-regex "^2.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.1"
+ kind-of "^3.0.2"
+ normalize-path "^2.0.1"
+ object.omit "^2.0.0"
+ parse-glob "^3.0.4"
+ regex-cache "^0.4.2"
+
micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
@@ -3659,12 +3960,14 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
minimatch@^3.0.0, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
minimist@0.0.8:
version "0.0.8"
- resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+ integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0:
version "1.2.0"
@@ -3674,7 +3977,15 @@ minimist@~0.0.1:
version "0.0.10"
resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
-minipass@^2.2.1, minipass@^2.3.3:
+minipass@^2.2.1, minipass@^2.3.4:
+ version "2.3.5"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
+ integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
+ dependencies:
+ safe-buffer "^5.1.2"
+ yallist "^3.0.0"
+
+minipass@^2.3.3:
version "2.3.4"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957"
dependencies:
@@ -3687,6 +3998,13 @@ minizlib@^1.1.0:
dependencies:
minipass "^2.2.1"
+minizlib@^1.1.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
+ integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
+ dependencies:
+ minipass "^2.2.1"
+
mixin-deep@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
@@ -3694,7 +4012,7 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
-mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
+mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
version "0.5.1"
resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
@@ -3707,6 +4025,7 @@ ms@2.0.0:
ms@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+ integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
nan@^2.0.7, nan@^2.9.2:
version "2.11.1"
@@ -3744,6 +4063,11 @@ node-fetch@^2.1.2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.2.0.tgz#4ee79bde909262f9775f731e3656d0db55ced5b5"
+node-fetch@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5"
+ integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==
+
node-fetch@~2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5"
@@ -3818,9 +4142,10 @@ normalize-package-data@^2.3.2:
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
-normalize-path@^2.1.1:
+normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+ integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
dependencies:
remove-trailing-separator "^1.0.1"
@@ -3914,6 +4239,14 @@ object.getownpropertydescriptors@^2.0.3:
define-properties "^1.1.2"
es-abstract "^1.5.1"
+object.omit@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+ integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=
+ dependencies:
+ for-own "^0.1.4"
+ is-extendable "^0.1.1"
+
object.pick@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
@@ -3938,6 +4271,7 @@ on-finished@~2.3.0:
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
@@ -4025,6 +4359,15 @@ osenv@^0.1.4:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
+output-file-sync@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76"
+ integrity sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=
+ dependencies:
+ graceful-fs "^4.1.4"
+ mkdirp "^0.5.1"
+ object-assign "^4.1.0"
+
p-defer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
@@ -4133,6 +4476,16 @@ parse-asn1@^5.0.0:
evp_bytestokey "^1.0.0"
pbkdf2 "^3.0.3"
+parse-glob@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+ integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw=
+ dependencies:
+ glob-base "^0.3.0"
+ is-dotfile "^1.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.0"
+
parse-json@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
@@ -4206,6 +4559,11 @@ pbkdf2@^3.0.3:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
+pend@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
+ integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
+
physical-cpu-count@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/physical-cpu-count/-/physical-cpu-count-2.0.0.tgz#18de2f97e4bf7a9551ad7511942b5496f7aba660"
@@ -4753,6 +5111,11 @@ prepend-http@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
+preserve@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+ integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
+
pretty-bytes@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
@@ -4769,6 +5132,11 @@ process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+progress@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+ integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
proto-list@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
@@ -4846,6 +5214,15 @@ quote-stream@^1.0.1, quote-stream@~1.0.2:
minimist "^1.1.3"
through2 "^2.0.0"
+randomatic@^3.0.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
+ integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==
+ dependencies:
+ is-number "^4.0.0"
+ kind-of "^6.0.0"
+ math-random "^1.0.1"
+
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80"
@@ -4915,6 +5292,13 @@ readdirp@^2.0.0:
micromatch "^3.1.10"
readable-stream "^2.0.2"
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
+ dependencies:
+ resolve "^1.1.6"
+
reduce-css-calc@^1.2.6:
version "1.3.0"
resolved "http://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
@@ -4965,6 +5349,13 @@ regenerator-transform@^0.13.3:
dependencies:
private "^0.1.6"
+regex-cache@^0.4.2:
+ version "0.4.4"
+ resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
+ integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==
+ dependencies:
+ is-equal-shallow "^0.1.3"
+
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
@@ -5019,7 +5410,7 @@ repeat-element@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
-repeat-string@^1.6.1:
+repeat-string@^1.5.2, repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
@@ -5076,6 +5467,13 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.6.1:
dependencies:
glob "^7.0.5"
+rimraf@^2.6.2:
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+ integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+ dependencies:
+ glob "^7.1.3"
+
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@@ -5210,6 +5608,15 @@ shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+shelljs@^0.8.3:
+ version "0.8.3"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
+ integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==
+ dependencies:
+ glob "^7.0.0"
+ interpret "^1.0.0"
+ rechoir "^0.6.2"
+
sigmund@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
@@ -5507,6 +5914,19 @@ tar@^4:
safe-buffer "^5.1.2"
yallist "^3.0.2"
+tar@^4.4.6:
+ version "4.4.8"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
+ integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
+ dependencies:
+ chownr "^1.1.1"
+ fs-minipass "^1.2.5"
+ minipass "^2.3.4"
+ minizlib "^1.1.1"
+ mkdirp "^0.5.0"
+ safe-buffer "^5.1.2"
+ yallist "^3.0.2"
+
terser@^3.7.3, terser@^3.8.1:
version "3.10.2"
resolved "https://registry.yarnpkg.com/terser/-/terser-3.10.2.tgz#a61d2c97065f9fdc8c49a18655e2a80ca7298a94"
@@ -5693,6 +6113,11 @@ use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+user-home@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
+ integrity sha1-K1viOjK2Onyd640PKNSFcko98ZA=
+
user-home@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
@@ -5726,6 +6151,13 @@ v8-compile-cache@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c"
+v8flags@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
+ integrity sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=
+ dependencies:
+ user-home "^1.1.1"
+
validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
@@ -6061,6 +6493,7 @@ wrap-ansi@^2.0.0:
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@^5.1.1:
version "5.2.2"
@@ -6102,8 +6535,9 @@ yallist@^2.1.2:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
yallist@^3.0.0, yallist@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
+ integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
yargs-parser@^10.1.0:
version "10.1.0"
@@ -6151,3 +6585,10 @@ yargs@^7.1.0:
which-module "^1.0.0"
y18n "^3.2.1"
yargs-parser "^5.0.0"
+
+yauzl@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
+ integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=
+ dependencies:
+ fd-slicer "~1.0.1"