summaryrefslogtreecommitdiffstats
path: root/security/nss/automation/taskcluster
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/automation/taskcluster')
-rw-r--r--security/nss/automation/taskcluster/docker-arm/Dockerfile27
-rwxr-xr-xsecurity/nss/automation/taskcluster/docker-arm/bin/checkout.sh25
-rwxr-xr-xsecurity/nss/automation/taskcluster/docker-arm/bin/uname.sh18
-rwxr-xr-xsecurity/nss/automation/taskcluster/docker-arm/setup.sh35
-rw-r--r--security/nss/automation/taskcluster/docker-decision/Dockerfile27
-rw-r--r--security/nss/automation/taskcluster/docker-decision/bin/checkout.sh20
-rw-r--r--security/nss/automation/taskcluster/docker-decision/setup.sh31
-rw-r--r--security/nss/automation/taskcluster/docker/Dockerfile27
-rw-r--r--security/nss/automation/taskcluster/docker/bin/checkout.sh20
-rw-r--r--security/nss/automation/taskcluster/docker/setup.sh62
-rw-r--r--security/nss/automation/taskcluster/graph/npm-shrinkwrap.json1643
-rw-r--r--security/nss/automation/taskcluster/graph/package.json24
-rw-r--r--security/nss/automation/taskcluster/graph/src/context_hash.js43
-rw-r--r--security/nss/automation/taskcluster/graph/src/extend.js572
-rw-r--r--security/nss/automation/taskcluster/graph/src/image_builder.js62
-rw-r--r--security/nss/automation/taskcluster/graph/src/index.js14
-rw-r--r--security/nss/automation/taskcluster/graph/src/merge.js10
-rw-r--r--security/nss/automation/taskcluster/graph/src/queue.js242
-rw-r--r--security/nss/automation/taskcluster/graph/src/try_syntax.js159
-rwxr-xr-xsecurity/nss/automation/taskcluster/scripts/build.sh18
-rwxr-xr-xsecurity/nss/automation/taskcluster/scripts/build_gyp.sh18
-rwxr-xr-xsecurity/nss/automation/taskcluster/scripts/extend_task_graph.sh16
-rwxr-xr-xsecurity/nss/automation/taskcluster/scripts/fuzz.sh20
-rwxr-xr-xsecurity/nss/automation/taskcluster/scripts/gen_certs.sh26
-rwxr-xr-xsecurity/nss/automation/taskcluster/scripts/run_clang_format.sh63
-rwxr-xr-xsecurity/nss/automation/taskcluster/scripts/run_scan_build.sh56
-rwxr-xr-xsecurity/nss/automation/taskcluster/scripts/run_tests.sh17
-rw-r--r--security/nss/automation/taskcluster/scripts/tools.sh28
-rw-r--r--security/nss/automation/taskcluster/windows/build.sh15
-rw-r--r--security/nss/automation/taskcluster/windows/gen_certs.sh19
-rw-r--r--security/nss/automation/taskcluster/windows/releng.manifest10
-rw-r--r--security/nss/automation/taskcluster/windows/run_tests.sh13
-rw-r--r--security/nss/automation/taskcluster/windows/setup.sh30
33 files changed, 3410 insertions, 0 deletions
diff --git a/security/nss/automation/taskcluster/docker-arm/Dockerfile b/security/nss/automation/taskcluster/docker-arm/Dockerfile
new file mode 100644
index 000000000..9a7e50201
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker-arm/Dockerfile
@@ -0,0 +1,27 @@
+FROM armv7/armhf-ubuntu:16.04
+MAINTAINER Franziskus Kiefer <franziskuskiefer@gmail.com>
+
+RUN useradd -d /home/worker -s /bin/bash -m worker
+WORKDIR /home/worker
+
+# Add build and test scripts.
+ADD bin /home/worker/bin
+RUN chmod +x /home/worker/bin/*
+
+# Install dependencies.
+ADD setup.sh /tmp/setup.sh
+RUN bash /tmp/setup.sh
+
+# Env variables.
+ENV HOME /home/worker
+ENV SHELL /bin/bash
+ENV USER worker
+ENV LOGNAME worker
+ENV HOSTNAME taskcluster-worker
+ENV LANG en_US.UTF-8
+ENV LC_ALL en_US.UTF-8
+ENV HOST localhost
+ENV DOMSUF localdomain
+
+# Set a default command for debugging.
+CMD ["/bin/bash", "--login"]
diff --git a/security/nss/automation/taskcluster/docker-arm/bin/checkout.sh b/security/nss/automation/taskcluster/docker-arm/bin/checkout.sh
new file mode 100755
index 000000000..4b891289d
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker-arm/bin/checkout.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) = 0 ]; then
+ # set up fake uname
+ if [ ! -f /bin/uname-real ]; then
+ mv /bin/uname /bin/uname-real
+ ln -s /home/worker/bin/uname.sh /bin/uname
+ fi
+ # Drop privileges by re-running this script.
+ exec su worker $0
+fi
+
+# Default values for testing.
+REVISION=${NSS_HEAD_REVISION:-default}
+REPOSITORY=${NSS_HEAD_REPOSITORY:-https://hg.mozilla.org/projects/nss}
+
+# Clone NSS.
+for i in 0 2 5; do
+ sleep $i
+ hg clone -r $REVISION $REPOSITORY nss && exit 0
+ rm -rf nss
+done
+exit 1
diff --git a/security/nss/automation/taskcluster/docker-arm/bin/uname.sh b/security/nss/automation/taskcluster/docker-arm/bin/uname.sh
new file mode 100755
index 000000000..61ad13c34
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker-arm/bin/uname.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+args=`getopt rmvs $*`
+set -- $args
+for i
+do
+ if [ "$i" == "-v" ]; then
+ /bin/uname-real -v
+ fi
+ if [ "$i" == "-r" ]; then
+ echo "4.4.16-v7+"
+ fi
+ if [ "$i" == "-m" ]; then
+ echo "armv7l"
+ fi
+ if [ "$i" == "-s" ]; then
+ echo "Linux"
+ fi
+done \ No newline at end of file
diff --git a/security/nss/automation/taskcluster/docker-arm/setup.sh b/security/nss/automation/taskcluster/docker-arm/setup.sh
new file mode 100755
index 000000000..42d66a454
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker-arm/setup.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+export DEBIAN_FRONTEND=noninteractive
+
+# Update.
+apt-get -y update
+apt-get -y dist-upgrade
+
+apt_packages=()
+apt_packages+=('build-essential')
+apt_packages+=('ca-certificates')
+apt_packages+=('curl')
+apt_packages+=('python-dev')
+apt_packages+=('python-pip')
+apt_packages+=('python-setuptools')
+apt_packages+=('zlib1g-dev')
+
+# Install packages.
+apt-get install -y --no-install-recommends ${apt_packages[@]}
+
+# Latest Mercurial.
+pip install --upgrade pip
+pip install Mercurial
+
+locale-gen en_US.UTF-8
+dpkg-reconfigure locales
+
+# Cleanup.
+rm -rf ~/.ccache ~/.cache
+apt-get autoremove -y
+apt-get clean
+apt-get autoclean
+rm $0
diff --git a/security/nss/automation/taskcluster/docker-decision/Dockerfile b/security/nss/automation/taskcluster/docker-decision/Dockerfile
new file mode 100644
index 000000000..35777c0b7
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker-decision/Dockerfile
@@ -0,0 +1,27 @@
+FROM ubuntu:16.04
+MAINTAINER Tim Taubert <ttaubert@mozilla.com>
+
+RUN useradd -d /home/worker -s /bin/bash -m worker
+WORKDIR /home/worker
+
+# Add build and test scripts.
+ADD bin /home/worker/bin
+RUN chmod +x /home/worker/bin/*
+
+# Install dependencies.
+ADD setup.sh /tmp/setup.sh
+RUN bash /tmp/setup.sh
+
+# Env variables.
+ENV HOME /home/worker
+ENV SHELL /bin/bash
+ENV USER worker
+ENV LOGNAME worker
+ENV HOSTNAME taskcluster-worker
+ENV LANG en_US.UTF-8
+ENV LC_ALL en_US.UTF-8
+ENV HOST localhost
+ENV DOMSUF localdomain
+
+# Set a default command for debugging.
+CMD ["/bin/bash", "--login"]
diff --git a/security/nss/automation/taskcluster/docker-decision/bin/checkout.sh b/security/nss/automation/taskcluster/docker-decision/bin/checkout.sh
new file mode 100644
index 000000000..9167f6bda
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker-decision/bin/checkout.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) = 0 ]; then
+ # Drop privileges by re-running this script.
+ exec su worker $0
+fi
+
+# Default values for testing.
+REVISION=${NSS_HEAD_REVISION:-default}
+REPOSITORY=${NSS_HEAD_REPOSITORY:-https://hg.mozilla.org/projects/nss}
+
+# Clone NSS.
+for i in 0 2 5; do
+ sleep $i
+ hg clone -r $REVISION $REPOSITORY nss && exit 0
+ rm -rf nss
+done
+exit 1
diff --git a/security/nss/automation/taskcluster/docker-decision/setup.sh b/security/nss/automation/taskcluster/docker-decision/setup.sh
new file mode 100644
index 000000000..e5a6d2019
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker-decision/setup.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Update packages.
+export DEBIAN_FRONTEND=noninteractive
+apt-get -y update && apt-get -y upgrade
+
+# Need those to install newer packages below.
+apt-get install -y --no-install-recommends apt-utils curl ca-certificates
+
+# Latest Mercurial.
+apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 41BD8711B1F0EC2B0D85B91CF59CE3A8323293EE
+echo "deb http://ppa.launchpad.net/mercurial-ppa/releases/ubuntu xenial main" > /etc/apt/sources.list.d/mercurial.list
+
+# Install packages.
+apt-get -y update && apt-get install -y --no-install-recommends mercurial
+
+# Latest Node.JS.
+curl -sL https://deb.nodesource.com/setup_6.x | bash -
+apt-get install -y --no-install-recommends nodejs
+
+locale-gen en_US.UTF-8
+dpkg-reconfigure locales
+
+# Cleanup.
+rm -rf ~/.ccache ~/.cache
+apt-get autoremove -y
+apt-get clean
+apt-get autoclean
+rm $0
diff --git a/security/nss/automation/taskcluster/docker/Dockerfile b/security/nss/automation/taskcluster/docker/Dockerfile
new file mode 100644
index 000000000..35777c0b7
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker/Dockerfile
@@ -0,0 +1,27 @@
+FROM ubuntu:16.04
+MAINTAINER Tim Taubert <ttaubert@mozilla.com>
+
+RUN useradd -d /home/worker -s /bin/bash -m worker
+WORKDIR /home/worker
+
+# Add build and test scripts.
+ADD bin /home/worker/bin
+RUN chmod +x /home/worker/bin/*
+
+# Install dependencies.
+ADD setup.sh /tmp/setup.sh
+RUN bash /tmp/setup.sh
+
+# Env variables.
+ENV HOME /home/worker
+ENV SHELL /bin/bash
+ENV USER worker
+ENV LOGNAME worker
+ENV HOSTNAME taskcluster-worker
+ENV LANG en_US.UTF-8
+ENV LC_ALL en_US.UTF-8
+ENV HOST localhost
+ENV DOMSUF localdomain
+
+# Set a default command for debugging.
+CMD ["/bin/bash", "--login"]
diff --git a/security/nss/automation/taskcluster/docker/bin/checkout.sh b/security/nss/automation/taskcluster/docker/bin/checkout.sh
new file mode 100644
index 000000000..9167f6bda
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker/bin/checkout.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) = 0 ]; then
+ # Drop privileges by re-running this script.
+ exec su worker $0
+fi
+
+# Default values for testing.
+REVISION=${NSS_HEAD_REVISION:-default}
+REPOSITORY=${NSS_HEAD_REPOSITORY:-https://hg.mozilla.org/projects/nss}
+
+# Clone NSS.
+for i in 0 2 5; do
+ sleep $i
+ hg clone -r $REVISION $REPOSITORY nss && exit 0
+ rm -rf nss
+done
+exit 1
diff --git a/security/nss/automation/taskcluster/docker/setup.sh b/security/nss/automation/taskcluster/docker/setup.sh
new file mode 100644
index 000000000..4969f4aa0
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker/setup.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Update packages.
+export DEBIAN_FRONTEND=noninteractive
+apt-get -y update && apt-get -y upgrade
+
+# Need this to add keys for PPAs below.
+apt-get install -y --no-install-recommends apt-utils
+
+apt_packages=()
+apt_packages+=('build-essential')
+apt_packages+=('ca-certificates')
+apt_packages+=('curl')
+apt_packages+=('npm')
+apt_packages+=('git')
+apt_packages+=('golang-1.6')
+apt_packages+=('ninja-build')
+apt_packages+=('pkg-config')
+apt_packages+=('zlib1g-dev')
+
+# 32-bit builds
+apt_packages+=('lib32z1-dev')
+apt_packages+=('gcc-multilib')
+apt_packages+=('g++-multilib')
+
+# ct-verif and sanitizers
+apt_packages+=('valgrind')
+
+# Latest Mercurial.
+apt_packages+=('mercurial')
+apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 41BD8711B1F0EC2B0D85B91CF59CE3A8323293EE
+echo "deb http://ppa.launchpad.net/mercurial-ppa/releases/ubuntu xenial main" > /etc/apt/sources.list.d/mercurial.list
+
+# gcc 4.8 and 6
+apt_packages+=('g++-6')
+apt_packages+=('g++-4.8')
+apt_packages+=('g++-6-multilib')
+apt_packages+=('g++-4.8-multilib')
+apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 60C317803A41BA51845E371A1E9377A2BA9EF27F
+echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" > /etc/apt/sources.list.d/toolchain.list
+
+# Install packages.
+apt-get -y update
+apt-get install -y --no-install-recommends ${apt_packages[@]}
+
+# 32-bit builds
+ln -s /usr/include/x86_64-linux-gnu/zconf.h /usr/include
+
+# Install clang-3.9 into /usr/local/.
+curl -L http://llvm.org/releases/3.9.0/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar xJv -C /usr/local --strip-components=1
+
+locale-gen en_US.UTF-8
+dpkg-reconfigure locales
+
+# Cleanup.
+rm -rf ~/.ccache ~/.cache
+apt-get autoremove -y
+apt-get clean
+apt-get autoclean
+rm $0
diff --git a/security/nss/automation/taskcluster/graph/npm-shrinkwrap.json b/security/nss/automation/taskcluster/graph/npm-shrinkwrap.json
new file mode 100644
index 000000000..b805bb8ed
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/npm-shrinkwrap.json
@@ -0,0 +1,1643 @@
+{
+ "name": "decision-task",
+ "version": "0.0.1",
+ "dependencies": {
+ "amqplib": {
+ "version": "0.4.2",
+ "from": "amqplib@>=0.4.1 <0.5.0",
+ "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.4.2.tgz",
+ "dependencies": {
+ "isarray": {
+ "version": "0.0.1",
+ "from": "isarray@0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+ },
+ "readable-stream": {
+ "version": "1.1.14",
+ "from": "readable-stream@>=1.0.0 <2.0.0 >=1.1.9",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz"
+ }
+ }
+ },
+ "ansi-regex": {
+ "version": "2.0.0",
+ "from": "ansi-regex@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "from": "ansi-styles@>=2.1.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
+ },
+ "anymatch": {
+ "version": "1.3.0",
+ "from": "anymatch@>=1.3.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz"
+ },
+ "argparse": {
+ "version": "1.0.9",
+ "from": "argparse@>=1.0.7 <2.0.0",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz"
+ },
+ "arr-diff": {
+ "version": "2.0.0",
+ "from": "arr-diff@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz"
+ },
+ "arr-flatten": {
+ "version": "1.0.1",
+ "from": "arr-flatten@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz"
+ },
+ "array-find-index": {
+ "version": "1.0.2",
+ "from": "array-find-index@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz"
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "from": "array-uniq@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz"
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "from": "array-unique@>=0.2.1 <0.3.0",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz"
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "from": "arrify@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz"
+ },
+ "asap": {
+ "version": "1.0.0",
+ "from": "asap@>=1.0.0 <1.1.0",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz"
+ },
+ "asn1": {
+ "version": "0.2.3",
+ "from": "asn1@>=0.2.3 <0.3.0",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"
+ },
+ "assert-plus": {
+ "version": "0.2.0",
+ "from": "assert-plus@>=0.2.0 <0.3.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
+ },
+ "async": {
+ "version": "2.1.1",
+ "from": "async@*",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.1.1.tgz"
+ },
+ "async-each": {
+ "version": "1.0.1",
+ "from": "async-each@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz"
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "from": "asynckit@>=0.4.0 <0.5.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
+ },
+ "aws-sign2": {
+ "version": "0.6.0",
+ "from": "aws-sign2@>=0.6.0 <0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+ },
+ "aws4": {
+ "version": "1.5.0",
+ "from": "aws4@>=1.2.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.5.0.tgz"
+ },
+ "babel-cli": {
+ "version": "6.16.0",
+ "from": "babel-cli@>=6.14.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.16.0.tgz"
+ },
+ "babel-code-frame": {
+ "version": "6.16.0",
+ "from": "babel-code-frame@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.16.0.tgz"
+ },
+ "babel-compile": {
+ "version": "2.0.0",
+ "from": "babel-compile@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/babel-compile/-/babel-compile-2.0.0.tgz"
+ },
+ "babel-core": {
+ "version": "6.17.0",
+ "from": "babel-core@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.17.0.tgz"
+ },
+ "babel-generator": {
+ "version": "6.17.0",
+ "from": "babel-generator@>=6.17.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.17.0.tgz"
+ },
+ "babel-helper-call-delegate": {
+ "version": "6.8.0",
+ "from": "babel-helper-call-delegate@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.8.0.tgz"
+ },
+ "babel-helper-define-map": {
+ "version": "6.9.0",
+ "from": "babel-helper-define-map@>=6.9.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.9.0.tgz"
+ },
+ "babel-helper-function-name": {
+ "version": "6.8.0",
+ "from": "babel-helper-function-name@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.8.0.tgz"
+ },
+ "babel-helper-get-function-arity": {
+ "version": "6.8.0",
+ "from": "babel-helper-get-function-arity@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.8.0.tgz"
+ },
+ "babel-helper-hoist-variables": {
+ "version": "6.8.0",
+ "from": "babel-helper-hoist-variables@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.8.0.tgz"
+ },
+ "babel-helper-optimise-call-expression": {
+ "version": "6.8.0",
+ "from": "babel-helper-optimise-call-expression@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.8.0.tgz"
+ },
+ "babel-helper-regex": {
+ "version": "6.9.0",
+ "from": "babel-helper-regex@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.9.0.tgz"
+ },
+ "babel-helper-remap-async-to-generator": {
+ "version": "6.16.2",
+ "from": "babel-helper-remap-async-to-generator@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.16.2.tgz"
+ },
+ "babel-helper-replace-supers": {
+ "version": "6.16.0",
+ "from": "babel-helper-replace-supers@>=6.14.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.16.0.tgz"
+ },
+ "babel-helpers": {
+ "version": "6.16.0",
+ "from": "babel-helpers@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.16.0.tgz"
+ },
+ "babel-messages": {
+ "version": "6.8.0",
+ "from": "babel-messages@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.8.0.tgz"
+ },
+ "babel-plugin-check-es2015-constants": {
+ "version": "6.8.0",
+ "from": "babel-plugin-check-es2015-constants@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.8.0.tgz"
+ },
+ "babel-plugin-syntax-async-functions": {
+ "version": "6.13.0",
+ "from": "babel-plugin-syntax-async-functions@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz"
+ },
+ "babel-plugin-transform-async-to-generator": {
+ "version": "6.16.0",
+ "from": "babel-plugin-transform-async-to-generator@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.16.0.tgz"
+ },
+ "babel-plugin-transform-es2015-arrow-functions": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-arrow-functions@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-block-scoped-functions": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-block-scoped-functions@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-block-scoping": {
+ "version": "6.15.0",
+ "from": "babel-plugin-transform-es2015-block-scoping@>=6.14.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.15.0.tgz"
+ },
+ "babel-plugin-transform-es2015-classes": {
+ "version": "6.14.0",
+ "from": "babel-plugin-transform-es2015-classes@>=6.14.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.14.0.tgz"
+ },
+ "babel-plugin-transform-es2015-computed-properties": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-computed-properties@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-destructuring": {
+ "version": "6.16.0",
+ "from": "babel-plugin-transform-es2015-destructuring@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.16.0.tgz"
+ },
+ "babel-plugin-transform-es2015-duplicate-keys": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-duplicate-keys@>=6.6.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-for-of": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-for-of@>=6.6.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-function-name": {
+ "version": "6.9.0",
+ "from": "babel-plugin-transform-es2015-function-name@>=6.9.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.9.0.tgz"
+ },
+ "babel-plugin-transform-es2015-literals": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-literals@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-modules-amd": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-modules-amd@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-modules-commonjs": {
+ "version": "6.16.0",
+ "from": "babel-plugin-transform-es2015-modules-commonjs@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.16.0.tgz"
+ },
+ "babel-plugin-transform-es2015-modules-systemjs": {
+ "version": "6.14.0",
+ "from": "babel-plugin-transform-es2015-modules-systemjs@>=6.14.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.14.0.tgz"
+ },
+ "babel-plugin-transform-es2015-modules-umd": {
+ "version": "6.12.0",
+ "from": "babel-plugin-transform-es2015-modules-umd@>=6.12.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.12.0.tgz"
+ },
+ "babel-plugin-transform-es2015-object-super": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-object-super@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-parameters": {
+ "version": "6.17.0",
+ "from": "babel-plugin-transform-es2015-parameters@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.17.0.tgz"
+ },
+ "babel-plugin-transform-es2015-shorthand-properties": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-shorthand-properties@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-spread": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-spread@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-sticky-regex": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-sticky-regex@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-template-literals": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-template-literals@>=6.6.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-typeof-symbol": {
+ "version": "6.8.0",
+ "from": "babel-plugin-transform-es2015-typeof-symbol@>=6.6.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.8.0.tgz"
+ },
+ "babel-plugin-transform-es2015-unicode-regex": {
+ "version": "6.11.0",
+ "from": "babel-plugin-transform-es2015-unicode-regex@>=6.3.13 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz"
+ },
+ "babel-plugin-transform-regenerator": {
+ "version": "6.16.1",
+ "from": "babel-plugin-transform-regenerator@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.16.1.tgz"
+ },
+ "babel-plugin-transform-runtime": {
+ "version": "6.15.0",
+ "from": "babel-plugin-transform-runtime@>=6.9.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.15.0.tgz"
+ },
+ "babel-plugin-transform-strict-mode": {
+ "version": "6.11.3",
+ "from": "babel-plugin-transform-strict-mode@>=6.8.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.11.3.tgz"
+ },
+ "babel-polyfill": {
+ "version": "6.16.0",
+ "from": "babel-polyfill@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.16.0.tgz"
+ },
+ "babel-preset-es2015": {
+ "version": "6.16.0",
+ "from": "babel-preset-es2015@>=6.9.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.16.0.tgz"
+ },
+ "babel-preset-taskcluster": {
+ "version": "3.0.0",
+ "from": "babel-preset-taskcluster@>=3.0.0 <4.0.0",
+ "resolved": "https://registry.npmjs.org/babel-preset-taskcluster/-/babel-preset-taskcluster-3.0.0.tgz"
+ },
+ "babel-register": {
+ "version": "6.16.3",
+ "from": "babel-register@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.16.3.tgz"
+ },
+ "babel-runtime": {
+ "version": "6.11.6",
+ "from": "babel-runtime@>=6.11.6 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.11.6.tgz"
+ },
+ "babel-template": {
+ "version": "6.16.0",
+ "from": "babel-template@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.16.0.tgz"
+ },
+ "babel-traverse": {
+ "version": "6.16.0",
+ "from": "babel-traverse@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.16.0.tgz"
+ },
+ "babel-types": {
+ "version": "6.16.0",
+ "from": "babel-types@>=6.16.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.16.0.tgz"
+ },
+ "babylon": {
+ "version": "6.11.6",
+ "from": "babylon@>=6.11.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.11.6.tgz"
+ },
+ "balanced-match": {
+ "version": "0.4.2",
+ "from": "balanced-match@>=0.4.1 <0.5.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz"
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.0",
+ "from": "bcrypt-pbkdf@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz"
+ },
+ "bin-version": {
+ "version": "1.0.4",
+ "from": "bin-version@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-1.0.4.tgz"
+ },
+ "bin-version-check": {
+ "version": "2.1.0",
+ "from": "bin-version-check@>=2.1.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-2.1.0.tgz"
+ },
+ "binary-extensions": {
+ "version": "1.7.0",
+ "from": "binary-extensions@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.7.0.tgz"
+ },
+ "bitsyntax": {
+ "version": "0.0.4",
+ "from": "bitsyntax@>=0.0.4 <0.1.0",
+ "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.0.4.tgz"
+ },
+ "bl": {
+ "version": "1.1.2",
+ "from": "bl@>=1.1.2 <1.2.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz",
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.0.6",
+ "from": "readable-stream@>=2.0.5 <2.1.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz"
+ }
+ }
+ },
+ "boom": {
+ "version": "2.10.1",
+ "from": "boom@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
+ },
+ "brace-expansion": {
+ "version": "1.1.6",
+ "from": "brace-expansion@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz"
+ },
+ "braces": {
+ "version": "1.8.5",
+ "from": "braces@>=1.8.2 <2.0.0",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz"
+ },
+ "buffer-more-ints": {
+ "version": "0.0.2",
+ "from": "buffer-more-ints@0.0.2",
+ "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz"
+ },
+ "buffer-shims": {
+ "version": "1.0.0",
+ "from": "buffer-shims@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz"
+ },
+ "builtin-modules": {
+ "version": "1.1.1",
+ "from": "builtin-modules@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz"
+ },
+ "camelcase": {
+ "version": "2.1.1",
+ "from": "camelcase@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz"
+ },
+ "camelcase-keys": {
+ "version": "2.1.0",
+ "from": "camelcase-keys@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz"
+ },
+ "caseless": {
+ "version": "0.11.0",
+ "from": "caseless@>=0.11.0 <0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+ },
+ "chalk": {
+ "version": "1.1.1",
+ "from": "chalk@1.1.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
+ },
+ "chokidar": {
+ "version": "1.6.0",
+ "from": "chokidar@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.6.0.tgz"
+ },
+ "combined-stream": {
+ "version": "1.0.5",
+ "from": "combined-stream@>=1.0.5 <1.1.0",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
+ },
+ "commander": {
+ "version": "2.9.0",
+ "from": "commander@>=2.8.1 <3.0.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
+ },
+ "component-emitter": {
+ "version": "1.2.1",
+ "from": "component-emitter@>=1.2.0 <1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz"
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "from": "concat-map@0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+ },
+ "convert-source-map": {
+ "version": "1.3.0",
+ "from": "convert-source-map@>=1.1.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.3.0.tgz"
+ },
+ "cookiejar": {
+ "version": "2.0.6",
+ "from": "cookiejar@2.0.6",
+ "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.0.6.tgz"
+ },
+ "core-js": {
+ "version": "2.4.1",
+ "from": "core-js@>=2.4.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz"
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "from": "core-util-is@>=1.0.0 <1.1.0",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
+ },
+ "cryptiles": {
+ "version": "2.0.5",
+ "from": "cryptiles@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
+ },
+ "currently-unhandled": {
+ "version": "0.4.1",
+ "from": "currently-unhandled@>=0.4.1 <0.5.0",
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz"
+ },
+ "dashdash": {
+ "version": "1.14.0",
+ "from": "dashdash@>=1.12.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz",
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "from": "assert-plus@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+ }
+ }
+ },
+ "debug": {
+ "version": "2.2.0",
+ "from": "debug@>=2.1.1 <3.0.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz"
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "from": "decamelize@>=1.1.2 <2.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz"
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "from": "delayed-stream@>=1.0.0 <1.1.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
+ },
+ "detect-indent": {
+ "version": "3.0.1",
+ "from": "detect-indent@>=3.0.1 <4.0.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz"
+ },
+ "ecc-jsbn": {
+ "version": "0.1.1",
+ "from": "ecc-jsbn@>=0.1.1 <0.2.0",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz"
+ },
+ "error-ex": {
+ "version": "1.3.0",
+ "from": "error-ex@>=1.2.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz"
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "from": "escape-string-regexp@>=1.0.2 <2.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
+ },
+ "esprima": {
+ "version": "2.7.3",
+ "from": "esprima@>=2.6.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz"
+ },
+ "esutils": {
+ "version": "2.0.2",
+ "from": "esutils@>=2.0.2 <3.0.0",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz"
+ },
+ "eventsource": {
+ "version": "0.1.6",
+ "from": "eventsource@>=0.1.6 <0.2.0",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz"
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "from": "expand-brackets@>=0.1.4 <0.2.0",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz"
+ },
+ "expand-range": {
+ "version": "1.8.2",
+ "from": "expand-range@>=1.8.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz"
+ },
+ "extend": {
+ "version": "3.0.0",
+ "from": "extend@>=3.0.0 <3.1.0",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "from": "extglob@>=0.3.1 <0.4.0",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz"
+ },
+ "extsprintf": {
+ "version": "1.0.2",
+ "from": "extsprintf@1.0.2",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
+ },
+ "faye-websocket": {
+ "version": "0.11.0",
+ "from": "faye-websocket@>=0.11.0 <0.12.0",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.0.tgz"
+ },
+ "filename-regex": {
+ "version": "2.0.0",
+ "from": "filename-regex@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz"
+ },
+ "fill-range": {
+ "version": "2.2.3",
+ "from": "fill-range@>=2.1.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz"
+ },
+ "find-up": {
+ "version": "1.1.2",
+ "from": "find-up@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "dependencies": {
+ "path-exists": {
+ "version": "2.1.0",
+ "from": "path-exists@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz"
+ }
+ }
+ },
+ "find-versions": {
+ "version": "1.2.1",
+ "from": "find-versions@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-1.2.1.tgz"
+ },
+ "flatmap": {
+ "version": "0.0.3",
+ "from": "flatmap@0.0.3",
+ "resolved": "https://registry.npmjs.org/flatmap/-/flatmap-0.0.3.tgz"
+ },
+ "for-in": {
+ "version": "0.1.6",
+ "from": "for-in@>=0.1.5 <0.2.0",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.6.tgz"
+ },
+ "for-own": {
+ "version": "0.1.4",
+ "from": "for-own@>=0.1.3 <0.2.0",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz"
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "from": "forever-agent@>=0.6.1 <0.7.0",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
+ },
+ "form-data": {
+ "version": "2.0.0",
+ "from": "form-data@>=2.0.0 <2.1.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz"
+ },
+ "formidable": {
+ "version": "1.0.17",
+ "from": "formidable@>=1.0.14 <1.1.0",
+ "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.17.tgz"
+ },
+ "fs-readdir-recursive": {
+ "version": "0.1.2",
+ "from": "fs-readdir-recursive@>=0.1.0 <0.2.0",
+ "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz"
+ },
+ "fs-walk": {
+ "version": "0.0.1",
+ "from": "fs-walk@0.0.1",
+ "resolved": "https://registry.npmjs.org/fs-walk/-/fs-walk-0.0.1.tgz"
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "from": "fs.realpath@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
+ },
+ "generate-function": {
+ "version": "2.0.0",
+ "from": "generate-function@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
+ },
+ "generate-object-property": {
+ "version": "1.2.0",
+ "from": "generate-object-property@>=1.1.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
+ },
+ "get-stdin": {
+ "version": "4.0.1",
+ "from": "get-stdin@>=4.0.1 <5.0.0",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
+ },
+ "getpass": {
+ "version": "0.1.6",
+ "from": "getpass@>=0.1.1 <0.2.0",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz",
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "from": "assert-plus@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+ }
+ }
+ },
+ "glob": {
+ "version": "5.0.15",
+ "from": "glob@>=5.0.5 <6.0.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
+ },
+ "glob-base": {
+ "version": "0.3.0",
+ "from": "glob-base@>=0.3.0 <0.4.0",
+ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz"
+ },
+ "glob-parent": {
+ "version": "2.0.0",
+ "from": "glob-parent@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz"
+ },
+ "globals": {
+ "version": "8.18.0",
+ "from": "globals@>=8.3.0 <9.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+ },
+ "graceful-fs": {
+ "version": "4.1.9",
+ "from": "graceful-fs@>=4.1.2 <5.0.0",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.9.tgz"
+ },
+ "graceful-readlink": {
+ "version": "1.0.1",
+ "from": "graceful-readlink@>=1.0.0",
+ "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+ },
+ "har-validator": {
+ "version": "2.0.6",
+ "from": "har-validator@>=2.0.6 <2.1.0",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz"
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "from": "has-ansi@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
+ },
+ "hawk": {
+ "version": "3.1.3",
+ "from": "hawk@>=3.1.3 <3.2.0",
+ "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz"
+ },
+ "hoek": {
+ "version": "2.16.3",
+ "from": "hoek@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+ },
+ "home-or-tmp": {
+ "version": "1.0.0",
+ "from": "home-or-tmp@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz"
+ },
+ "hosted-git-info": {
+ "version": "2.1.5",
+ "from": "hosted-git-info@>=2.1.4 <3.0.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz"
+ },
+ "http-signature": {
+ "version": "1.1.1",
+ "from": "http-signature@>=1.1.0 <1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz"
+ },
+ "indent-string": {
+ "version": "2.1.0",
+ "from": "indent-string@>=2.1.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+ "dependencies": {
+ "repeating": {
+ "version": "2.0.1",
+ "from": "repeating@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz"
+ }
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "from": "inflight@>=1.0.4 <2.0.0",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "from": "inherits@>=2.0.1 <3.0.0",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
+ },
+ "intersect": {
+ "version": "1.0.1",
+ "from": "intersect@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/intersect/-/intersect-1.0.1.tgz"
+ },
+ "invariant": {
+ "version": "2.2.1",
+ "from": "invariant@>=2.2.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.1.tgz"
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "from": "is-arrayish@>=0.2.1 <0.3.0",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "from": "is-binary-path@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz"
+ },
+ "is-buffer": {
+ "version": "1.1.4",
+ "from": "is-buffer@>=1.0.2 <2.0.0",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz"
+ },
+ "is-builtin-module": {
+ "version": "1.0.0",
+ "from": "is-builtin-module@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz"
+ },
+ "is-dotfile": {
+ "version": "1.0.2",
+ "from": "is-dotfile@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz"
+ },
+ "is-equal-shallow": {
+ "version": "0.1.3",
+ "from": "is-equal-shallow@>=0.1.3 <0.2.0",
+ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz"
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "from": "is-extendable@>=0.1.1 <0.2.0",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz"
+ },
+ "is-extglob": {
+ "version": "1.0.0",
+ "from": "is-extglob@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz"
+ },
+ "is-finite": {
+ "version": "1.0.2",
+ "from": "is-finite@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz"
+ },
+ "is-glob": {
+ "version": "2.0.1",
+ "from": "is-glob@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz"
+ },
+ "is-my-json-valid": {
+ "version": "2.15.0",
+ "from": "is-my-json-valid@>=2.12.4 <3.0.0",
+ "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz"
+ },
+ "is-number": {
+ "version": "2.1.0",
+ "from": "is-number@>=2.1.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz"
+ },
+ "is-posix-bracket": {
+ "version": "0.1.1",
+ "from": "is-posix-bracket@>=0.1.0 <0.2.0",
+ "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz"
+ },
+ "is-primitive": {
+ "version": "2.0.0",
+ "from": "is-primitive@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz"
+ },
+ "is-property": {
+ "version": "1.0.2",
+ "from": "is-property@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "from": "is-typedarray@>=1.0.0 <1.1.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "from": "is-utf8@>=0.2.0 <0.3.0",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz"
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "from": "isarray@1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+ },
+ "isobject": {
+ "version": "2.1.0",
+ "from": "isobject@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz"
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "from": "isstream@>=0.1.2 <0.2.0",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+ },
+ "jodid25519": {
+ "version": "1.0.2",
+ "from": "jodid25519@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz"
+ },
+ "js-tokens": {
+ "version": "2.0.0",
+ "from": "js-tokens@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-2.0.0.tgz"
+ },
+ "js-yaml": {
+ "version": "3.6.1",
+ "from": "js-yaml@>=3.6.1 <4.0.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz"
+ },
+ "jsbn": {
+ "version": "0.1.0",
+ "from": "jsbn@>=0.1.0 <0.2.0",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz"
+ },
+ "jsesc": {
+ "version": "1.3.0",
+ "from": "jsesc@>=1.3.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz"
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "from": "json-schema@0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz"
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "from": "json-stringify-safe@>=5.0.1 <5.1.0",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
+ },
+ "json3": {
+ "version": "3.3.2",
+ "from": "json3@>=3.3.2 <4.0.0",
+ "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz"
+ },
+ "json5": {
+ "version": "0.4.0",
+ "from": "json5@>=0.4.0 <0.5.0",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz"
+ },
+ "jsonpointer": {
+ "version": "4.0.0",
+ "from": "jsonpointer@>=4.0.0 <5.0.0",
+ "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.0.tgz"
+ },
+ "jsprim": {
+ "version": "1.3.1",
+ "from": "jsprim@>=1.2.2 <2.0.0",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz"
+ },
+ "kind-of": {
+ "version": "3.0.4",
+ "from": "kind-of@>=3.0.2 <4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz"
+ },
+ "load-json-file": {
+ "version": "1.1.0",
+ "from": "load-json-file@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz"
+ },
+ "lodash": {
+ "version": "4.16.4",
+ "from": "lodash@>=4.2.0 <5.0.0",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.4.tgz"
+ },
+ "log-symbols": {
+ "version": "1.0.2",
+ "from": "log-symbols@>=1.0.2 <2.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz"
+ },
+ "loose-envify": {
+ "version": "1.2.0",
+ "from": "loose-envify@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.2.0.tgz",
+ "dependencies": {
+ "js-tokens": {
+ "version": "1.0.3",
+ "from": "js-tokens@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.3.tgz"
+ }
+ }
+ },
+ "loud-rejection": {
+ "version": "1.6.0",
+ "from": "loud-rejection@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz"
+ },
+ "map-obj": {
+ "version": "1.0.1",
+ "from": "map-obj@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
+ },
+ "meow": {
+ "version": "3.7.0",
+ "from": "meow@>=3.5.0 <4.0.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz"
+ },
+ "merge": {
+ "version": "1.2.0",
+ "from": "merge@>=1.2.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz"
+ },
+ "methods": {
+ "version": "1.1.2",
+ "from": "methods@>=1.1.1 <1.2.0",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz"
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "from": "micromatch@>=2.1.5 <3.0.0",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz"
+ },
+ "mime": {
+ "version": "1.3.4",
+ "from": "mime@1.3.4",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz"
+ },
+ "mime-db": {
+ "version": "1.24.0",
+ "from": "mime-db@>=1.24.0 <1.25.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.24.0.tgz"
+ },
+ "mime-types": {
+ "version": "2.1.12",
+ "from": "mime-types@>=2.1.7 <2.2.0",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.12.tgz"
+ },
+ "minimatch": {
+ "version": "3.0.3",
+ "from": "minimatch@>=3.0.2 <4.0.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "from": "minimist@>=1.2.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "from": "mkdirp@>=0.5.1 <0.6.0",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "from": "minimist@0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
+ }
+ }
+ },
+ "ms": {
+ "version": "0.7.1",
+ "from": "ms@0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
+ },
+ "node-uuid": {
+ "version": "1.4.7",
+ "from": "node-uuid@>=1.4.7 <1.5.0",
+ "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"
+ },
+ "normalize-package-data": {
+ "version": "2.3.5",
+ "from": "normalize-package-data@>=2.3.4 <3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz"
+ },
+ "normalize-path": {
+ "version": "2.0.1",
+ "from": "normalize-path@>=2.0.1 <3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz"
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "from": "number-is-nan@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz"
+ },
+ "oauth-sign": {
+ "version": "0.8.2",
+ "from": "oauth-sign@>=0.8.1 <0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz"
+ },
+ "object-assign": {
+ "version": "4.1.0",
+ "from": "object-assign@>=4.0.1 <5.0.0",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz"
+ },
+ "object.omit": {
+ "version": "2.0.0",
+ "from": "object.omit@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.0.tgz"
+ },
+ "once": {
+ "version": "1.4.0",
+ "from": "once@>=1.3.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
+ },
+ "original": {
+ "version": "1.0.0",
+ "from": "original@>=0.0.5",
+ "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz",
+ "dependencies": {
+ "url-parse": {
+ "version": "1.0.5",
+ "from": "url-parse@>=1.0.0 <1.1.0",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz"
+ }
+ }
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "from": "os-tmpdir@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
+ },
+ "output-file-sync": {
+ "version": "1.1.2",
+ "from": "output-file-sync@>=1.1.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz"
+ },
+ "parse-glob": {
+ "version": "3.0.4",
+ "from": "parse-glob@>=3.0.4 <4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz"
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "from": "parse-json@>=2.2.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz"
+ },
+ "path-exists": {
+ "version": "1.0.0",
+ "from": "path-exists@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz"
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "from": "path-is-absolute@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+ },
+ "path-type": {
+ "version": "1.1.0",
+ "from": "path-type@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz"
+ },
+ "pify": {
+ "version": "2.3.0",
+ "from": "pify@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "from": "pinkie@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz"
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "from": "pinkie-promise@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz"
+ },
+ "preserve": {
+ "version": "0.2.0",
+ "from": "preserve@>=0.2.0 <0.3.0",
+ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz"
+ },
+ "private": {
+ "version": "0.1.6",
+ "from": "private@>=0.1.6 <0.2.0",
+ "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz"
+ },
+ "process-nextick-args": {
+ "version": "1.0.7",
+ "from": "process-nextick-args@>=1.0.6 <1.1.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz"
+ },
+ "promise": {
+ "version": "6.1.0",
+ "from": "promise@>=6.1.0 <7.0.0",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz"
+ },
+ "qs": {
+ "version": "6.2.1",
+ "from": "qs@>=6.2.0 <6.3.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz"
+ },
+ "querystringify": {
+ "version": "0.0.4",
+ "from": "querystringify@>=0.0.0 <0.1.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz"
+ },
+ "randomatic": {
+ "version": "1.1.5",
+ "from": "randomatic@>=1.1.3 <2.0.0",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.5.tgz"
+ },
+ "read-pkg": {
+ "version": "1.1.0",
+ "from": "read-pkg@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz"
+ },
+ "read-pkg-up": {
+ "version": "1.0.1",
+ "from": "read-pkg-up@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz"
+ },
+ "readable-stream": {
+ "version": "2.1.5",
+ "from": "readable-stream@>=2.0.2 <3.0.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz"
+ },
+ "readdirp": {
+ "version": "2.1.0",
+ "from": "readdirp@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz"
+ },
+ "redent": {
+ "version": "1.0.0",
+ "from": "redent@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz"
+ },
+ "reduce-component": {
+ "version": "1.0.1",
+ "from": "reduce-component@1.0.1",
+ "resolved": "https://registry.npmjs.org/reduce-component/-/reduce-component-1.0.1.tgz"
+ },
+ "regenerate": {
+ "version": "1.3.1",
+ "from": "regenerate@>=1.2.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.1.tgz"
+ },
+ "regenerator-runtime": {
+ "version": "0.9.5",
+ "from": "regenerator-runtime@>=0.9.5 <0.10.0",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.5.tgz"
+ },
+ "regex-cache": {
+ "version": "0.4.3",
+ "from": "regex-cache@>=0.4.2 <0.5.0",
+ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz"
+ },
+ "regexpu-core": {
+ "version": "2.0.0",
+ "from": "regexpu-core@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz"
+ },
+ "regjsgen": {
+ "version": "0.2.0",
+ "from": "regjsgen@>=0.2.0 <0.3.0",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz"
+ },
+ "regjsparser": {
+ "version": "0.1.5",
+ "from": "regjsparser@>=0.1.4 <0.2.0",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
+ "dependencies": {
+ "jsesc": {
+ "version": "0.5.0",
+ "from": "jsesc@>=0.5.0 <0.6.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz"
+ }
+ }
+ },
+ "repeat-element": {
+ "version": "1.1.2",
+ "from": "repeat-element@>=1.1.2 <2.0.0",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz"
+ },
+ "repeat-string": {
+ "version": "1.5.4",
+ "from": "repeat-string@>=1.5.2 <2.0.0",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz"
+ },
+ "repeating": {
+ "version": "1.1.3",
+ "from": "repeating@>=1.1.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz"
+ },
+ "request": {
+ "version": "2.75.0",
+ "from": "request@>=2.65.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz"
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "from": "requires-port@>=1.0.0 <1.1.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz"
+ },
+ "rimraf": {
+ "version": "2.5.4",
+ "from": "rimraf@>=2.4.3 <3.0.0",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz",
+ "dependencies": {
+ "glob": {
+ "version": "7.1.1",
+ "from": "glob@>=7.0.5 <8.0.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz"
+ }
+ }
+ },
+ "semver": {
+ "version": "4.3.6",
+ "from": "semver@>=4.0.3 <5.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
+ },
+ "semver-regex": {
+ "version": "1.0.0",
+ "from": "semver-regex@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-1.0.0.tgz"
+ },
+ "semver-truncate": {
+ "version": "1.1.2",
+ "from": "semver-truncate@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz",
+ "dependencies": {
+ "semver": {
+ "version": "5.3.0",
+ "from": "semver@>=5.3.0 <6.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz"
+ }
+ }
+ },
+ "set-immediate-shim": {
+ "version": "1.0.1",
+ "from": "set-immediate-shim@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz"
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "from": "shebang-regex@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz"
+ },
+ "signal-exit": {
+ "version": "3.0.1",
+ "from": "signal-exit@>=3.0.0 <4.0.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.1.tgz"
+ },
+ "slash": {
+ "version": "1.0.0",
+ "from": "slash@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz"
+ },
+ "slugid": {
+ "version": "1.1.0",
+ "from": "slugid@>=1.1.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/slugid/-/slugid-1.1.0.tgz"
+ },
+ "sntp": {
+ "version": "1.0.9",
+ "from": "sntp@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+ },
+ "sockjs-client": {
+ "version": "1.1.1",
+ "from": "sockjs-client@>=1.0.3 <2.0.0",
+ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.1.tgz"
+ },
+ "source-map": {
+ "version": "0.5.6",
+ "from": "source-map@>=0.5.0 <0.6.0",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
+ },
+ "source-map-support": {
+ "version": "0.4.3",
+ "from": "source-map-support@>=0.4.2 <0.5.0",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.3.tgz"
+ },
+ "spdx-correct": {
+ "version": "1.0.2",
+ "from": "spdx-correct@>=1.0.0 <1.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz"
+ },
+ "spdx-expression-parse": {
+ "version": "1.0.4",
+ "from": "spdx-expression-parse@>=1.0.0 <1.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz"
+ },
+ "spdx-license-ids": {
+ "version": "1.2.2",
+ "from": "spdx-license-ids@>=1.0.2 <2.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz"
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "from": "sprintf-js@>=1.0.2 <1.1.0",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
+ },
+ "sshpk": {
+ "version": "1.10.1",
+ "from": "sshpk@>=1.7.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.1.tgz",
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "from": "assert-plus@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "from": "string_decoder@>=0.10.0 <0.11.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+ },
+ "stringstream": {
+ "version": "0.0.5",
+ "from": "stringstream@>=0.0.4 <0.1.0",
+ "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "from": "strip-ansi@>=3.0.0 <4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz"
+ },
+ "strip-bom": {
+ "version": "2.0.0",
+ "from": "strip-bom@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz"
+ },
+ "strip-indent": {
+ "version": "1.0.1",
+ "from": "strip-indent@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz"
+ },
+ "superagent": {
+ "version": "1.7.2",
+ "from": "superagent@>=1.7.0 <1.8.0",
+ "resolved": "https://registry.npmjs.org/superagent/-/superagent-1.7.2.tgz",
+ "dependencies": {
+ "async": {
+ "version": "0.9.2",
+ "from": "async@>=0.9.0 <0.10.0",
+ "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
+ },
+ "combined-stream": {
+ "version": "0.0.7",
+ "from": "combined-stream@>=0.0.4 <0.1.0",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz"
+ },
+ "delayed-stream": {
+ "version": "0.0.5",
+ "from": "delayed-stream@0.0.5",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz"
+ },
+ "form-data": {
+ "version": "0.2.0",
+ "from": "form-data@0.2.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz"
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "from": "isarray@0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+ },
+ "mime-db": {
+ "version": "1.12.0",
+ "from": "mime-db@>=1.12.0 <1.13.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz"
+ },
+ "mime-types": {
+ "version": "2.0.14",
+ "from": "mime-types@>=2.0.3 <2.1.0",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz"
+ },
+ "qs": {
+ "version": "2.3.3",
+ "from": "qs@2.3.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz"
+ },
+ "readable-stream": {
+ "version": "1.0.27-1",
+ "from": "readable-stream@1.0.27-1",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.27-1.tgz"
+ }
+ }
+ },
+ "superagent-hawk": {
+ "version": "0.0.6",
+ "from": "superagent-hawk@>=0.0.6 <0.0.7",
+ "resolved": "https://registry.npmjs.org/superagent-hawk/-/superagent-hawk-0.0.6.tgz",
+ "dependencies": {
+ "boom": {
+ "version": "0.4.2",
+ "from": "boom@>=0.4.0 <0.5.0",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz"
+ },
+ "cryptiles": {
+ "version": "0.2.2",
+ "from": "cryptiles@>=0.2.0 <0.3.0",
+ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz"
+ },
+ "hawk": {
+ "version": "1.0.0",
+ "from": "hawk@>=1.0.0 <1.1.0",
+ "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.0.0.tgz"
+ },
+ "hoek": {
+ "version": "0.9.1",
+ "from": "hoek@>=0.9.0 <0.10.0",
+ "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz"
+ },
+ "qs": {
+ "version": "0.6.6",
+ "from": "qs@>=0.6.6 <0.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz"
+ },
+ "sntp": {
+ "version": "0.2.4",
+ "from": "sntp@>=0.2.0 <0.3.0",
+ "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz"
+ }
+ }
+ },
+ "superagent-promise": {
+ "version": "0.2.0",
+ "from": "superagent-promise@>=0.2.0 <0.3.0",
+ "resolved": "https://registry.npmjs.org/superagent-promise/-/superagent-promise-0.2.0.tgz"
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "from": "supports-color@>=2.0.0 <3.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+ },
+ "taskcluster-client": {
+ "version": "1.4.0",
+ "from": "taskcluster-client@>=1.2.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/taskcluster-client/-/taskcluster-client-1.4.0.tgz",
+ "dependencies": {
+ "hawk": {
+ "version": "2.3.1",
+ "from": "hawk@>=2.3.1 <3.0.0",
+ "resolved": "https://registry.npmjs.org/hawk/-/hawk-2.3.1.tgz"
+ },
+ "lodash": {
+ "version": "3.10.1",
+ "from": "lodash@>=3.6.0 <4.0.0",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
+ }
+ }
+ },
+ "to-fast-properties": {
+ "version": "1.0.2",
+ "from": "to-fast-properties@>=1.0.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz"
+ },
+ "tough-cookie": {
+ "version": "2.3.1",
+ "from": "tough-cookie@>=2.3.0 <2.4.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.1.tgz"
+ },
+ "trim-newlines": {
+ "version": "1.0.0",
+ "from": "trim-newlines@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
+ },
+ "tunnel-agent": {
+ "version": "0.4.3",
+ "from": "tunnel-agent@>=0.4.1 <0.5.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz"
+ },
+ "tweetnacl": {
+ "version": "0.14.3",
+ "from": "tweetnacl@>=0.14.0 <0.15.0",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.3.tgz"
+ },
+ "url-join": {
+ "version": "0.0.1",
+ "from": "url-join@>=0.0.1 <0.0.2",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-0.0.1.tgz"
+ },
+ "url-parse": {
+ "version": "1.1.6",
+ "from": "url-parse@>=1.1.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.6.tgz"
+ },
+ "user-home": {
+ "version": "1.1.1",
+ "from": "user-home@>=1.1.1 <2.0.0",
+ "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz"
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "from": "util-deprecate@>=1.0.1 <1.1.0",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+ },
+ "uuid": {
+ "version": "2.0.3",
+ "from": "uuid@>=2.0.1 <3.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz"
+ },
+ "v8flags": {
+ "version": "2.0.11",
+ "from": "v8flags@>=2.0.10 <3.0.0",
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.0.11.tgz"
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.1",
+ "from": "validate-npm-package-license@>=3.0.1 <4.0.0",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz"
+ },
+ "verror": {
+ "version": "1.3.6",
+ "from": "verror@1.3.6",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz"
+ },
+ "websocket-driver": {
+ "version": "0.6.5",
+ "from": "websocket-driver@>=0.5.1",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz"
+ },
+ "websocket-extensions": {
+ "version": "0.1.1",
+ "from": "websocket-extensions@>=0.1.1",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz"
+ },
+ "when": {
+ "version": "3.6.4",
+ "from": "when@>=3.6.2 <3.7.0",
+ "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz"
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "from": "wrappy@>=1.0.0 <2.0.0",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "from": "xtend@>=4.0.0 <5.0.0",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+ }
+ }
+}
diff --git a/security/nss/automation/taskcluster/graph/package.json b/security/nss/automation/taskcluster/graph/package.json
new file mode 100644
index 000000000..d866adebc
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "decision-task",
+ "version": "0.0.1",
+ "private": true,
+ "author": "Tim Taubert <ttaubert@mozilla.com>",
+ "description": "Decision Task for NSS",
+ "scripts": {
+ "compile": "babel-compile -p taskcluster src:lib",
+ "install": "npm run compile"
+ },
+ "dependencies": {
+ "babel-cli": "^6.14.0",
+ "babel-compile": "^2.0.0",
+ "babel-preset-taskcluster": "^3.0.0",
+ "babel-runtime": "^6.11.6",
+ "flatmap": "0.0.3",
+ "intersect": "^1.0.1",
+ "js-yaml": "^3.6.1",
+ "merge": "^1.2.0",
+ "minimist": "^1.2.0",
+ "slugid": "^1.1.0",
+ "taskcluster-client": "^1.2.1"
+ }
+}
diff --git a/security/nss/automation/taskcluster/graph/src/context_hash.js b/security/nss/automation/taskcluster/graph/src/context_hash.js
new file mode 100644
index 000000000..f0a2e9a88
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/src/context_hash.js
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import fs from "fs";
+import path from "path";
+import crypto from "crypto";
+import flatmap from "flatmap";
+
+// Compute the SHA-256 digest.
+function sha256(data) {
+ let hash = crypto.createHash("sha256");
+ hash.update(data);
+ return hash.digest("hex");
+}
+
+// Recursively collect a list of all files of a given directory.
+function collectFilesInDirectory(dir) {
+ return flatmap(fs.readdirSync(dir), entry => {
+ let entry_path = path.join(dir, entry);
+
+ if (fs.lstatSync(entry_path).isDirectory()) {
+ return collectFilesInDirectory(entry_path);
+ }
+
+ return [entry_path];
+ });
+}
+
+// Compute a context hash for the given context path.
+export default function (context_path) {
+ let root = path.join(__dirname, "../../../..");
+ let dir = path.join(root, context_path);
+ let files = collectFilesInDirectory(dir).sort();
+ let hashes = files.map(file => {
+ return sha256(file + "|" + fs.readFileSync(file, "utf-8"));
+ });
+
+ // Generate a new prefix every month to ensure the image stays buildable.
+ let now = new Date();
+ let prefix = `${now.getUTCFullYear()}-${now.getUTCMonth() + 1}:`;
+ return sha256(prefix + hashes.join(","));
+}
diff --git a/security/nss/automation/taskcluster/graph/src/extend.js b/security/nss/automation/taskcluster/graph/src/extend.js
new file mode 100644
index 000000000..a6a8fcbe2
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -0,0 +1,572 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import merge from "./merge";
+import * as queue from "./queue";
+
+const LINUX_IMAGE = {name: "linux", path: "automation/taskcluster/docker"};
+
+const WINDOWS_CHECKOUT_CMD =
+ "bash -c \"hg clone -r $NSS_HEAD_REVISION $NSS_HEAD_REPOSITORY nss || " +
+ "(sleep 2; hg clone -r $NSS_HEAD_REVISION $NSS_HEAD_REPOSITORY nss) || " +
+ "(sleep 5; hg clone -r $NSS_HEAD_REVISION $NSS_HEAD_REPOSITORY nss)\"";
+
+/*****************************************************************************/
+
+queue.filter(task => {
+ if (task.group == "Builds") {
+ // Remove extra builds on {A,UB}San and ARM.
+ if (task.collection == "asan" || task.collection == "arm-debug" ||
+ task.collection == "gyp-asan") {
+ return false;
+ }
+
+ // Remove extra builds w/o libpkix for non-linux64-debug.
+ if (task.symbol == "noLibpkix" &&
+ (task.platform != "linux64" || task.collection != "debug")) {
+ return false;
+ }
+ }
+
+ if (task.tests == "bogo") {
+ // No BoGo tests on Windows.
+ if (task.platform == "windows2012-64") {
+ return false;
+ }
+
+ // No BoGo tests on ARM.
+ if (task.collection == "arm-debug") {
+ return false;
+ }
+ }
+
+ // GYP builds with -Ddisable_libpkix=1 by default.
+ if ((task.collection == "gyp" || task.collection == "gyp-asan") &&
+ task.tests == "chains") {
+ return false;
+ }
+
+ return true;
+});
+
+queue.map(task => {
+ if (task.collection == "asan" || task.collection == "gyp-asan") {
+ // CRMF and FIPS tests still leak, unfortunately.
+ if (task.tests == "crmf" || task.tests == "fips") {
+ task.env.ASAN_OPTIONS = "detect_leaks=0";
+ }
+ }
+
+ if (task.collection == "arm-debug") {
+ // These tests take quite some time on our poor ARM devices.
+ if (task.tests == "chains" || (task.tests == "ssl" && task.cycle == "standard")) {
+ task.maxRunTime = 14400;
+ }
+ }
+
+ // Windows is slow.
+ if (task.platform == "windows2012-64" && task.tests == "chains") {
+ task.maxRunTime = 7200;
+ }
+
+ // Enable TLS 1.3 for every task.
+ task.env = task.env || {};
+ task.env.NSS_ENABLE_TLS_1_3 = "1";
+
+ return task;
+});
+
+/*****************************************************************************/
+
+export default async function main() {
+ await scheduleLinux("Linux 32 (opt)", {
+ env: {BUILD_OPT: "1"},
+ platform: "linux32",
+ image: LINUX_IMAGE
+ });
+
+ await scheduleLinux("Linux 32 (debug)", {
+ platform: "linux32",
+ collection: "debug",
+ image: LINUX_IMAGE
+ });
+
+ await scheduleLinux("Linux 64 (opt)", {
+ env: {USE_64: "1", BUILD_OPT: "1"},
+ platform: "linux64",
+ image: LINUX_IMAGE
+ });
+
+ await scheduleLinux("Linux 64 (debug)", {
+ env: {USE_64: "1"},
+ platform: "linux64",
+ collection: "debug",
+ image: LINUX_IMAGE
+ });
+
+ await scheduleLinux("Linux 64 (debug, gyp)", {
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/build_gyp.sh"
+ ],
+ platform: "linux64",
+ collection: "gyp",
+ image: LINUX_IMAGE
+ });
+
+ await scheduleLinux("Linux 64 (debug, gyp, asan, ubsan)", {
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/build_gyp.sh -g -v --ubsan --asan"
+ ],
+ env: {
+ ASAN_OPTIONS: "detect_odr_violation=0", // bug 1316276
+ UBSAN_OPTIONS: "print_stacktrace=1",
+ NSS_DISABLE_ARENA_FREE_LIST: "1",
+ NSS_DISABLE_UNLOAD: "1",
+ CC: "clang",
+ CCC: "clang++"
+ },
+ platform: "linux64",
+ collection: "gyp-asan",
+ image: LINUX_IMAGE
+ });
+
+ await scheduleLinux("Linux 64 (ASan, debug)", {
+ env: {
+ UBSAN_OPTIONS: "print_stacktrace=1",
+ NSS_DISABLE_ARENA_FREE_LIST: "1",
+ NSS_DISABLE_UNLOAD: "1",
+ CC: "clang",
+ CCC: "clang++",
+ USE_UBSAN: "1",
+ USE_ASAN: "1",
+ USE_64: "1"
+ },
+ platform: "linux64",
+ collection: "asan",
+ image: LINUX_IMAGE
+ });
+
+ await scheduleWindows("Windows 2012 64 (opt)", {
+ env: {BUILD_OPT: "1"}
+ });
+
+ await scheduleWindows("Windows 2012 64 (debug)", {
+ collection: "debug"
+ });
+
+ await scheduleFuzzing();
+
+ await scheduleTestBuilds();
+
+ await scheduleTools();
+
+ await scheduleLinux("Linux 32 (ARM, debug)", {
+ image: "franziskus/nss-arm-ci",
+ provisioner: "localprovisioner",
+ collection: "arm-debug",
+ workerType: "nss-rpi",
+ platform: "linux32",
+ maxRunTime: 7200,
+ tier: 3
+ });
+}
+
+/*****************************************************************************/
+
+async function scheduleLinux(name, base) {
+ // Build base definition.
+ let build_base = merge({
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/build.sh"
+ ],
+ artifacts: {
+ public: {
+ expires: 24 * 7,
+ type: "directory",
+ path: "/home/worker/artifacts"
+ }
+ },
+ kind: "build",
+ symbol: "B"
+ }, base);
+
+ // The task that builds NSPR+NSS.
+ let task_build = queue.scheduleTask(merge(build_base, {name}));
+
+ // The task that generates certificates.
+ let task_cert = queue.scheduleTask(merge(build_base, {
+ name: "Certificates",
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/gen_certs.sh"
+ ],
+ parent: task_build,
+ symbol: "Certs"
+ }));
+
+ // Schedule tests.
+ scheduleTests(task_build, task_cert, merge(base, {
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
+ ]
+ }));
+
+ // Extra builds.
+ let extra_base = merge({group: "Builds"}, build_base);
+ queue.scheduleTask(merge(extra_base, {
+ name: `${name} w/ clang-3.9`,
+ env: {
+ CC: "clang",
+ CCC: "clang++",
+ },
+ symbol: "clang-3.9"
+ }));
+
+ queue.scheduleTask(merge(extra_base, {
+ name: `${name} w/ gcc-4.8`,
+ env: {
+ CC: "gcc-4.8",
+ CCC: "g++-4.8"
+ },
+ symbol: "gcc-4.8"
+ }));
+
+ queue.scheduleTask(merge(extra_base, {
+ name: `${name} w/ gcc-6.1`,
+ env: {
+ CC: "gcc-6",
+ CCC: "g++-6"
+ },
+ symbol: "gcc-6.1"
+ }));
+
+ queue.scheduleTask(merge(extra_base, {
+ name: `${name} w/ NSS_DISABLE_LIBPKIX=1`,
+ env: {NSS_DISABLE_LIBPKIX: "1"},
+ symbol: "noLibpkix"
+ }));
+
+ return queue.submit();
+}
+
+/*****************************************************************************/
+
+async function scheduleFuzzing() {
+ let base = {
+ env: {
+ // bug 1316276
+ ASAN_OPTIONS: "allocator_may_return_null=1:detect_odr_violation=0",
+ UBSAN_OPTIONS: "print_stacktrace=1",
+ NSS_DISABLE_ARENA_FREE_LIST: "1",
+ NSS_DISABLE_UNLOAD: "1",
+ CC: "clang",
+ CCC: "clang++"
+ },
+ platform: "linux64",
+ collection: "fuzz",
+ image: LINUX_IMAGE
+ };
+
+ // Build base definition.
+ let build_base = merge({
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && " +
+ "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz"
+ ],
+ artifacts: {
+ public: {
+ expires: 24 * 7,
+ type: "directory",
+ path: "/home/worker/artifacts"
+ }
+ },
+ kind: "build",
+ symbol: "B"
+ }, base);
+
+ // The task that builds NSPR+NSS.
+ let task_build = queue.scheduleTask(merge(build_base, {
+ name: "Linux x64 (debug, fuzz)"
+ }));
+
+ // Schedule tests.
+ queue.scheduleTask(merge(base, {
+ parent: task_build,
+ name: "Gtests",
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
+ ],
+ env: {GTESTFILTER: "*Fuzz*"},
+ tests: "ssl_gtests gtests",
+ cycle: "standard",
+ symbol: "Gtest",
+ kind: "test"
+ }));
+
+ queue.scheduleTask(merge(base, {
+ parent: task_build,
+ name: "Cert",
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/fuzz.sh " +
+ "cert nss/fuzz/corpus/cert -max_total_time=300"
+ ],
+ // Need a privileged docker container to remove this.
+ env: {ASAN_OPTIONS: "detect_leaks=0"},
+ symbol: "SCert",
+ kind: "test"
+ }));
+
+ queue.scheduleTask(merge(base, {
+ parent: task_build,
+ name: "SPKI",
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/fuzz.sh " +
+ "spki nss/fuzz/corpus/spki -max_total_time=300"
+ ],
+ // Need a privileged docker container to remove this.
+ env: {ASAN_OPTIONS: "detect_leaks=0"},
+ symbol: "SPKI",
+ kind: "test"
+ }));
+
+ return queue.submit();
+}
+
+/*****************************************************************************/
+
+async function scheduleTestBuilds() {
+ let base = {
+ platform: "linux64",
+ collection: "gyp",
+ group: "Test",
+ image: LINUX_IMAGE
+ };
+
+ // Build base definition.
+ let build = merge({
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && " +
+ "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --test"
+ ],
+ artifacts: {
+ public: {
+ expires: 24 * 7,
+ type: "directory",
+ path: "/home/worker/artifacts"
+ }
+ },
+ kind: "build",
+ symbol: "B",
+ name: "Linux 64 (debug, gyp, test)"
+ }, base);
+
+ // The task that builds NSPR+NSS.
+ let task_build = queue.scheduleTask(build);
+
+ // Schedule tests.
+ queue.scheduleTask(merge(base, {
+ parent: task_build,
+ name: "mpi",
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
+ ],
+ tests: "mpi",
+ cycle: "standard",
+ symbol: "mpi",
+ kind: "test"
+ }));
+
+ return queue.submit();
+}
+
+
+/*****************************************************************************/
+
+async function scheduleWindows(name, base) {
+ base = merge(base, {
+ workerType: "nss-win2012r2",
+ platform: "windows2012-64",
+ env: {
+ PATH: "c:\\mozilla-build\\python;c:\\mozilla-build\\msys\\local\\bin;" +
+ "c:\\mozilla-build\\7zip;c:\\mozilla-build\\info-zip;" +
+ "c:\\mozilla-build\\python\\Scripts;c:\\mozilla-build\\yasm;" +
+ "c:\\mozilla-build\\msys\\bin;c:\\Windows\\system32;" +
+ "c:\\mozilla-build\\upx391w;c:\\mozilla-build\\moztools-x64\\bin;" +
+ "c:\\mozilla-build\\wget",
+ DOMSUF: "localdomain",
+ HOST: "localhost",
+ USE_64: "1"
+ }
+ });
+
+ // Build base definition.
+ let build_base = merge(base, {
+ command: [
+ WINDOWS_CHECKOUT_CMD,
+ "bash -c nss/automation/taskcluster/windows/build.sh"
+ ],
+ artifacts: [{
+ expires: 24 * 7,
+ type: "directory",
+ path: "public\\build"
+ }],
+ kind: "build",
+ symbol: "B"
+ });
+
+ // The task that builds NSPR+NSS.
+ let task_build = queue.scheduleTask(merge(build_base, {name}));
+
+ // The task that generates certificates.
+ let task_cert = queue.scheduleTask(merge(build_base, {
+ name: "Certificates",
+ command: [
+ WINDOWS_CHECKOUT_CMD,
+ "bash -c nss/automation/taskcluster/windows/gen_certs.sh"
+ ],
+ parent: task_build,
+ symbol: "Certs"
+ }));
+
+ // Schedule tests.
+ scheduleTests(task_build, task_cert, merge(base, {
+ command: [
+ WINDOWS_CHECKOUT_CMD,
+ "bash -c nss/automation/taskcluster/windows/run_tests.sh"
+ ]
+ }));
+
+ return queue.submit();
+}
+
+/*****************************************************************************/
+
+function scheduleTests(task_build, task_cert, test_base) {
+ test_base = merge({kind: "test"}, test_base);
+
+ // Schedule tests that do NOT need certificates.
+ let no_cert_base = merge(test_base, {parent: task_build});
+ queue.scheduleTask(merge(no_cert_base, {
+ name: "Gtests", symbol: "Gtest", tests: "ssl_gtests gtests", cycle: "standard"
+ }));
+ queue.scheduleTask(merge(no_cert_base, {
+ name: "Bogo tests", symbol: "Bogo", tests: "bogo", cycle: "standard"
+ }));
+ queue.scheduleTask(merge(no_cert_base, {
+ name: "Chains tests", symbol: "Chains", tests: "chains"
+ }));
+ queue.scheduleTask(merge(no_cert_base, {
+ name: "Cipher tests", symbol: "Cipher", tests: "cipher"
+ }));
+ queue.scheduleTask(merge(no_cert_base, {
+ name: "EC tests", symbol: "EC", tests: "ec"
+ }));
+ queue.scheduleTask(merge(no_cert_base, {
+ name: "Lowhash tests", symbol: "Lowhash", tests: "lowhash"
+ }));
+ queue.scheduleTask(merge(no_cert_base, {
+ name: "SDR tests", symbol: "SDR", tests: "sdr"
+ }));
+
+ // Schedule tests that need certificates.
+ let cert_base = merge(test_base, {parent: task_cert});
+ queue.scheduleTask(merge(cert_base, {
+ name: "CRMF tests", symbol: "CRMF", tests: "crmf"
+ }));
+ queue.scheduleTask(merge(cert_base, {
+ name: "DB tests", symbol: "DB", tests: "dbtests"
+ }));
+ queue.scheduleTask(merge(cert_base, {
+ name: "FIPS tests", symbol: "FIPS", tests: "fips"
+ }));
+ queue.scheduleTask(merge(cert_base, {
+ name: "Merge tests", symbol: "Merge", tests: "merge"
+ }));
+ queue.scheduleTask(merge(cert_base, {
+ name: "S/MIME tests", symbol: "SMIME", tests: "smime"
+ }));
+ queue.scheduleTask(merge(cert_base, {
+ name: "Tools tests", symbol: "Tools", tests: "tools"
+ }));
+
+ // SSL tests, need certificates too.
+ let ssl_base = merge(cert_base, {tests: "ssl", group: "SSL"});
+ queue.scheduleTask(merge(ssl_base, {
+ name: "SSL tests (standard)", symbol: "standard", cycle: "standard"
+ }));
+ queue.scheduleTask(merge(ssl_base, {
+ name: "SSL tests (pkix)", symbol: "pkix", cycle: "pkix"
+ }));
+ queue.scheduleTask(merge(ssl_base, {
+ name: "SSL tests (sharedb)", symbol: "sharedb", cycle: "sharedb"
+ }));
+ queue.scheduleTask(merge(ssl_base, {
+ name: "SSL tests (upgradedb)", symbol: "upgradedb", cycle: "upgradedb"
+ }));
+}
+
+/*****************************************************************************/
+
+async function scheduleTools() {
+ let base = {
+ image: LINUX_IMAGE,
+ platform: "nss-tools",
+ kind: "test"
+ };
+
+ queue.scheduleTask(merge(base, {
+ symbol: "clang-format-3.9",
+ name: "clang-format-3.9",
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/run_clang_format.sh"
+ ]
+ }));
+
+ queue.scheduleTask(merge(base, {
+ symbol: "scan-build-3.9",
+ name: "scan-build-3.9",
+ env: {
+ USE_64: "1",
+ CC: "clang",
+ CCC: "clang++",
+ },
+ artifacts: {
+ public: {
+ expires: 24 * 7,
+ type: "directory",
+ path: "/home/worker/artifacts"
+ }
+ },
+ command: [
+ "/bin/bash",
+ "-c",
+ "bin/checkout.sh && nss/automation/taskcluster/scripts/run_scan_build.sh"
+ ]
+ }));
+
+ return queue.submit();
+}
diff --git a/security/nss/automation/taskcluster/graph/src/image_builder.js b/security/nss/automation/taskcluster/graph/src/image_builder.js
new file mode 100644
index 000000000..bc90e0242
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/src/image_builder.js
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import * as queue from "./queue";
+import context_hash from "./context_hash";
+import taskcluster from "taskcluster-client";
+
+async function taskHasImageArtifact(taskId) {
+ let queue = new taskcluster.Queue();
+ let {artifacts} = await queue.listLatestArtifacts(taskId);
+ return artifacts.some(artifact => artifact.name == "public/image.tar");
+}
+
+async function findTaskWithImageArtifact(ns) {
+ let index = new taskcluster.Index();
+ let {taskId} = await index.findTask(ns);
+ let has_image = await taskHasImageArtifact(taskId);
+ return has_image ? taskId : null;
+}
+
+export async function findTask({name, path}) {
+ let hash = await context_hash(path);
+ let ns = `docker.images.v1.${process.env.TC_PROJECT}.${name}.hash.${hash}`;
+ return findTaskWithImageArtifact(ns).catch(() => null);
+}
+
+export async function buildTask({name, path}) {
+ let hash = await context_hash(path);
+ let ns = `docker.images.v1.${process.env.TC_PROJECT}.${name}.hash.${hash}`;
+
+ return {
+ name: "Image Builder",
+ image: "taskcluster/image_builder:0.1.5",
+ routes: ["index." + ns],
+ env: {
+ HEAD_REPOSITORY: process.env.NSS_HEAD_REPOSITORY,
+ BASE_REPOSITORY: process.env.NSS_HEAD_REPOSITORY,
+ HEAD_REV: process.env.NSS_HEAD_REVISION,
+ HEAD_REF: process.env.NSS_HEAD_REVISION,
+ PROJECT: process.env.TC_PROJECT,
+ CONTEXT_PATH: path,
+ HASH: hash
+ },
+ artifacts: {
+ "public/image.tar": {
+ type: "file",
+ expires: 24 * 90,
+ path: "/artifacts/image.tar"
+ }
+ },
+ command: [
+ "/bin/bash",
+ "-c",
+ "/home/worker/bin/build_image.sh"
+ ],
+ platform: "nss-decision",
+ features: ["dind"],
+ kind: "build",
+ symbol: "I"
+ };
+}
diff --git a/security/nss/automation/taskcluster/graph/src/index.js b/security/nss/automation/taskcluster/graph/src/index.js
new file mode 100644
index 000000000..4153e1b18
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/src/index.js
@@ -0,0 +1,14 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import * as try_syntax from "./try_syntax";
+import extend from "./extend";
+
+// Init try syntax filter.
+if (process.env.TC_PROJECT == "nss-try") {
+ try_syntax.initFilter();
+}
+
+// Extend the task graph.
+extend().catch(console.error);
diff --git a/security/nss/automation/taskcluster/graph/src/merge.js b/security/nss/automation/taskcluster/graph/src/merge.js
new file mode 100644
index 000000000..17043dd8e
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/src/merge.js
@@ -0,0 +1,10 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import {recursive as merge} from "merge";
+
+// We always want to clone.
+export default function (...args) {
+ return merge(true, ...args);
+}
diff --git a/security/nss/automation/taskcluster/graph/src/queue.js b/security/nss/automation/taskcluster/graph/src/queue.js
new file mode 100644
index 000000000..2a4a7b3fe
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/src/queue.js
@@ -0,0 +1,242 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import {clone} from "merge";
+import merge from "./merge";
+import slugid from "slugid";
+import taskcluster from "taskcluster-client";
+import * as image_builder from "./image_builder";
+
+let maps = [];
+let filters = [];
+
+let tasks = new Map();
+let image_tasks = new Map();
+
+let queue = new taskcluster.Queue({
+ baseUrl: "http://taskcluster/queue/v1"
+});
+
+function fromNow(hours) {
+ let d = new Date();
+ d.setHours(d.getHours() + (hours|0));
+ return d.toJSON();
+}
+
+function parseRoutes(routes) {
+ return [
+ `tc-treeherder.v2.${process.env.TC_PROJECT}.${process.env.NSS_HEAD_REVISION}.${process.env.NSS_PUSHLOG_ID}`,
+ ...routes
+ ];
+}
+
+function parseFeatures(list) {
+ return list.reduce((map, feature) => {
+ map[feature] = true;
+ return map;
+ }, {});
+}
+
+function parseArtifacts(artifacts) {
+ let copy = clone(artifacts);
+ Object.keys(copy).forEach(key => {
+ copy[key].expires = fromNow(copy[key].expires);
+ });
+ return copy;
+}
+
+function parseCollection(name) {
+ let collection = {};
+ collection[name] = true;
+ return collection;
+}
+
+function parseTreeherder(def) {
+ let treeherder = {
+ build: {
+ platform: def.platform
+ },
+ machine: {
+ platform: def.platform
+ },
+ symbol: def.symbol,
+ jobKind: def.kind
+ };
+
+ if (def.group) {
+ treeherder.groupSymbol = def.group;
+ }
+
+ if (def.collection) {
+ treeherder.collection = parseCollection(def.collection);
+ }
+
+ if (def.tier) {
+ treeherder.tier = def.tier;
+ }
+
+ return treeherder;
+}
+
+function convertTask(def) {
+ let dependencies = [];
+
+ let env = merge({
+ NSS_HEAD_REPOSITORY: process.env.NSS_HEAD_REPOSITORY,
+ NSS_HEAD_REVISION: process.env.NSS_HEAD_REVISION
+ }, def.env || {});
+
+ if (def.parent) {
+ dependencies.push(def.parent);
+ env.TC_PARENT_TASK_ID = def.parent;
+ }
+
+ if (def.tests) {
+ env.NSS_TESTS = def.tests;
+ }
+
+ if (def.cycle) {
+ env.NSS_CYCLES = def.cycle;
+ }
+
+ let payload = {
+ env,
+ command: def.command,
+ maxRunTime: def.maxRunTime || 3600
+ };
+
+ if (def.image) {
+ payload.image = def.image;
+ }
+
+ if (def.features) {
+ payload.features = parseFeatures(def.features);
+ }
+
+ if (def.artifacts) {
+ payload.artifacts = parseArtifacts(def.artifacts);
+ }
+
+ return {
+ provisionerId: def.provisioner || "aws-provisioner-v1",
+ workerType: def.workerType || "hg-worker",
+ schedulerId: "task-graph-scheduler",
+
+ created: fromNow(0),
+ deadline: fromNow(24),
+
+ dependencies,
+ routes: parseRoutes(def.routes || []),
+
+ metadata: {
+ name: def.name,
+ description: def.name,
+ owner: process.env.TC_OWNER,
+ source: process.env.TC_SOURCE
+ },
+
+ payload,
+
+ extra: {
+ treeherder: parseTreeherder(def)
+ }
+ };
+}
+
+export function map(fun) {
+ maps.push(fun);
+}
+
+export function filter(fun) {
+ filters.push(fun);
+}
+
+export function scheduleTask(def) {
+ let taskId = slugid.v4();
+ tasks.set(taskId, merge({}, def));
+ return taskId;
+}
+
+export async function submit() {
+ let promises = new Map();
+
+ for (let [taskId, task] of tasks) {
+ // Allow filtering tasks before we schedule them.
+ if (!filters.every(filter => filter(task))) {
+ continue;
+ }
+
+ // Allow changing tasks before we schedule them.
+ maps.forEach(map => { task = map(merge({}, task)) });
+
+ let log_id = `${task.name} @ ${task.platform}[${task.collection || "opt"}]`;
+ console.log(`+ Submitting ${log_id}.`);
+
+ let parent = task.parent;
+
+ // Convert the task definition.
+ task = await convertTask(task);
+
+ // Convert the docker image definition.
+ let image_def = task.payload.image;
+ if (image_def && image_def.hasOwnProperty("path")) {
+ let key = `${image_def.name}:${image_def.path}`;
+ let data = {};
+
+ // Check the cache first.
+ if (image_tasks.has(key)) {
+ data = image_tasks.get(key);
+ } else {
+ data.taskId = await image_builder.findTask(image_def);
+ data.isPending = !data.taskId;
+
+ // No task found.
+ if (data.isPending) {
+ let image_task = await image_builder.buildTask(image_def);
+
+ // Schedule a new image builder task immediately.
+ data.taskId = slugid.v4();
+
+ try {
+ await queue.createTask(data.taskId, convertTask(image_task));
+ } catch (e) {
+ console.error("! FAIL: Scheduling image builder task failed.");
+ continue; /* Skip this task on failure. */
+ }
+ }
+
+ // Store in cache.
+ image_tasks.set(key, data);
+ }
+
+ if (data.isPending) {
+ task.dependencies.push(data.taskId);
+ }
+
+ task.payload.image = {
+ path: "public/image.tar",
+ taskId: data.taskId,
+ type: "task-image"
+ };
+ }
+
+ // Wait for the parent task to be created before scheduling dependants.
+ let predecessor = parent ? promises.get(parent) : Promise.resolve();
+
+ promises.set(taskId, predecessor.then(() => {
+ // Schedule the task.
+ return queue.createTask(taskId, task).catch(err => {
+ console.error(`! FAIL: Scheduling ${log_id} failed.`, err);
+ });
+ }));
+ }
+
+ // Wait for all requests to finish.
+ if (promises.length) {
+ await Promise.all([...promises.values()]);
+ console.log("=== Total:", promises.length, "tasks. ===");
+ }
+
+ tasks.clear();
+}
diff --git a/security/nss/automation/taskcluster/graph/src/try_syntax.js b/security/nss/automation/taskcluster/graph/src/try_syntax.js
new file mode 100644
index 000000000..695c9e92f
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/src/try_syntax.js
@@ -0,0 +1,159 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import * as queue from "./queue";
+import intersect from "intersect";
+import parse_args from "minimist";
+
+function parseOptions(opts) {
+ opts = parse_args(opts.split(/\s+/), {
+ default: {build: "do", platform: "all", unittests: "none", tools: "none"},
+ alias: {b: "build", p: "platform", u: "unittests", t: "tools", e: "extra-builds"},
+ string: ["build", "platform", "unittests", "tools", "extra-builds"]
+ });
+
+ // Parse build types (d=debug, o=opt).
+ let builds = intersect(opts.build.split(""), ["d", "o"]);
+
+ // If the given value is nonsense default to debug and opt builds.
+ if (builds.length == 0) {
+ builds = ["d", "o"];
+ }
+
+ // Parse platforms.
+ let allPlatforms = ["linux", "linux64", "linux64-asan", "win64", "arm",
+ "linux64-gyp", "linux64-gyp-asan", "linux64-fuzz"];
+ let platforms = intersect(opts.platform.split(/\s*,\s*/), allPlatforms);
+
+ // If the given value is nonsense or "none" default to all platforms.
+ if (platforms.length == 0 && opts.platform != "none") {
+ platforms = allPlatforms;
+ }
+
+ // Parse unit tests.
+ let aliases = {"gtests": "gtest"};
+ let allUnitTests = ["bogo", "crmf", "chains", "cipher", "db", "ec", "fips",
+ "gtest", "lowhash", "merge", "sdr", "smime", "tools",
+ "ssl", "mpi", "scert", "spki"];
+ let unittests = intersect(opts.unittests.split(/\s*,\s*/).map(t => {
+ return aliases[t] || t;
+ }), allUnitTests);
+
+ // If the given value is "all" run all tests.
+ // If it's nonsense then don't run any tests.
+ if (opts.unittests == "all") {
+ unittests = allUnitTests;
+ } else if (unittests.length == 0) {
+ unittests = [];
+ }
+
+ // Parse tools.
+ let allTools = ["clang-format", "scan-build"];
+ let tools = intersect(opts.tools.split(/\s*,\s*/), allTools);
+
+ // If the given value is "all" run all tools.
+ // If it's nonsense then don't run any tools.
+ if (opts.tools == "all") {
+ tools = allTools;
+ } else if (tools.length == 0) {
+ tools = [];
+ }
+
+ return {
+ builds: builds,
+ platforms: platforms,
+ unittests: unittests,
+ extra: (opts.e == "all"),
+ tools: tools
+ };
+}
+
+function filter(opts) {
+ return function (task) {
+ // Filter tools. We can immediately return here as those
+ // are not affected by platform or build type selectors.
+ if (task.platform == "nss-tools") {
+ return opts.tools.some(tool => {
+ return task.symbol.toLowerCase().startsWith(tool);
+ });
+ }
+
+ // Filter unit tests.
+ if (task.tests) {
+ let found = opts.unittests.some(test => {
+ // TODO: think of something more intelligent here.
+ if (task.symbol.toLowerCase().startsWith("mpi") && test == "mpi") {
+ return true;
+ }
+ return (task.group || task.symbol).toLowerCase().startsWith(test);
+ });
+
+ if (!found) {
+ return false;
+ }
+ }
+
+ // Filter extra builds.
+ if (task.group == "Builds" && !opts.extra) {
+ return false;
+ }
+
+ let coll = name => name == (task.collection || "opt");
+
+ // Filter by platform.
+ let found = opts.platforms.some(platform => {
+ let aliases = {
+ "linux": "linux32",
+ "linux64-asan": "linux64",
+ "linux64-fuzz": "linux64",
+ "linux64-gyp": "linux64",
+ "linux64-gyp-asan": "linux64",
+ "win64": "windows2012-64",
+ "arm": "linux32"
+ };
+
+ // Check the platform name.
+ let keep = (task.platform == (aliases[platform] || platform));
+
+ // Additional checks.
+ if (platform == "linux64-asan") {
+ keep &= coll("asan");
+ } else if (platform == "arm") {
+ keep &= coll("arm-opt") || coll("arm-debug");
+ } else if (platform == "linux64-gyp") {
+ keep &= coll("gyp");
+ } else if (platform == "linux64-gyp-asan") {
+ keep &= coll("gyp-asan");
+ } else if (platform == "linux64-fuzz") {
+ keep &= coll("fuzz");
+ } else {
+ keep &= coll("opt") || coll("debug");
+ }
+
+ return keep;
+ });
+
+ if (!found) {
+ return false;
+ }
+
+ // Finally, filter by build type.
+ let isDebug = coll("debug") || coll("asan") || coll("arm-debug") ||
+ coll("gyp") || coll("fuzz");
+ return (isDebug && opts.builds.includes("d")) ||
+ (!isDebug && opts.builds.includes("o"));
+ }
+}
+
+export function initFilter() {
+ let comment = process.env.TC_COMMENT || "";
+
+ // Check for try syntax in changeset comment.
+ let match = comment.match(/^\s*try:\s*(.*)\s*$/);
+
+ // Add try syntax filter.
+ if (match) {
+ queue.filter(filter(parseOptions(match[1])));
+ }
+}
diff --git a/security/nss/automation/taskcluster/scripts/build.sh b/security/nss/automation/taskcluster/scripts/build.sh
new file mode 100755
index 000000000..69968b138
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/build.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+source $(dirname $0)/tools.sh
+
+if [[ $(id -u) -eq 0 ]]; then
+ # Drop privileges by re-running this script.
+ exec su worker $0
+fi
+
+# Clone NSPR if needed.
+hg_clone https://hg.mozilla.org/projects/nspr nspr default
+
+# Build.
+make -C nss nss_build_all
+
+# Package.
+mkdir artifacts
+tar cvfjh artifacts/dist.tar.bz2 dist
diff --git a/security/nss/automation/taskcluster/scripts/build_gyp.sh b/security/nss/automation/taskcluster/scripts/build_gyp.sh
new file mode 100755
index 000000000..590e634a3
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/build_gyp.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+source $(dirname $0)/tools.sh
+
+if [[ $(id -u) -eq 0 ]]; then
+ # Drop privileges by re-running this script.
+ exec su worker -c "$0 $*"
+fi
+
+# Clone NSPR if needed.
+hg_clone https://hg.mozilla.org/projects/nspr nspr default
+
+# Build.
+nss/build.sh ${*--g -v}
+
+# Package.
+mkdir artifacts
+tar cvfjh artifacts/dist.tar.bz2 dist
diff --git a/security/nss/automation/taskcluster/scripts/extend_task_graph.sh b/security/nss/automation/taskcluster/scripts/extend_task_graph.sh
new file mode 100755
index 000000000..5a3fb8d98
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/extend_task_graph.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) = 0 ]; then
+ # Drop privileges by re-running this script.
+ exec su worker $0
+fi
+
+mkdir -p /home/worker/artifacts
+
+# Install Node.JS dependencies.
+cd nss/automation/taskcluster/graph/ && npm install
+
+# Extend the task graph.
+node lib/index.js
diff --git a/security/nss/automation/taskcluster/scripts/fuzz.sh b/security/nss/automation/taskcluster/scripts/fuzz.sh
new file mode 100755
index 000000000..5f8dd7bff
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/fuzz.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+source $(dirname $0)/tools.sh
+
+if [ $(id -u) = 0 ]; then
+ # Drop privileges by re-running this script.
+ exec su worker -c "$0 $*"
+fi
+
+# Fetch artifact if needed.
+fetch_dist
+
+# Clone corpus.
+./nss/fuzz/clone_corpus.sh
+
+# Fetch objdir name.
+objdir=$(cat dist/latest)
+
+# Run nssfuzz.
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:dist/$objdir/lib dist/$objdir/bin/nssfuzz $*
diff --git a/security/nss/automation/taskcluster/scripts/gen_certs.sh b/security/nss/automation/taskcluster/scripts/gen_certs.sh
new file mode 100755
index 000000000..aee100147
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/gen_certs.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+source $(dirname $0)/tools.sh
+
+if [ $(id -u) = 0 ]; then
+ # Stupid Docker.
+ echo "127.0.0.1 localhost.localdomain" >> /etc/hosts
+
+ # Drop privileges by re-running this script.
+ exec su worker $0
+fi
+
+# Fetch artifact if needed.
+fetch_dist
+
+# Generate certificates.
+NSS_TESTS=cert NSS_CYCLES="standard pkix sharedb" $(dirname $0)/run_tests.sh
+
+# Reset test counter so that test runs pick up our certificates.
+echo 1 > tests_results/security/localhost
+
+# Package.
+mkdir artifacts
+tar cvfjh artifacts/dist.tar.bz2 dist tests_results
diff --git a/security/nss/automation/taskcluster/scripts/run_clang_format.sh b/security/nss/automation/taskcluster/scripts/run_clang_format.sh
new file mode 100755
index 000000000..c4b60290f
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/run_clang_format.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) -eq 0 ]; then
+ # Drop privileges by re-running this script.
+ exec su worker $0 "$@"
+fi
+
+# Apply clang-format on the provided folder and verify that this doesn't change any file.
+# If any file differs after formatting, the script eventually exits with 1.
+# Any differences between formatted and unformatted files is printed to stdout to give a hint what's wrong.
+
+# Includes a default set of directories.
+
+if [ $# -gt 0 ]; then
+ dirs=("$@")
+else
+ top=$(dirname $0)/../../..
+ dirs=( \
+ "$top/cmd" \
+ "$top/fuzz" \
+ "$top/lib/base" \
+ "$top/lib/certdb" \
+ "$top/lib/certhigh" \
+ "$top/lib/ckfw" \
+ "$top/lib/crmf" \
+ "$top/lib/cryptohi" \
+ "$top/lib/dbm" \
+ "$top/lib/dev" \
+ "$top/lib/freebl" \
+ "$top/lib/jar" \
+ "$top/lib/nss" \
+ "$top/lib/pk11wrap" \
+ "$top/lib/pkcs7" \
+ "$top/lib/pkcs12" \
+ "$top/lib/pki" \
+ "$top/lib/smime" \
+ "$top/lib/softoken" \
+ "$top/lib/ssl" \
+ "$top/lib/sysinit" \
+ "$top/lib/util" \
+ "$top/gtests/common" \
+ "$top/gtests/der_gtest" \
+ "$top/gtests/freebl_gtest" \
+ "$top/gtests/pk11_gtest" \
+ "$top/gtests/ssl_gtest" \
+ "$top/gtests/util_gtest" \
+ )
+fi
+
+for dir in "${dirs[@]}"; do
+ find "$dir" -type f \( -name '*.[ch]' -o -name '*.cc' \) -exec clang-format -i {} \+
+done
+
+TMPFILE=$(mktemp /tmp/$(basename $0).XXXXXX)
+trap 'rm $TMPFILE' exit
+if (cd $(dirname $0); hg root >/dev/null 2>&1); then
+ hg diff --git "$top" | tee $TMPFILE
+else
+ git -C "$top" diff | tee $TMPFILE
+fi
+[[ ! -s $TMPFILE ]]
diff --git a/security/nss/automation/taskcluster/scripts/run_scan_build.sh b/security/nss/automation/taskcluster/scripts/run_scan_build.sh
new file mode 100755
index 000000000..99f80ab5f
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/run_scan_build.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+source $(dirname $0)/tools.sh
+
+if [ $(id -u) = 0 ]; then
+ # Drop privileges by re-running this script.
+ exec su worker $0 $@
+fi
+
+# Clone NSPR if needed.
+if [ ! -d "nspr" ]; then
+ hg_clone https://hg.mozilla.org/projects/nspr nspr default
+fi
+
+# Build.
+cd nss
+make nss_build_all
+
+# What we want to scan.
+# key: directory to scan
+# value: number of errors expected in that directory
+declare -A scan=( \
+ [lib/base]=0 \
+ [lib/certdb]=0 \
+ [lib/certhigh]=0 \
+ [lib/ckfw]=0 \
+ [lib/crmf]=0 \
+ [lib/cryptohi]=0 \
+ [lib/dev]=0 \
+ [lib/freebl]=0 \
+ [lib/nss]=0 \
+ [lib/ssl]=0 \
+ [lib/util]=0 \
+ )
+
+# remove .OBJ directories to force a rebuild of just the select few
+for i in "${!scan[@]}"; do
+ find "$i" -name "*.OBJ" -exec rm -rf {} \+
+done
+
+# run scan-build (only building affected directories)
+scan-build -o /home/worker/artifacts --use-cc=$CC --use-c++=$CCC make nss_build_all && cd ..
+
+# print errors we found
+set +v +x
+STATUS=0
+for i in "${!scan[@]}"; do
+ n=$(grep -Rn "$i" /home/worker/artifacts/*/report-*.html | wc -l)
+ if [ $n -ne ${scan[$i]} ]; then
+ STATUS=1
+ echo "$(date '+%T') WARNING - TEST-UNEXPECTED-FAIL: $i contains $n scan-build errors"
+ elif [ $n -ne 0 ]; then
+ echo "$(date '+%T') WARNING - TEST-EXPECTED-FAIL: $i contains $n scan-build errors"
+ fi
+done
+exit $STATUS
diff --git a/security/nss/automation/taskcluster/scripts/run_tests.sh b/security/nss/automation/taskcluster/scripts/run_tests.sh
new file mode 100755
index 000000000..4c87e7e32
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/run_tests.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+source $(dirname $0)/tools.sh
+
+if [ $(id -u) = 0 ]; then
+ # Stupid Docker.
+ echo "127.0.0.1 localhost.localdomain" >> /etc/hosts
+
+ # Drop privileges by re-running this script.
+ exec su worker $0
+fi
+
+# Fetch artifact if needed.
+fetch_dist
+
+# Run tests.
+cd nss/tests && ./all.sh
diff --git a/security/nss/automation/taskcluster/scripts/tools.sh b/security/nss/automation/taskcluster/scripts/tools.sh
new file mode 100644
index 000000000..dacfdeb28
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/tools.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Usage: hg_clone repo dir [revision=@]
+hg_clone() {
+ repo=$1
+ dir=$2
+ rev=${3:-@}
+ for i in 0 2 5; do
+ sleep $i
+ hg clone -r "$rev" "$repo" "$dir" && return
+ rm -rf "$dir"
+ done
+ exit 1
+}
+
+fetch_dist() {
+ url=https://queue.taskcluster.net/v1/task/$TC_PARENT_TASK_ID/artifacts/public/dist.tar.bz2
+ if [ ! -d "dist" ]; then
+ for i in 0 2 5; do
+ sleep $i
+ curl --retry 3 -Lo dist.tar.bz2 $url && tar xvjf dist.tar.bz2 && return
+ rm -fr dist.tar.bz2 dist
+ done
+ exit 1
+ fi
+}
diff --git a/security/nss/automation/taskcluster/windows/build.sh b/security/nss/automation/taskcluster/windows/build.sh
new file mode 100644
index 000000000..6c8a47470
--- /dev/null
+++ b/security/nss/automation/taskcluster/windows/build.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Set up the toolchain.
+source $(dirname $0)/setup.sh
+
+# Clone NSPR.
+hg_clone https://hg.mozilla.org/projects/nspr nspr default
+
+# Build.
+make -C nss nss_build_all
+
+# Package.
+7z a public/build/dist.7z dist
diff --git a/security/nss/automation/taskcluster/windows/gen_certs.sh b/security/nss/automation/taskcluster/windows/gen_certs.sh
new file mode 100644
index 000000000..ead16bbc3
--- /dev/null
+++ b/security/nss/automation/taskcluster/windows/gen_certs.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Set up the toolchain.
+source $(dirname $0)/setup.sh
+
+# Fetch artifact.
+wget -t 3 --retry-connrefused -w 5 --random-wait https://queue.taskcluster.net/v1/task/$TC_PARENT_TASK_ID/artifacts/public/build/dist.7z -O dist.7z
+7z x dist.7z
+
+# Generate certificates.
+NSS_TESTS=cert NSS_CYCLES="standard pkix sharedb" nss/tests/all.sh
+
+# Reset test counter so that test runs pick up our certificates.
+echo 1 > tests_results/security/localhost
+
+# Package.
+7z a public/build/dist.7z dist tests_results
diff --git a/security/nss/automation/taskcluster/windows/releng.manifest b/security/nss/automation/taskcluster/windows/releng.manifest
new file mode 100644
index 000000000..b3f449854
--- /dev/null
+++ b/security/nss/automation/taskcluster/windows/releng.manifest
@@ -0,0 +1,10 @@
+[
+ {
+ "version": "Visual Studio 2015 Update 2 / SDK 10.0.10586.0/212",
+ "size": 332442800,
+ "digest": "995394a4a515c7cb0f8595f26f5395361a638870dd0bbfcc22193fe1d98a0c47126057d5999cc494f3f3eac5cb49160e79757c468f83ee5797298e286ef6252c",
+ "algorithm": "sha512",
+ "filename": "vs2015u2.zip",
+ "unpack": true
+ }
+]
diff --git a/security/nss/automation/taskcluster/windows/run_tests.sh b/security/nss/automation/taskcluster/windows/run_tests.sh
new file mode 100644
index 000000000..f64a78e30
--- /dev/null
+++ b/security/nss/automation/taskcluster/windows/run_tests.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Set up the toolchain.
+source $(dirname $0)/setup.sh
+
+# Fetch artifact.
+wget -t 3 --retry-connrefused -w 5 --random-wait https://queue.taskcluster.net/v1/task/$TC_PARENT_TASK_ID/artifacts/public/build/dist.7z -O dist.7z
+7z x dist.7z
+
+# Run tests.
+cd nss/tests && ./all.sh
diff --git a/security/nss/automation/taskcluster/windows/setup.sh b/security/nss/automation/taskcluster/windows/setup.sh
new file mode 100644
index 000000000..80cee2850
--- /dev/null
+++ b/security/nss/automation/taskcluster/windows/setup.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Usage: hg_clone repo dir [revision=@]
+hg_clone() {
+ repo=$1
+ dir=$2
+ rev=${3:-@}
+ for i in 0 2 5; do
+ sleep $i
+ hg clone -r "$rev" "$repo" "$dir" && return
+ rm -rf "$dir"
+ done
+ exit 1
+}
+
+hg_clone https://hg.mozilla.org/build/tools tools default
+
+tools/scripts/tooltool/tooltool_wrapper.sh $(dirname $0)/releng.manifest https://api.pub.build.mozilla.org/tooltool/ non-existant-file.sh /c/mozilla-build/python/python.exe /c/builds/tooltool.py --authentication-file /c/builds/relengapi.tok -c /c/builds/tooltool_cache
+VSPATH="$(pwd)/vs2015u2"
+
+export WINDOWSSDKDIR="${VSPATH}/SDK"
+export WIN32_REDIST_DIR="${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT"
+export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x64"
+
+export PATH="${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x64:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${PATH}"
+
+export INCLUDE="${VSPATH}/VC/include:${VSPATH}/SDK/Include/10.0.10586.0/ucrt:${VSPATH}/SDK/Include/10.0.10586.0/shared:${VSPATH}/SDK/Include/10.0.10586.0/um"
+export LIB="${VSPATH}/VC/lib/amd64:${VSPATH}/SDK/lib/10.0.10586.0/ucrt/x64:${VSPATH}/SDK/lib/10.0.10586.0/um/x64"