<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[45745] trunk: Build Tools: Add a WordPress Development Environment.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/45745">45745</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/45745","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>pento</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2019-08-05 07:09:14 +0000 (Mon, 05 Aug 2019)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Build Tools: Add a WordPress Development Environment.

This commit adds the first iteration of a Docker-based config for setting up a local WordPress development environment.

Props pento, noisysocks, mcsf, pbearne, isabel_brison.
See <a href="https://core.trac.wordpress.org/ticket/47767">#47767</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunktravisyml">trunk/.travis.yml</a></li>
<li><a href="#trunkpackagelockjson">trunk/package-lock.json</a></li>
<li><a href="#trunkpackagejson">trunk/package.json</a></li>
<li><a href="#trunktoolslocalenvdockercomposeyml">trunk/tools/local-env/docker-compose.yml</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkenv">trunk/.env</a></li>
<li><a href="#trunkREADMEmd">trunk/README.md</a></li>
<li><a href="#trunktoolslocalenvdefaulttemplate">trunk/tools/local-env/default.template</a></li>
<li><a href="#trunktoolslocalenvdockercomposescriptsyml">trunk/tools/local-env/docker-compose.scripts.yml</a></li>
<li><a href="#trunktoolslocalenvmysqlinitsql">trunk/tools/local-env/mysql-init.sql</a></li>
<li><a href="#trunktoolslocalenvphpconfigini">trunk/tools/local-env/php-config.ini</a></li>
<li><a href="#trunktoolslocalenvphpunitconfigini">trunk/tools/local-env/phpunit-config.ini</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunktoolslocalenvincludessh">trunk/tools/local-env/includes.sh</a></li>
<li><a href="#trunktoolslocalenvinstallnodenvmsh">trunk/tools/local-env/install-node-nvm.sh</a></li>
<li><a href="#trunktoolslocalenvinstallwordpresssh">trunk/tools/local-env/install-wordpress.sh</a></li>
<li><a href="#trunktoolslocalenvlaunchcontainerssh">trunk/tools/local-env/launch-containers.sh</a></li>
<li><a href="#trunktoolslocalenvstartsh">trunk/tools/local-env/start.sh</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkenv"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/.env</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/.env                                (rev 0)
+++ trunk/.env  2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,28 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+##
+# Default configuration options for the local dev environment.
+#
+# All of these options can be overriden by setting them as environment variables before starting
+# the environment. You will need to restart your environment when changing any of these.
+##
+
+# The site will be available at http://localhost:LOCAL_PORT
+LOCAL_PORT=8889
+
+# Where to run WordPress from. Valid options are 'src' and 'build'.
+LOCAL_DIR=src
+
+# The PHP version to use. Valid options are 'latest', and '{version}-fpm', where '{version}' is any
+# x.y PHP version from 5.2 onwards.
+LOCAL_PHP=latest
+
+# Whether or not to enable XDebug.
+LOCAL_PHP_XDEBUG=false
+
+# The MySQL version to use. See https://hub.docker.com/_/mysql/ for valid versions.
+LOCAL_MYSQL=5.7
+
+# The debug settings to add to `wp-config.php`.
+LOCAL_WP_DEBUG=true
+LOCAL_WP_DEBUG_LOG=true
+LOCAL_WP_DEBUG_DISPLAY=true
+LOCAL_SCRIPT_DEBUG=true
</ins></span></pre></div>
<a id="trunktravisyml"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/.travis.yml</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/.travis.yml 2019-08-04 14:43:21 UTC (rev 45744)
+++ trunk/.travis.yml   2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,6 +1,13 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-sudo: false
-dist: trusty
</del><span class="cx" style="display: block; padding: 0 10px"> language: php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+services:
+  - docker
+  - mysql
+
+addons:
+  apt:
+    packages:
+      - docker-ce
+
</ins><span class="cx" style="display: block; padding: 0 10px"> cache:
</span><span class="cx" style="display: block; padding: 0 10px">   apt: true
</span><span class="cx" style="display: block; padding: 0 10px">   directories:
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7,32 +14,36 @@
</span><span class="cx" style="display: block; padding: 0 10px">     - $HOME/.npm
</span><span class="cx" style="display: block; padding: 0 10px">     - vendor
</span><span class="cx" style="display: block; padding: 0 10px">     - $HOME/.composer/cache
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> env:
</span><span class="cx" style="display: block; padding: 0 10px">   global:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    - WP_TRAVISCI=travis:phpunit
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    - LOCAL_DIR=build
+
</ins><span class="cx" style="display: block; padding: 0 10px"> matrix:
</span><span class="cx" style="display: block; padding: 0 10px">   include:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  - php: 7.2
-    env: WP_TRAVISCI=e2e
-  - php: 7.2
-    env: WP_TRAVISCI=travis:phpcs
-  - php: 7.1
-    env: WP_TRAVISCI=travis:js
-  - php: 7.4snapshot
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  - env: WP_TRAVISCI=test:e2e
+  - env: WP_TRAVISCI=travis:phpcs
+  - env: WP_TRAVISCI=travis:js
+  - env: LOCAL_PHP=7.3-fpm WP_TRAVISCI=test:php
</ins><span class="cx" style="display: block; padding: 0 10px">   - php: 7.3
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  - php: 7.3
-    env: WP_TRAVIS_OBJECT_CACHE=true
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    dist: trusty
+    env: WP_TRAVIS_OBJECT_CACHE=true WP_TRAVISCI=travis:phpunit
</ins><span class="cx" style="display: block; padding: 0 10px">     services: memcached
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  - php: 7.2
-  - php: 7.1
-  - php: 7.0
-    env: WP_TEST_REPORTER=true
-  - php: 5.6
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  - env: LOCAL_PHP=7.2-fpm WP_TRAVISCI=test:php
+  - env: LOCAL_PHP=7.1-fpm WP_TRAVISCI=test:php
+  - env: LOCAL_PHP=7.0-fpm WP_TEST_REPORTER=true WP_TRAVISCI=test:php
+  - env: LOCAL_PHP=5.6-fpm WP_TRAVISCI=test:php
+  - php: 7.4snapshot
+    dist: trusty
+    env: WP_TRAVISCI=travis:phpunit
</ins><span class="cx" style="display: block; padding: 0 10px">   - php: nightly
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    dist: trusty
+    env: WP_TRAVISCI=travis:phpunit
</ins><span class="cx" style="display: block; padding: 0 10px">   allow_failures:
</span><span class="cx" style="display: block; padding: 0 10px">   - php: 7.4snapshot
</span><span class="cx" style="display: block; padding: 0 10px">   - php: nightly
</span><span class="cx" style="display: block; padding: 0 10px">   fast_finish: true
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> before_install:
</span><span class="cx" style="display: block; padding: 0 10px"> - |
</span><span class="cx" style="display: block; padding: 0 10px">   if [[ "$WP_TRAVISCI" == "travis:phpunit" ]]; then
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44,10 +55,25 @@
</span><span class="cx" style="display: block; padding: 0 10px">       travis_retry svn checkout https://plugins.svn.wordpress.org/wordpress-importer/tags/0.6.3/ tests/phpunit/data/plugins/wordpress-importer
</span><span class="cx" style="display: block; padding: 0 10px">   fi
</span><span class="cx" style="display: block; padding: 0 10px"> - |
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  if [[ "$WP_TRAVISCI" == "test:php" ]]; then
+      cp wp-tests-config-sample.php wp-tests-config.php
+      sed -i "s/youremptytestdbnamehere/wordpress_develop_tests/" wp-tests-config.php
+      sed -i "s/yourusernamehere/root/" wp-tests-config.php
+      sed -i "s/yourpasswordhere/password/" wp-tests-config.php
+      sed -i "s/localhost/mysql/" wp-tests-config.php
+      travis_retry svn checkout https://plugins.svn.wordpress.org/wordpress-importer/tags/0.6.3/ tests/phpunit/data/plugins/wordpress-importer
+  fi
+- |
+  sudo rm /usr/local/bin/docker-compose
+  curl -L https://github.com/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` > docker-compose
+  chmod +x docker-compose
+  sudo mv docker-compose /usr/local/bin
+- |
</ins><span class="cx" style="display: block; padding: 0 10px">   if [[ "$WP_TRAVIS_OBJECT_CACHE" == "true" ]]; then
</span><span class="cx" style="display: block; padding: 0 10px">     cp tests/phpunit/includes/object-cache.php src/wp-content/object-cache.php
</span><span class="cx" style="display: block; padding: 0 10px">     echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
</span><span class="cx" style="display: block; padding: 0 10px">   fi
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> before_script:
</span><span class="cx" style="display: block; padding: 0 10px"> - |
</span><span class="cx" style="display: block; padding: 0 10px">   # Remove Xdebug for a huge performance increase:
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -57,30 +83,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">     echo "xdebug.ini does not exist"
</span><span class="cx" style="display: block; padding: 0 10px">   fi
</span><span class="cx" style="display: block; padding: 0 10px"> - |
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  # Export Composer's global bin dir to PATH, but not on PHP 5.2:
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  # Export Composer's global bin dir to PATH:
</ins><span class="cx" style="display: block; padding: 0 10px">   composer config --list --global
</span><span class="cx" style="display: block; padding: 0 10px">   export PATH=`composer config --list --global | grep '\[home\]' | { read a; echo "${a#* }/vendor/bin:$PATH"; }`
</span><span class="cx" style="display: block; padding: 0 10px"> - |
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  # Install the specified version of PHPUnit depending on the PHP version:
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  # Install PHPUnit for the tests that don't run in Docker.
</ins><span class="cx" style="display: block; padding: 0 10px">   if [[ "$WP_TRAVISCI" == "travis:phpunit" ]]; then
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    case "$TRAVIS_PHP_VERSION" in
-      7.4snapshot|7.3|7.2|7.1|nightly)
-        echo "Using PHPUnit 7.x"
-        travis_retry composer global require "phpunit/phpunit:^7"
-        ;;
-      7.0)
-        echo "Using PHPUnit 6.x"
-        travis_retry composer global require "phpunit/phpunit:^6"
-        ;;
-      5.6)
-        echo "Using PHPUnit 4.x"
-        travis_retry composer global require "phpunit/phpunit:^4"
-        ;;
-      *)
-        echo "No PHPUnit version handling for PHP version $TRAVIS_PHP_VERSION"
-        exit 1
-        ;;
-    esac
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    echo "Using PHPUnit 7.x"
+    travis_retry composer global require "phpunit/phpunit:^7"
</ins><span class="cx" style="display: block; padding: 0 10px">   fi
</span><span class="cx" style="display: block; padding: 0 10px"> - |
</span><span class="cx" style="display: block; padding: 0 10px">   # We only need to run composer install on the PHP coding standards job.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -93,6 +103,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> - nvm install 10.13.0
</span><span class="cx" style="display: block; padding: 0 10px"> - npm install
</span><span class="cx" style="display: block; padding: 0 10px"> - npm prune
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+- |
+  if [[ "$WP_TRAVISCI" == "test:e2e" ]] || [[ "$WP_TRAVISCI" == "test:php" ]]; then
+    npm run env:start
+    npm run build
+  fi
+- |
+  if [[ "$WP_TRAVISCI" == "test:e2e" ]]; then
+    npm run env:install
+  fi
</ins><span class="cx" style="display: block; padding: 0 10px"> - mysql --version
</span><span class="cx" style="display: block; padding: 0 10px"> - phpenv versions
</span><span class="cx" style="display: block; padding: 0 10px"> - php --version
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -105,15 +124,22 @@
</span><span class="cx" style="display: block; padding: 0 10px"> - git --version
</span><span class="cx" style="display: block; padding: 0 10px"> - svn --version
</span><span class="cx" style="display: block; padding: 0 10px"> - locale -a
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> script:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-- |
-  if [[ "$WP_TRAVISCI" == "e2e" ]]; then
-    npm run env:start
-    npm run env:reset-site
-    npm run test:e2e
-  else
-    npm run grunt $WP_TRAVISCI
-  fi
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  - |
+    if [[ "$WP_TRAVISCI" == "test:e2e" ]]; then
+      npm run test:e2e
+    elif [[ "$WP_TRAVISCI" == "test:php" ]]; then
+      npm run test:php -- -- -- --verbose -c phpunit.xml.dist
+      npm run test:php -- -- -- --verbose -c phpunit.xml.dist --group ajax
+      npm run test:php -- -- -- --verbose -c tests/phpunit/multisite.xml
+      npm run test:php -- -- -- --verbose -c tests/phpunit/multisite.xml --group ms-files
+      npm run test:php -- -- -- --verbose -c phpunit.xml.dist --group external-http
+      npm run test:php -- -- -- --verbose -c phpunit.xml.dist --group restapi-jsclient
+    else
+      npm run grunt $WP_TRAVISCI
+    fi
+
</ins><span class="cx" style="display: block; padding: 0 10px"> after_script:
</span><span class="cx" style="display: block; padding: 0 10px"> - |
</span><span class="cx" style="display: block; padding: 0 10px">   if [[ "$WP_TEST_REPORTER" == "true" ]]; then
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -122,6 +148,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     export WPT_TEST_DIR=$(pwd)
</span><span class="cx" style="display: block; padding: 0 10px">     php test-runner/report.php
</span><span class="cx" style="display: block; padding: 0 10px">   fi
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> notifications:
</span><span class="cx" style="display: block; padding: 0 10px">   slack:
</span><span class="cx" style="display: block; padding: 0 10px">     rooms:
</span></span></pre></div>
<a id="trunkREADMEmd"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/README.md</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/README.md                           (rev 0)
+++ trunk/README.md     2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,26 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+# WordPress
+
+[![Build Status](https://img.shields.io/travis/com/WordPress/wordpress-develop/master.svg)](https://travis-ci.com/WordPress/wordpress-develop)
+
+Welcome to the WordPress development repository! Please check out our [contributor handbook](https://make.wordpress.org/core/handbook/) for information about how to open bug reports, contribute patches, test, documention, or get involved in any way you can.
+
+## Getting Started
+
+WordPress is a PHP/MySQL-based project. We have a basic development environment that you can quickly get up and running with a few commands. First off, you will need to download and install [Docker](https://www.docker.com/products/docker-desktop), if you don't have it already. After that, there are a few commands to run:
+
+### Development Environment Commands
+
+Running these commands will start the development environment:
+
+```
+npm install
+npm run build:dev
+npm run env:start
+npm run env:install
+```
+
+Additionally, `npm run env:stop` will stop the environment.
+
+`npm run env:cli` runs the [WP-CLI tool](https://make.wordpress.org/cli/handbook/). WP-CLI has a lot of [useful commands](https://developer.wordpress.org/cli/commands/) you can use to work on your WordPress site. Where the documentation mentions running `wp`, run `npm run env:cli` instead. For example, `npm run env:cli help`.
+
+`npm run test:php` and `npm run test:e2e` run the PHP and E2E test suites, respectively.
</ins></span></pre></div>
<a id="trunkpackagelockjson"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/package-lock.json</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/package-lock.json   2019-08-04 14:43:21 UTC (rev 45744)
+++ trunk/package-lock.json     2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1084,6 +1084,53 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/@financial-times/useragent_parser/-/useragent_parser-1.0.2.tgz",
</span><span class="cx" style="display: block; padding: 0 10px">                        "integrity": "sha512-zuJMxn5Qnk7CKl+zrVXDqXs0F+p4tshO6B4s8VenJj34EEVuV4iZIbkGiEFJUbn29z9Mcn6k8yfj9qSCNDcPPQ=="
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "@hapi/address": {
+                       "version": "2.0.0",
+                       "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.0.0.tgz",
+                       "integrity": "sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==",
+                       "dev": true
+               },
+               "@hapi/hoek": {
+                       "version": "6.2.4",
+                       "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-6.2.4.tgz",
+                       "integrity": "sha512-HOJ20Kc93DkDVvjwHyHawPwPkX44sIrbXazAUDiUXaY2R9JwQGo2PhFfnQtdrsIe4igjG2fPgMra7NYw7qhy0A==",
+                       "dev": true
+               },
+               "@hapi/joi": {
+                       "version": "15.1.0",
+                       "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.0.tgz",
+                       "integrity": "sha512-n6kaRQO8S+kepUTbXL9O/UOL788Odqs38/VOfoCrATDtTvyfiO3fgjlSRaNkHabpTLgM7qru9ifqXlXbXk8SeQ==",
+                       "dev": true,
+                       "requires": {
+                               "@hapi/address": "2.x.x",
+                               "@hapi/hoek": "6.x.x",
+                               "@hapi/marker": "1.x.x",
+                               "@hapi/topo": "3.x.x"
+                       }
+               },
+               "@hapi/marker": {
+                       "version": "1.0.0",
+                       "resolved": "https://registry.npmjs.org/@hapi/marker/-/marker-1.0.0.tgz",
+                       "integrity": "sha512-JOfdekTXnJexfE8PyhZFyHvHjt81rBFSAbTIRAhF2vv/2Y1JzoKsGqxH/GpZJoF7aEfYok8JVcAHmSz1gkBieA==",
+                       "dev": true
+               },
+               "@hapi/topo": {
+                       "version": "3.1.2",
+                       "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.2.tgz",
+                       "integrity": "sha512-r+aumOqJ5QbD6aLPJWqVjMAPsx5pZKz+F5yPqXZ/WWG9JTtHbQqlzrJoknJ0iJxLj9vlXtmpSdjlkszseeG8OA==",
+                       "dev": true,
+                       "requires": {
+                               "@hapi/hoek": "8.x.x"
+                       },
+                       "dependencies": {
+                               "@hapi/hoek": {
+                                       "version": "8.0.2",
+                                       "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.0.2.tgz",
+                                       "integrity": "sha512-O6o6mrV4P65vVccxymuruucb+GhP2zl9NLCG8OdoFRS8BEGw3vwpPp20wpAtpbQQxz1CEUtmxJGgWhjq1XA3qw==",
+                                       "dev": true
+                               }
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "@jest/console": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "24.7.1",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3672,6 +3719,28 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "trim-right": "^1.0.1"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "babel-helper-bindify-decorators": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz",
+                       "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=",
+                       "dev": true,
+                       "requires": {
+                               "babel-runtime": "^6.22.0",
+                               "babel-traverse": "^6.24.1",
+                               "babel-types": "^6.24.1"
+                       }
+               },
+               "babel-helper-builder-binary-assignment-operator-visitor": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
+                       "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=",
+                       "dev": true,
+                       "requires": {
+                               "babel-helper-explode-assignable-expression": "^6.24.1",
+                               "babel-runtime": "^6.22.0",
+                               "babel-types": "^6.24.1"
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "babel-helper-call-delegate": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "6.24.1",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3694,6 +3763,29 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "lodash": "^4.17.4"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "babel-helper-explode-assignable-expression": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
+                       "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=",
+                       "dev": true,
+                       "requires": {
+                               "babel-runtime": "^6.22.0",
+                               "babel-traverse": "^6.24.1",
+                               "babel-types": "^6.24.1"
+                       }
+               },
+               "babel-helper-explode-class": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz",
+                       "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=",
+                       "dev": true,
+                       "requires": {
+                               "babel-helper-bindify-decorators": "^6.24.1",
+                               "babel-runtime": "^6.22.0",
+                               "babel-traverse": "^6.24.1",
+                               "babel-types": "^6.24.1"
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "babel-helper-function-name": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "6.24.1",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3743,6 +3835,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "lodash": "^4.17.4"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "babel-helper-remap-async-to-generator": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
+                       "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
+                       "dev": true,
+                       "requires": {
+                               "babel-helper-function-name": "^6.24.1",
+                               "babel-runtime": "^6.22.0",
+                               "babel-template": "^6.24.1",
+                               "babel-traverse": "^6.24.1",
+                               "babel-types": "^6.24.1"
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "babel-helper-replace-supers": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "6.24.1",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3910,6 +4015,146 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "@types/babel__traverse": "^7.0.6"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "babel-plugin-syntax-async-functions": {
+                       "version": "6.13.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
+                       "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-async-generators": {
+                       "version": "6.13.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz",
+                       "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-class-constructor-call": {
+                       "version": "6.18.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz",
+                       "integrity": "sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-class-properties": {
+                       "version": "6.13.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
+                       "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-decorators": {
+                       "version": "6.13.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz",
+                       "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-do-expressions": {
+                       "version": "6.13.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz",
+                       "integrity": "sha1-V0d1YTmqJtOQ0JQQsDdEugfkeW0=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-dynamic-import": {
+                       "version": "6.18.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
+                       "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-exponentiation-operator": {
+                       "version": "6.13.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
+                       "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-export-extensions": {
+                       "version": "6.13.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz",
+                       "integrity": "sha1-cKFITw+QiaToStRLrDU8lbmxJyE=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-function-bind": {
+                       "version": "6.13.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz",
+                       "integrity": "sha1-SMSV8Xe98xqYHnMvVa3AvdJgH0Y=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-object-rest-spread": {
+                       "version": "6.13.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
+                       "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
+                       "dev": true
+               },
+               "babel-plugin-syntax-trailing-function-commas": {
+                       "version": "6.22.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
+                       "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=",
+                       "dev": true
+               },
+               "babel-plugin-transform-async-generator-functions": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz",
+                       "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=",
+                       "dev": true,
+                       "requires": {
+                               "babel-helper-remap-async-to-generator": "^6.24.1",
+                               "babel-plugin-syntax-async-generators": "^6.5.0",
+                               "babel-runtime": "^6.22.0"
+                       }
+               },
+               "babel-plugin-transform-async-to-generator": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
+                       "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=",
+                       "dev": true,
+                       "requires": {
+                               "babel-helper-remap-async-to-generator": "^6.24.1",
+                               "babel-plugin-syntax-async-functions": "^6.8.0",
+                               "babel-runtime": "^6.22.0"
+                       }
+               },
+               "babel-plugin-transform-class-constructor-call": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz",
+                       "integrity": "sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk=",
+                       "dev": true,
+                       "requires": {
+                               "babel-plugin-syntax-class-constructor-call": "^6.18.0",
+                               "babel-runtime": "^6.22.0",
+                               "babel-template": "^6.24.1"
+                       }
+               },
+               "babel-plugin-transform-class-properties": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
+                       "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
+                       "dev": true,
+                       "requires": {
+                               "babel-helper-function-name": "^6.24.1",
+                               "babel-plugin-syntax-class-properties": "^6.8.0",
+                               "babel-runtime": "^6.22.0",
+                               "babel-template": "^6.24.1"
+                       }
+               },
+               "babel-plugin-transform-decorators": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz",
+                       "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=",
+                       "dev": true,
+                       "requires": {
+                               "babel-helper-explode-class": "^6.24.1",
+                               "babel-plugin-syntax-decorators": "^6.13.0",
+                               "babel-runtime": "^6.22.0",
+                               "babel-template": "^6.24.1",
+                               "babel-types": "^6.24.1"
+                       }
+               },
+               "babel-plugin-transform-do-expressions": {
+                       "version": "6.22.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz",
+                       "integrity": "sha1-KMyvkoEtlJws0SgfaQyP3EaK6bs=",
+                       "dev": true,
+                       "requires": {
+                               "babel-plugin-syntax-do-expressions": "^6.8.0",
+                               "babel-runtime": "^6.22.0"
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "babel-plugin-transform-es2015-arrow-functions": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "6.22.0",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4122,6 +4367,47 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "regexpu-core": "^2.0.0"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "babel-plugin-transform-exponentiation-operator": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
+                       "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=",
+                       "dev": true,
+                       "requires": {
+                               "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1",
+                               "babel-plugin-syntax-exponentiation-operator": "^6.8.0",
+                               "babel-runtime": "^6.22.0"
+                       }
+               },
+               "babel-plugin-transform-export-extensions": {
+                       "version": "6.22.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz",
+                       "integrity": "sha1-U3OLR+deghhYnuqUbLvTkQm75lM=",
+                       "dev": true,
+                       "requires": {
+                               "babel-plugin-syntax-export-extensions": "^6.8.0",
+                               "babel-runtime": "^6.22.0"
+                       }
+               },
+               "babel-plugin-transform-function-bind": {
+                       "version": "6.22.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz",
+                       "integrity": "sha1-xvuOlqwpajELjPjqQBRiQH3fapc=",
+                       "dev": true,
+                       "requires": {
+                               "babel-plugin-syntax-function-bind": "^6.8.0",
+                               "babel-runtime": "^6.22.0"
+                       }
+               },
+               "babel-plugin-transform-object-rest-spread": {
+                       "version": "6.26.0",
+                       "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
+                       "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
+                       "dev": true,
+                       "requires": {
+                               "babel-plugin-syntax-object-rest-spread": "^6.8.0",
+                               "babel-runtime": "^6.26.0"
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "babel-plugin-transform-regenerator": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "6.26.0",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4180,6 +4466,53 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "babel-plugin-jest-hoist": "^24.6.0"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "babel-preset-stage-0": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz",
+                       "integrity": "sha1-VkLRUEL5E4TX5a+LyIsduVsDnmo=",
+                       "dev": true,
+                       "requires": {
+                               "babel-plugin-transform-do-expressions": "^6.22.0",
+                               "babel-plugin-transform-function-bind": "^6.22.0",
+                               "babel-preset-stage-1": "^6.24.1"
+                       }
+               },
+               "babel-preset-stage-1": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz",
+                       "integrity": "sha1-dpLNfc1oSZB+auSgqFWJz7niv7A=",
+                       "dev": true,
+                       "requires": {
+                               "babel-plugin-transform-class-constructor-call": "^6.24.1",
+                               "babel-plugin-transform-export-extensions": "^6.22.0",
+                               "babel-preset-stage-2": "^6.24.1"
+                       }
+               },
+               "babel-preset-stage-2": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz",
+                       "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=",
+                       "dev": true,
+                       "requires": {
+                               "babel-plugin-syntax-dynamic-import": "^6.18.0",
+                               "babel-plugin-transform-class-properties": "^6.24.1",
+                               "babel-plugin-transform-decorators": "^6.24.1",
+                               "babel-preset-stage-3": "^6.24.1"
+                       }
+               },
+               "babel-preset-stage-3": {
+                       "version": "6.24.1",
+                       "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz",
+                       "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=",
+                       "dev": true,
+                       "requires": {
+                               "babel-plugin-syntax-trailing-function-commas": "^6.22.0",
+                               "babel-plugin-transform-async-generator-functions": "^6.24.1",
+                               "babel-plugin-transform-async-to-generator": "^6.24.1",
+                               "babel-plugin-transform-exponentiation-operator": "^6.24.1",
+                               "babel-plugin-transform-object-rest-spread": "^6.22.0"
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "babel-register": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "6.26.0",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5837,6 +6170,174 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "copyfiles": {
+                       "version": "2.1.1",
+                       "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.1.1.tgz",
+                       "integrity": "sha512-y6DZHve80whydXzBal7r70TBgKMPKesVRR1Sn/raUu7Jh/i7iSLSyGvYaq0eMJ/3Y/CKghwzjY32q1WzEnpp3Q==",
+                       "dev": true,
+                       "requires": {
+                               "glob": "^7.0.5",
+                               "minimatch": "^3.0.3",
+                               "mkdirp": "^0.5.1",
+                               "noms": "0.0.0",
+                               "through2": "^2.0.1",
+                               "yargs": "^13.2.4"
+                       },
+                       "dependencies": {
+                               "ansi-regex": {
+                                       "version": "4.1.0",
+                                       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+                                       "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+                                       "dev": true
+                               },
+                               "ansi-styles": {
+                                       "version": "3.2.1",
+                                       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+                                       "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+                                       "dev": true,
+                                       "requires": {
+                                               "color-convert": "^1.9.0"
+                                       }
+                               },
+                               "camelcase": {
+                                       "version": "5.3.1",
+                                       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+                                       "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+                                       "dev": true
+                               },
+                               "cliui": {
+                                       "version": "5.0.0",
+                                       "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+                                       "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+                                       "dev": true,
+                                       "requires": {
+                                               "string-width": "^3.1.0",
+                                               "strip-ansi": "^5.2.0",
+                                               "wrap-ansi": "^5.1.0"
+                                       }
+                               },
+                               "find-up": {
+                                       "version": "3.0.0",
+                                       "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+                                       "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+                                       "dev": true,
+                                       "requires": {
+                                               "locate-path": "^3.0.0"
+                                       }
+                               },
+                               "get-caller-file": {
+                                       "version": "2.0.5",
+                                       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+                                       "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+                                       "dev": true
+                               },
+                               "locate-path": {
+                                       "version": "3.0.0",
+                                       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+                                       "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+                                       "dev": true,
+                                       "requires": {
+                                               "p-locate": "^3.0.0",
+                                               "path-exists": "^3.0.0"
+                                       }
+                               },
+                               "p-limit": {
+                                       "version": "2.2.0",
+                                       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
+                                       "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
+                                       "dev": true,
+                                       "requires": {
+                                               "p-try": "^2.0.0"
+                                       }
+                               },
+                               "p-locate": {
+                                       "version": "3.0.0",
+                                       "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+                                       "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+                                       "dev": true,
+                                       "requires": {
+                                               "p-limit": "^2.0.0"
+                                       }
+                               },
+                               "p-try": {
+                                       "version": "2.2.0",
+                                       "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+                                       "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+                                       "dev": true
+                               },
+                               "require-main-filename": {
+                                       "version": "2.0.0",
+                                       "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+                                       "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+                                       "dev": true
+                               },
+                               "string-width": {
+                                       "version": "3.1.0",
+                                       "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+                                       "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                                       "dev": true,
+                                       "requires": {
+                                               "emoji-regex": "^7.0.1",
+                                               "is-fullwidth-code-point": "^2.0.0",
+                                               "strip-ansi": "^5.1.0"
+                                       }
+                               },
+                               "strip-ansi": {
+                                       "version": "5.2.0",
+                                       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+                                       "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+                                       "dev": true,
+                                       "requires": {
+                                               "ansi-regex": "^4.1.0"
+                                       }
+                               },
+                               "wrap-ansi": {
+                                       "version": "5.1.0",
+                                       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+                                       "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+                                       "dev": true,
+                                       "requires": {
+                                               "ansi-styles": "^3.2.0",
+                                               "string-width": "^3.0.0",
+                                               "strip-ansi": "^5.0.0"
+                                       }
+                               },
+                               "y18n": {
+                                       "version": "4.0.0",
+                                       "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+                                       "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+                                       "dev": true
+                               },
+                               "yargs": {
+                                       "version": "13.3.0",
+                                       "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
+                                       "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
+                                       "dev": true,
+                                       "requires": {
+                                               "cliui": "^5.0.0",
+                                               "find-up": "^3.0.0",
+                                               "get-caller-file": "^2.0.1",
+                                               "require-directory": "^2.1.1",
+                                               "require-main-filename": "^2.0.0",
+                                               "set-blocking": "^2.0.0",
+                                               "string-width": "^3.0.0",
+                                               "which-module": "^2.0.0",
+                                               "y18n": "^4.0.0",
+                                               "yargs-parser": "^13.1.1"
+                                       }
+                               },
+                               "yargs-parser": {
+                                       "version": "13.1.1",
+                                       "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
+                                       "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
+                                       "dev": true,
+                                       "requires": {
+                                               "camelcase": "^5.0.0",
+                                               "decamelize": "^1.2.0"
+                                       }
+                               }
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "core-js": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "3.1.4",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5950,6 +6451,31 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "sha.js": "^2.4.8"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "cross-env": {
+                       "version": "5.2.0",
+                       "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz",
+                       "integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==",
+                       "dev": true,
+                       "requires": {
+                               "cross-spawn": "^6.0.5",
+                               "is-windows": "^1.0.0"
+                       },
+                       "dependencies": {
+                               "cross-spawn": {
+                                       "version": "6.0.5",
+                                       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+                                       "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+                                       "dev": true,
+                                       "requires": {
+                                               "nice-try": "^1.0.4",
+                                               "path-key": "^2.0.1",
+                                               "semver": "^5.5.0",
+                                               "shebang-command": "^1.2.0",
+                                               "which": "^1.2.9"
+                                       }
+                               }
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "cross-spawn": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "5.1.0",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5960,6 +6486,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "which": "^1.2.9"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "cross-var": {
+                       "version": "1.1.0",
+                       "resolved": "https://registry.npmjs.org/cross-var/-/cross-var-1.1.0.tgz",
+                       "integrity": "sha1-8PDUuyNdlRONGlOYQtKQ8A23HNY=",
+                       "dev": true,
+                       "requires": {
+                               "babel-preset-es2015": "^6.18.0",
+                               "babel-preset-stage-0": "^6.16.0",
+                               "babel-register": "^6.18.0",
+                               "cross-spawn": "^5.0.1",
+                               "exit": "^0.1.2"
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "crypto-browserify": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "3.12.0",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7070,6 +7609,48 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "is-obj": "^1.0.0"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "dotenv-cli": {
+                       "version": "2.0.1",
+                       "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-2.0.1.tgz",
+                       "integrity": "sha512-RnjvnE+r27ni9j93w1ddMs9mQgxWlRozSfby7M4xVDJ5/DgLOFFAP92JrmXHkpn8dXCy+OObRx+w5wx0Dc3yww==",
+                       "dev": true,
+                       "requires": {
+                               "cross-spawn": "^4.0.0",
+                               "dotenv": "^7.0.0",
+                               "dotenv-expand": "^5.0.0",
+                               "minimist": "^1.1.3"
+                       },
+                       "dependencies": {
+                               "cross-spawn": {
+                                       "version": "4.0.2",
+                                       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
+                                       "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=",
+                                       "dev": true,
+                                       "requires": {
+                                               "lru-cache": "^4.0.1",
+                                               "which": "^1.2.9"
+                                       }
+                               },
+                               "dotenv": {
+                                       "version": "7.0.0",
+                                       "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz",
+                                       "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==",
+                                       "dev": true
+                               },
+                               "minimist": {
+                                       "version": "1.2.0",
+                                       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+                                       "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+                                       "dev": true
+                               }
+                       }
+               },
+               "dotenv-expand": {
+                       "version": "5.1.0",
+                       "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
+                       "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
+                       "dev": true
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "download": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "4.4.3",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/download/-/download-4.4.3.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -11115,12 +11696,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                "minimalistic-crypto-utils": "^1.0.1"
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "hoek": {
-                       "version": "5.0.4",
-                       "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz",
-                       "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==",
-                       "dev": true
-               },
</del><span class="cx" style="display: block; padding: 0 10px">                 "hoist-non-react-statics": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "2.5.5",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12267,23 +12842,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
</span><span class="cx" style="display: block; padding: 0 10px">                        "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "isemail": {
-                       "version": "3.2.0",
-                       "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz",
-                       "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==",
-                       "dev": true,
-                       "requires": {
-                               "punycode": "2.x.x"
-                       },
-                       "dependencies": {
-                               "punycode": {
-                                       "version": "2.1.1",
-                                       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-                                       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
-                                       "dev": true
-                               }
-                       }
-               },
</del><span class="cx" style="display: block; padding: 0 10px">                 "isexe": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "2.0.0",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -13756,17 +14314,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "joi": {
-                       "version": "13.7.0",
-                       "resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz",
-                       "integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==",
-                       "dev": true,
-                       "requires": {
-                               "hoek": "5.x.x",
-                               "isemail": "3.x.x",
-                               "topo": "3.x.x"
-                       }
-               },
</del><span class="cx" style="display: block; padding: 0 10px">                 "jpegtran-bin": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "3.2.0",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/jpegtran-bin/-/jpegtran-bin-3.2.0.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -15598,6 +16145,42 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        "dev": true,
</span><span class="cx" style="display: block; padding: 0 10px">                        "optional": true
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "noms": {
+                       "version": "0.0.0",
+                       "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz",
+                       "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=",
+                       "dev": true,
+                       "requires": {
+                               "inherits": "^2.0.1",
+                               "readable-stream": "~1.0.31"
+                       },
+                       "dependencies": {
+                               "isarray": {
+                                       "version": "0.0.1",
+                                       "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+                                       "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+                                       "dev": true
+                               },
+                               "readable-stream": {
+                                       "version": "1.0.34",
+                                       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+                                       "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+                                       "dev": true,
+                                       "requires": {
+                                               "core-util-is": "~1.0.0",
+                                               "inherits": "~2.0.1",
+                                               "isarray": "0.0.1",
+                                               "string_decoder": "~0.10.x"
+                                       }
+                               },
+                               "string_decoder": {
+                                       "version": "0.10.31",
+                                       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+                                       "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+                                       "dev": true
+                               }
+                       }
+               },
</ins><span class="cx" style="display: block; padding: 0 10px">                 "nopt": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "3.0.6",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20524,23 +21107,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
</span><span class="cx" style="display: block; padding: 0 10px">                        "dev": true
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "topo": {
-                       "version": "3.0.3",
-                       "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz",
-                       "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==",
-                       "dev": true,
-                       "requires": {
-                               "hoek": "6.x.x"
-                       },
-                       "dependencies": {
-                               "hoek": {
-                                       "version": "6.1.3",
-                                       "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz",
-                                       "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==",
-                                       "dev": true
-                               }
-                       }
-               },
</del><span class="cx" style="display: block; padding: 0 10px">                 "toposort": {
</span><span class="cx" style="display: block; padding: 0 10px">                        "version": "2.0.2",
</span><span class="cx" style="display: block; padding: 0 10px">                        "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -21334,13 +21900,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><span class="cx" style="display: block; padding: 0 10px">                "wait-on": {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        "version": "3.2.0",
-                       "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-3.2.0.tgz",
-                       "integrity": "sha512-QUGNKlKLDyY6W/qHdxaRlXUAgLPe+3mLL/tRByHpRNcHs/c7dZXbu+OnJWGNux6tU1WFh/Z8aEwvbuzSAu79Zg==",
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 "version": "3.3.0",
+                       "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-3.3.0.tgz",
+                       "integrity": "sha512-97dEuUapx4+Y12aknWZn7D25kkjMk16PbWoYzpSdA8bYpVfS6hpl2a2pOWZ3c+Tyt3/i4/pglyZctG3J4V1hWQ==",
</ins><span class="cx" style="display: block; padding: 0 10px">                         "dev": true,
</span><span class="cx" style="display: block; padding: 0 10px">                        "requires": {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                "core-js": "^2.5.7",
-                               "joi": "^13.0.0",
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         "@hapi/joi": "^15.0.3",
+                               "core-js": "^2.6.5",
</ins><span class="cx" style="display: block; padding: 0 10px">                                 "minimist": "^1.2.0",
</span><span class="cx" style="display: block; padding: 0 10px">                                "request": "^2.88.0",
</span><span class="cx" style="display: block; padding: 0 10px">                                "rx": "^4.1.0"
</span></span></pre></div>
<a id="trunkpackagejson"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/package.json</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/package.json        2019-08-04 14:43:21 UTC (rev 45744)
+++ trunk/package.json  2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -22,8 +22,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">                "babel-jest": "24.8.0",
</span><span class="cx" style="display: block; padding: 0 10px">                "check-node-version": "3.2.0",
</span><span class="cx" style="display: block; padding: 0 10px">                "copy-webpack-plugin": "^4.6.0",
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "copyfiles": "2.1.1",
</ins><span class="cx" style="display: block; padding: 0 10px">                 "core-js": "3.1.4",
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "cross-env": "5.2.0",
+               "cross-var": "1.1.0",
</ins><span class="cx" style="display: block; padding: 0 10px">                 "cssnano": "4.1.8",
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "dotenv-cli": "2.0.1",
</ins><span class="cx" style="display: block; padding: 0 10px">                 "grunt": "~1.0.3",
</span><span class="cx" style="display: block; padding: 0 10px">                "grunt-banner": "^0.6.0",
</span><span class="cx" style="display: block; padding: 0 10px">                "grunt-contrib-clean": "~2.0.0",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -53,6 +57,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                "source-map-loader": "^0.2.4",
</span><span class="cx" style="display: block; padding: 0 10px">                "uglify-js": "^3.4.9",
</span><span class="cx" style="display: block; padding: 0 10px">                "uglifyjs-webpack-plugin": "2.1.1",
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                "wait-on": "3.3.0",
</ins><span class="cx" style="display: block; padding: 0 10px">                 "webpack": "4.29.2",
</span><span class="cx" style="display: block; padding: 0 10px">                "webpack-dev-server": "3.1.14",
</span><span class="cx" style="display: block; padding: 0 10px">                "webpack-livereload-plugin": "2.2.0"
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -119,12 +124,32 @@
</span><span class="cx" style="display: block; padding: 0 10px">        },
</span><span class="cx" style="display: block; padding: 0 10px">        "scripts": {
</span><span class="cx" style="display: block; padding: 0 10px">                "build": "grunt build",
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "dev": "grunt build --dev",
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         "build:dev": "grunt build --dev",
+               "dev": "grunt watch --dev",
</ins><span class="cx" style="display: block; padding: 0 10px">                 "test": "grunt test",
</span><span class="cx" style="display: block; padding: 0 10px">                "watch": "grunt watch",
</span><span class="cx" style="display: block; padding: 0 10px">                "grunt": "grunt",
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "env:start": "./tools/local-env/start.sh",
-               "env:reset-site": "./tools/local-env/install-wordpress.sh --reset-site",
-               "test:e2e": "wp-scripts test-e2e --config tests/e2e/jest.config.js"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         "env:start": "dotenv npm run env:__start-next",
+               "env:__start-next": "docker-compose -f ./tools/local-env/docker-compose.yml up -d",
+               "env:stop": "dotenv npm run env:__stop-next",
+               "env:clean": "dotenv npm run env:__stop-next -- -- -v --remove-orphans",
+               "env:reset": "dotenv npm run env:__stop-next -- -- --rmi all -v --remove-orphans",
+               "env:__stop-next": "docker-compose -f ./tools/local-env/docker-compose.yml -f ./tools/local-env/docker-compose.scripts.yml down",
+               "env:install": "dotenv npm run env:__install-next",
+               "env:__install-next": "npm run env:__install-config && npm run env:__install-config-define-wp_debug && npm run env:__install-config-define-wp_debug_log && npm run env:__install-config-define-wp_debug_display && npm run env:__install-config-define-script_debug && copyfiles -f src/wp-config.php . && npm run env:__reset-site && npm run env:__install-site",
+               "env:__install-config": "cross-var npm run env:__cli-next config create -- --dbname=wordpress_develop --dbuser=root --dbpass=password --dbhost=mysql --path=/var/www/src --force",
+               "env:__install-config-define-wp_debug": "cross-var npm run env:__cli-next config set WP_DEBUG $LOCAL_WP_DEBUG -- --raw",
+               "env:__install-config-define-wp_debug_log": "cross-var npm run env:__cli-next config set WP_DEBUG_LOG $LOCAL_WP_DEBUG_LOG -- --raw",
+               "env:__install-config-define-wp_debug_display": "cross-var npm run env:__cli-next config set WP_DEBUG_DISPLAY $LOCAL_WP_DEBUG_DISPLAY -- --raw",
+               "env:__install-config-define-script_debug": "cross-var npm run env:__cli-next config set SCRIPT_DEBUG $LOCAL_SCRIPT_DEBUG -- --raw",
+               "env:__install-site": "cross-var wait-on tcp:localhost:$LOCAL_PORT && cross-var npm run env:__cli-next core install -- --title=WPDEV --admin_user=admin --admin_password=password --admin_email=test@test.com --skip-email --url=http://localhost:$LOCAL_PORT --quiet",
+               "env:__reset-site": "cross-var wait-on tcp:localhost:$LOCAL_PORT && npm run env:__cli-next db reset -- --yes --quiet",
+               "env:cli": "dotenv npm run env:__cli-next",
+               "env:__cli-next": "docker-compose -f ./tools/local-env/docker-compose.yml -f ./tools/local-env/docker-compose.scripts.yml run --rm cli",
+               "env:logs": "docker-compose -f ./tools/local-env/docker-compose.yml -f ./tools/local-env/docker-compose.scripts.yml logs",
+               "test:e2e": "dotenv npm run test:__e2e-next",
+               "test:__e2e-next": "cross-var cross-env WP_BASE_URL=http://localhost:$LOCAL_PORT wp-scripts test-e2e --config tests/e2e/jest.config.js",
+               "test:php": "dotenv npm run test:__php-next",
+               "test:__php-next": "docker-compose -f ./tools/local-env/docker-compose.yml -f ./tools/local-env/docker-compose.scripts.yml run --rm phpunit phpunit"
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunktoolslocalenvdefaulttemplate"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tools/local-env/default.template</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/default.template                            (rev 0)
+++ trunk/tools/local-env/default.template      2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,29 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+server {
+       index index.php index.html;
+
+       listen 80 default_server;
+       listen [::]:80 default_server;
+
+       server_name localhost;
+
+       client_max_body_size 1g;
+
+       error_log  /var/log/nginx/error.log;
+       access_log /var/log/nginx/access.log;
+
+       root /var/www/${LOCAL_DIR};
+
+       location / {
+               try_files $uri $uri/ /index.php?$args;
+       }
+
+       location ~ \.php$ {
+               try_files $uri =404;
+               fastcgi_split_path_info ^(.+\.php)(/.+)$;
+               fastcgi_pass php:9000;
+               fastcgi_index index.php;
+               include fastcgi_params;
+               fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+               fastcgi_param PATH_INFO $fastcgi_path_info;
+       }
+}
</ins></span></pre></div>
<a id="trunktoolslocalenvdockercomposescriptsyml"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tools/local-env/docker-compose.scripts.yml</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/docker-compose.scripts.yml                          (rev 0)
+++ trunk/tools/local-env/docker-compose.scripts.yml    2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,48 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+version: '3.7'
+
+services:
+
+  ##
+  # The WP CLI container.
+  ##
+  cli:
+    image: wordpressdevelop/cli:${LOCAL_PHP-latest}
+
+    networks:
+      - wpdevnet
+
+    environment:
+      LOCAL_PHP_XDEBUG: ${LOCAL_PHP_XDEBUG-false}
+
+    volumes:
+      - ../../:/var/www
+
+    # The init directive ensures the command runs with a PID > 1, so Ctrl+C works correctly.
+    init: true
+
+  ##
+  # The PHPUnit container.
+  ##
+  phpunit:
+    image: wordpressdevelop/phpunit:${LOCAL_PHP-latest}
+
+    networks:
+      - wpdevnet
+
+    environment:
+      LOCAL_PHP_XDEBUG: ${LOCAL_PHP_XDEBUG-false}
+
+    volumes:
+      - ./phpunit-config.ini:/usr/local/etc/php/conf.d/phpunit-config.ini
+      - ../../:/wordpress-develop
+      - phpunit-uploads:/wordpress-develop/${LOCAL_DIR-src}/wp-content/uploads
+
+    # The init directive ensures the command runs with a PID > 1, so Ctrl+C works correctly.
+    init: true
+
+    depends_on:
+      - mysql
+
+volumes:
+  # Using a volume for the uploads directory improves PHPUnit performance.
+  phpunit-uploads: {}
</ins></span></pre></div>
<a id="trunktoolslocalenvdockercomposeyml"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tools/local-env/docker-compose.yml</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/docker-compose.yml  2019-08-04 14:43:21 UTC (rev 45744)
+++ trunk/tools/local-env/docker-compose.yml    2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,41 +1,75 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-version: '3.1'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+version: '3.7'
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> services:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  wordpress:
-    image: wordpress
-    restart: always
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+  ##
+  # The web server container.
+  ##
+  wordpress-develop:
+    image: nginx:alpine
+
+    networks:
+      - wpdevnet
+
</ins><span class="cx" style="display: block; padding: 0 10px">     ports:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      - 8889:80
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      - ${LOCAL_PORT-8889}:80
+
</ins><span class="cx" style="display: block; padding: 0 10px">     environment:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      WORDPRESS_DB_HOST: mysql
-      WORDPRESS_DB_PASSWORD: example
-      ABSPATH: /usr/src/wordpress/
-      WORDPRESS_DEBUG: 1
-      WORDPRESS_CONFIG_EXTRA: |
-        define( 'SCRIPT_DEBUG', true );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      LOCAL_DIR: ${LOCAL_DIR-src}
+
</ins><span class="cx" style="display: block; padding: 0 10px">     volumes:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      - wordpress_data:/var/www/html
-      - ../../build/:/var/www/html/
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      - ./default.template:/etc/nginx/conf.d/default.template
+      - ../../:/var/www
+
+    # Load our config file, substituning environment variables into the config.
+    command: /bin/sh -c "envsubst '$$LOCAL_DIR' < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"
+
</ins><span class="cx" style="display: block; padding: 0 10px">     depends_on:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      - mysql
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      - php
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  cli:
-    image: wordpress:cli
-    restart: always
-    user: xfs
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  ##
+  # The PHP container.
+  ##
+  php:
+    image: wordpressdevelop/php:${LOCAL_PHP-latest}
+
+    networks:
+      - wpdevnet
+
+    environment:
+      LOCAL_PHP_XDEBUG: ${LOCAL_PHP_XDEBUG-false}
+
</ins><span class="cx" style="display: block; padding: 0 10px">     volumes:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      - wordpress_data:/var/www/html
-      - ../../build/:/var/www/html/
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      - ./php-config.ini:/usr/local/etc/php/conf.d/php-config.ini
+      - ../../:/var/www
+
</ins><span class="cx" style="display: block; padding: 0 10px">     depends_on:
</span><span class="cx" style="display: block; padding: 0 10px">       - mysql
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      - wordpress
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  ##
+  # The MySQL container.
+  ##
</ins><span class="cx" style="display: block; padding: 0 10px">   mysql:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    image: mysql:5.7
-    restart: always
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    image: mysql:${LOCAL_MYSQL-latest}
+
+    networks:
+      - wpdevnet
+
</ins><span class="cx" style="display: block; padding: 0 10px">     environment:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      MYSQL_ROOT_PASSWORD: example
-      MYSQL_DATABASE: wordpress_test
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      MYSQL_ROOT_PASSWORD: password
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    volumes:
+      - ./mysql-init.sql:/docker-entrypoint-initdb.d/mysql-init.sql
+      - mysql:/var/lib/mysql
+
+    # For compatibility with PHP versions that don't support the caching_sha2_password auth plugin used in MySQL 8.0.
+    command: --default-authentication-plugin=mysql_native_password
+
</ins><span class="cx" style="display: block; padding: 0 10px"> volumes:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  wordpress_data:
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  # So that sites aren't wiped every time containers are restarted, MySQL uses a persistent volume.
+  mysql: {}
+
+networks:
+  # Creating our own network allows us to connect between containers using their service name.
+  wpdevnet:
+    driver: bridge
</ins></span></pre></div>
<a id="trunktoolslocalenvincludessh"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/tools/local-env/includes.sh</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/includes.sh 2019-08-04 14:43:21 UTC (rev 45744)
+++ trunk/tools/local-env/includes.sh   2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,134 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-#!/bin/bash
-
-##
-# Ask a Yes/No question, and way for a reply.
-#
-# This is a general-purpose function to ask Yes/No questions in Bash, either with or without a default
-# answer. It keeps repeating the question until it gets a valid answer.
-#
-# @param {string} prompt    The question to ask the user.
-# @param {string} [default] Optional. "Y" or "N", for the default option to use if none is entered.
-# @param {int}    [timeout] Optional. The number of seconds to wait before using the default option.
-#
-# @returns {bool} true if the user replies Yes, false if the user replies No.
-##
-ask() {
-    # Source: https://djm.me/ask
-    local timeout endtime timediff prompt default reply
-
-    while true; do
-
-               timeout="${3:-}"
-
-        if [ "${2:-}" = "Y" ]; then
-            prompt="Y/n"
-            default=Y
-        elif [ "${2:-}" = "N" ]; then
-            prompt="y/N"
-            default=N
-        else
-            prompt="y/n"
-            default=
-                       timeout=
-        fi
-
-               if [ -z "$timeout" ]; then
-               # Ask the question (not using "read -p" as it uses stderr not stdout)
-               echo -en "$1 [$prompt] "
-
-               # Read the answer (use /dev/tty in case stdin is redirected from somewhere else)
-               read reply </dev/tty
-               else
-                       endtime=$((`date +%s` + $timeout));
-                       while [ "$endtime" -ge `date +%s` ]; do
-                               timediff=$(($endtime - `date +%s`))
-
-                               echo -en "\r$1 [$prompt] (Default $default in ${timediff}s) "
-                               read -t 1 reply </dev/tty
-
-                               if [ -n "$reply" ]; then
-                                       break
-                               fi
-                       done
-               fi
-
-        # Default?
-        if [ -z "$reply" ]; then
-            reply=$default
-        fi
-
-        # Check if the reply is valid
-        case "$reply" in
-            Y*|y*) return 0 ;;
-            N*|n*) return 1 ;;
-        esac
-
-    done
-}
-
-##
-# Download from a remote source.
-#
-# Checks for the existence of curl and wget, then downloads the remote file using the first available option.
-#
-# @param {string} remote  The remote file to download.
-# @param {string} [local] Optional. The local filename to use. If it isn't passed, STDOUT is used.
-#
-# @return {bool} Whether the download succeeded or not.
-##
-download() {
-    if command_exists "curl"; then
-        curl -s -o "${2:--}" "$1"
-    elif command_exists "wget"; then
-               wget -nv -O "${2:--}" "$1"
-    fi
-}
-
-##
-# Add error message formatting to a string, and echo it.
-#
-# @param {string} message The string to add formatting to.
-##
-error_message() {
-       echo -en "\033[31mERROR\033[0m: $1"
-}
-
-##
-# Add warning message formatting to a string, and echo it.
-#
-# @param {string} message The string to add formatting to.
-##
-warning_message() {
-       echo -en "\033[33mWARNING\033[0m: $1"
-}
-
-##
-# Add status message formatting to a string, and echo it.
-#
-# @param {string} message The string to add formatting to.
-##
-status_message() {
-       echo -en "\033[32mSTATUS\033[0m: $1"
-}
-
-##
-# Add formatting to an action string.
-#
-# @param {string} message The string to add formatting to.
-##
-action_format() {
-       echo -en "\033[32m$1\033[0m"
-}
-
-##
-# Check if the command exists as some sort of executable.
-#
-# The executable form of the command could be an alias, function, builtin, executable file or shell keyword.
-#
-# @param {string} command The command to check.
-#
-# @return {bool} Whether the command exists or not.
-##
-command_exists() {
-       type -t "$1" >/dev/null 2>&1
-}
</del></span></pre></div>
<a id="trunktoolslocalenvinstallnodenvmsh"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/tools/local-env/install-node-nvm.sh</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/install-node-nvm.sh 2019-08-04 14:43:21 UTC (rev 45744)
+++ trunk/tools/local-env/install-node-nvm.sh   2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,94 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-#!/bin/bash
-NVM_VERSION=`curl -Ls -w %{url_effective} -o /dev/null https://github.com/nvm-sh/nvm/releases/latest | rev | cut -d '/' -f 1 | rev`
-
-# Exit if any command fails
-set -e
-
-# Include useful functions
-. "$(dirname "$0")/includes.sh"
-
-# Load NVM
-if [ -n "$NVM_DIR" ]; then
-       # The --no-use option ensures loading NVM doesn't switch the current version.
-       if [ -f "$NVM_DIR/nvm.sh" ]; then
-               . "$NVM_DIR/nvm.sh" --no-use
-       elif command_exists "brew" && [ -f "$(brew --prefix nvm)/nvm.sh" ]; then
-               # use homebrew if that's how nvm was installed
-               . "$(brew --prefix nvm)/nvm.sh" --no-use
-       fi
-fi
-
-# Change to the expected directory
-cd "$(dirname "$0")/../.."
-
-# Check if nvm is installed
-if [ "$TRAVIS" != "true" ] && ! command_exists "nvm"; then
-       if ask "$(error_message "NVM isn't installed, would you like to download and install it automatically?")" Y; then
-               # The .bash_profile file needs to exist for NVM to install
-               if [ ! -e ~/.bash_profile ]; then
-                       touch ~/.bash_profile
-               fi
-
-               echo -en $(status_message "Installing NVM..." )
-               download "https://raw.githubusercontent.com/nvm-sh/nvm/$NVM_VERSION/install.sh" | bash >/dev/null 2>&1
-               echo ' done!'
-
-               echo -e $(warning_message "NVM was updated, please run this command to reload it:" )
-               echo -e $(warning_message "$(action_format ". \$HOME/.nvm/nvm.sh")" )
-               echo -e $(warning_message "After that, re-run the setup script to continue." )
-       else
-               echo -e $(error_message "")
-               echo -e $(error_message "Please install NVM manually, then re-run the setup script to continue.")
-               echo -e $(error_message "NVM installation instructions can be found here: $(action_format "https://github.com/nvm-sh/nvm")")
-       fi
-
-       exit 1
-fi
-
-# Check if the current nvm version is up to date.
-if [ "$TRAVIS" != "true" ] && [ $NVM_VERSION != "v$(nvm --version)" ]; then
-       echo -en $(status_message "Updating NVM..." )
-       download "https://raw.githubusercontent.com/nvm-sh/nvm/$NVM_VERSION/install.sh" | bash >/dev/null 2>&1
-       echo ' done!'
-
-       echo -e $(warning_message "NVM was updated, please run this command to reload it:" )
-       echo -e $(warning_message "$(action_format ". \$HOME/.nvm/nvm.sh")" )
-       echo -e $(warning_message "After that, re-run the setup script to continue." )
-       exit 1
-fi
-
-# Check if the current node version is up to date.
-if [ "$TRAVIS" != "true" ] && [ "$(nvm current)" != "$(nvm version-remote --lts)" ]; then
-       echo -e $(warning_message "Node version does not match the latest long term support version. Please run this command to install and use it:" )
-       echo -e $(warning_message "$(action_format "nvm install")" )
-       echo -e $(warning_message "After that, re-run the setup script to continue." )
-       exit 1
-fi
-
-# Install/update packages
-echo -e $(status_message "Installing and updating NPM packages..." )
-npm install
-
-# Make sure npm is up-to-date
-npm install npm -g
-
-# There was a bug in NPM that caused changes in package-lock.json. Handle that.
-if [ "$TRAVIS" != "true" ] && ! git diff --no-ext-diff --exit-code package-lock.json >/dev/null; then
-       if ask "$(warning_message "Your package-lock.json changed, which may mean there's an issue with your NPM cache. Would you like to try and automatically clean it up?" )" N 10; then
-               rm -rf node_modules/
-               npm cache clean --force >/dev/null 2>&1
-               git checkout package-lock.json
-
-               echo -e $(status_message "Reinstalling NPM packages..." )
-               npm install
-
-               # Check that it's cleaned up now.
-               if git diff --no-ext-diff --exit-code package-lock.json >/dev/null; then
-                       echo -e $(warning_message "Confirmed that the NPM cache is cleaned up." )
-               else
-                       echo -e $(error_message "We were unable to clean the NPM cache, please manually review the changes to package-lock.json. Continuing with the setup process..." )
-               fi
-       else
-               echo -e $(warning_message "Please manually review the changes to package-lock.json. Continuing with the setup process..." )
-       fi
-fi
</del></span></pre></div>
<a id="trunktoolslocalenvinstallwordpresssh"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/tools/local-env/install-wordpress.sh</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/install-wordpress.sh        2019-08-04 14:43:21 UTC (rev 45744)
+++ trunk/tools/local-env/install-wordpress.sh  2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,88 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-#!/bin/bash
-
-# Exit if any command fails.
-set -e
-
-# Common variables.
-DOCKER_COMPOSE_FILE_OPTIONS="-f $(dirname "$0")/docker-compose.yml"
-WP_DEBUG=${WP_DEBUG-true}
-SCRIPT_DEBUG=${SCRIPT_DEBUG-true}
-
-# Gutenberg script includes.
-. "$(dirname "$0")/includes.sh"
-
-# These are the containers and values for the development site.
-CLI='cli'
-CONTAINER='wordpress'
-SITE_TITLE='WordPress Dev'
-
-# Get the host port for the WordPress container.
-HOST_PORT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS port $CONTAINER 80 | awk -F : '{printf $2}')
-
-# Wait until the Docker containers are running and the WordPress site is
-# responding to requests.
-echo -en $(status_message "Attempting to connect to WordPress...")
-until $(curl -L http://localhost:$HOST_PORT -so - 2>&1 | grep -q "WordPress"); do
-    echo -n '.'
-    sleep 5
-done
-echo ''
-
-# If this is the test site, we reset the database so no posts/comments/etc.
-# dirty up the tests.
-if [ "$1" == '--reset-site' ]; then
-       echo -e $(status_message "Resetting test database...")
-       docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI db reset --yes --quiet
-fi
-
-# Install WordPress.
-echo -e $(status_message "Installing WordPress...")
-# The `-u 33` flag tells Docker to run the command as a particular user and
-# prevents permissions errors. See: https://github.com/WordPress/gutenberg/pull/8427#issuecomment-410232369
-docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI core install --title="$SITE_TITLE" --admin_user=admin --admin_password=password --admin_email=test@test.com --skip-email --url=http://localhost:$HOST_PORT --quiet
-
-if [ "$E2E_ROLE" = "author" ]; then
-       echo -e $(status_message "Creating an additional author user for testing...")
-       # Create an additional author user for testing.
-       docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI user create author author@example.com --role=author --user_pass=authpass --quiet
-       # Assign the existing Hello World post to the author.
-       docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI post update 1 --post_author=2 --quiet
-fi
-
-CURRENT_WP_VERSION=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm $CLI core version)
-echo -e $(status_message "Current WordPress version: $CURRENT_WP_VERSION...")
-
-if [ "$WP_VERSION" == "latest" ]; then
-       # Check for WordPress updates, to make sure we're running the very latest version.
-       echo -e $(status_message "Updating WordPress to the latest version...")
-       docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI core update --quiet
-       echo -e $(status_message "Updating The WordPress Database...")
-       docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI core update-db --quiet
-fi
-
-# If the 'wordpress' volume wasn't during the down/up earlier, but the post port has changed, we need to update it.
-echo -e $(status_message "Checking the site's url...")
-CURRENT_URL=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm $CLI option get siteurl)
-if [ "$CURRENT_URL" != "http://localhost:$HOST_PORT" ]; then
-       docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI option update home "http://localhost:$HOST_PORT" --quiet
-       docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI option update siteurl "http://localhost:$HOST_PORT" --quiet
-fi
-
-# Install a dummy favicon to avoid 404 errors.
-echo -e $(status_message "Installing a dummy favicon...")
-docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm $CONTAINER touch /var/www/html/favicon.ico
-
-# Configure site constants.
-echo -e $(status_message "Configuring site constants...")
-WP_DEBUG_CURRENT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm -u 33 $CLI config get --type=constant --format=json WP_DEBUG)
-if [ $WP_DEBUG != $WP_DEBUG_CURRENT ]; then
-       docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI config set WP_DEBUG $WP_DEBUG --raw --type=constant --quiet
-       WP_DEBUG_RESULT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm -u 33 $CLI config get --type=constant --format=json WP_DEBUG)
-       echo -e $(status_message "WP_DEBUG: $WP_DEBUG_RESULT...")
-fi
-SCRIPT_DEBUG_CURRENT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm -u 33 $CLI config get --type=constant --format=json SCRIPT_DEBUG)
-if [ $SCRIPT_DEBUG != $SCRIPT_DEBUG_CURRENT ]; then
-       docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI config set SCRIPT_DEBUG $SCRIPT_DEBUG --raw --type=constant --quiet
-       SCRIPT_DEBUG_RESULT=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm -u 33 $CLI config get --type=constant --format=json SCRIPT_DEBUG)
-       echo -e $(status_message "SCRIPT_DEBUG: $SCRIPT_DEBUG_RESULT...")
-fi
</del></span></pre></div>
<a id="trunktoolslocalenvlaunchcontainerssh"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/tools/local-env/launch-containers.sh</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/launch-containers.sh        2019-08-04 14:43:21 UTC (rev 45744)
+++ trunk/tools/local-env/launch-containers.sh  2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,34 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-#!/bin/bash
-
-# Exit if any command fails.
-set -e
-
-# Common variables.
-DOCKER_COMPOSE_FILE_OPTIONS="-f $(dirname "$0")/docker-compose.yml"
-
-# Include useful functions.
-. "$(dirname "$0")/includes.sh"
-
-# Check that Docker is installed.
-if ! command_exists "docker"; then
-       echo -e $(error_message "Docker doesn't seem to be installed. Please head on over to the Docker site to download it: $(action_format "https://www.docker.com/products/docker-desktop")")
-       exit 1
-fi
-
-# Check that Docker is running.
-if ! docker info >/dev/null 2>&1; then
-       echo -e $(error_message "Docker isn't running. Please check that you've started your Docker app, and see it in your system tray.")
-       exit 1
-fi
-
-# Stop existing containers.
-echo -e $(status_message "Stopping Docker containers...")
-docker-compose $DOCKER_COMPOSE_FILE_OPTIONS down --remove-orphans >/dev/null
-
-# Download image updates.
-echo -e $(status_message "Downloading Docker image updates...")
-docker-compose $DOCKER_COMPOSE_FILE_OPTIONS pull
-
-# Launch the containers.
-echo -e $(status_message "Starting Docker containers...")
-docker-compose $DOCKER_COMPOSE_FILE_OPTIONS up -d >/dev/null
</del></span></pre></div>
<a id="trunktoolslocalenvmysqlinitsql"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tools/local-env/mysql-init.sql</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/mysql-init.sql                              (rev 0)
+++ trunk/tools/local-env/mysql-init.sql        2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,8 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * MySQL server init.
+ *
+ * SQL queries in this file will be executed the first time the MySQL server is started.
+ */
+
+CREATE DATABASE IF NOT EXISTS wordpress_develop;
+CREATE DATABASE IF NOT EXISTS wordpress_develop_tests;
</ins></span></pre></div>
<a id="trunktoolslocalenvphpconfigini"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tools/local-env/php-config.ini</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/php-config.ini                              (rev 0)
+++ trunk/tools/local-env/php-config.ini        2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,2 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+upload_max_filesize = 1G
+post_max_size = 1G
</ins></span></pre></div>
<a id="trunktoolslocalenvphpunitconfigini"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tools/local-env/phpunit-config.ini</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/phpunit-config.ini                          (rev 0)
+++ trunk/tools/local-env/phpunit-config.ini    2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,6 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+upload_max_filesize = 1G
+post_max_size = 1G
+
+opcache.enable = 1
+opcache.enable_cli = 1
+opache.file_cache = /tmp/php-opcache
</ins></span></pre></div>
<a id="trunktoolslocalenvstartsh"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/tools/local-env/start.sh</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tools/local-env/start.sh    2019-08-04 14:43:21 UTC (rev 45744)
+++ trunk/tools/local-env/start.sh      2019-08-05 07:09:14 UTC (rev 45745)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,65 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-#!/bin/bash
-
-# Exit if any command fails
-set -e
-
-# Include useful functions
-. "$(dirname "$0")/includes.sh"
-
-# Change to the expected directory
-cd "$(dirname "$0")/../../"
-
-# Check Node and NVM are installed
-. "$(dirname "$0")/install-node-nvm.sh"
-
-# Check Docker is installed and running and launch the containers
-. "$(dirname "$0")/launch-containers.sh"
-
-# Set up WordPress Development site.
-# Note: we don't bother installing the test site right now, because that's
-# done on every time `npm run test-e2e` is run.
-. "$(dirname "$0")/install-wordpress.sh"
-
-! read -d '' WORDPRESS <<"EOT"
-                   `-/+osssssssssssso+/-`
-               ./oys+:.`            `.:+syo/.
-            .+ys:.   .:/osyyhhhhyyso/:.   ./sy+.
-          /ys:   -+ydmmmmmmmmmmmmmmmmmmdy+-   :sy/
-        /h+`  -odmmmmmmmmmmmmmmmmmmmmmmmmmmdo-  `+h/
-      :ho`  /hmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmds/   `oh:
-    `sy.  /hmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmd+        .ys`
-   .ho  `sdddhhhyhmmmdyyhhhdddddhhhyydmmmmy           oh.
-  .h+          ``-dmmy.``         ``.ymmmmh            +h.
- `ho  `       /mmmmmmmmmmo       .dmmmmmmmms        ~~  oh`
- oy  .h`       ymmmmmmmmmm:       /mmmmmmmmmy`      -d.  yo
-.d-  ymy       `dmmmmmmmmmd.       ymmmmmmmmmh`     /my  -d.
-oy  -mmm+       /mmmmmmmmmmy       .dmmmmmmmmmy     ymm-  yo
-h+  +mmmd-       smmmmmmmmmm+       /mmmmmmmmmm-   :mmm+  +h
-d/  smmmmh`      `dmmmmmmmmmd`       smmmmmmmmm:  `dmmms  /d
-d/  smmmmms       :mmmmmmmmm+        `dmmmmmmmd.  smmmms  /d
-h+  +mmmmmm/       smmmmmmmh  +       /mmmmmmmy  /mmmmm+  +h
-oy  -mmmmmmd.      `dmmmmmd- +m/       smmmmmd. .dmmmmm-  yo
-.d-  ymmmmmmh       :mmmmm+ .dmd-      `dmmmm/  ymmmmmy  -d.
- oy  .dmmmmmmo       smmmh  hmmmh`      :mmmy  +mmmmmd.  yo
- `ho  -dmmmmmd:      `dmd- ommmmms       smd- .dmmmmd-  oh`
-  .h+  -dmmmmmd`      :m+ -dmmmmmm:      `do  hmmmmd-  +h.
-   .ho  .ymmmmmy       + `hmmmmmmmd.      :` ommmmy.  oh.
-    `sy.  /hmmmm+        ommmmmmmmmy        -dmmh/  .ys`
-      :ho`  /hmmd-      :mmmmmmmmmmmo      `hmh/  `oh:
-        /h+`  -odh`    `dmmmmmmmmmmmd:     oo-  `+h/
-          /ys:   ~~    smmmmmmmmmmmmmd`       :sy/
-            .+ys/.    `/osyyhhhhyyso/:`   ./sy+.
-               ./oys+:.`            `.:+syo/.
-                   `-/+osssssssssssso+/-`
-EOT
-
-CURRENT_URL=$(docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run -T --rm cli option get siteurl)
-
-echo -e "\nWelcome to...\n"
-echo -e "\033[95m$WORDPRESS\033[0m"
-
-# Give the user more context to what they should do next: Run the environment and start testing!
-echo -e "\nOpen $(action_format "$CURRENT_URL") to get started!"
-
-echo -e "\n\nAccess the above install using the following credentials:"
-echo -e "Default username: $(action_format "admin"), password: $(action_format "password")"
</del></span></pre>
</div>
</div>

</body>
</html>