diff --git a/.gitignore b/.gitignore index 723ef36..d09ac72 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -.idea \ No newline at end of file +.idea +.DS_Store +*.pyc diff --git a/README.md b/README.md index ffff7bc..8d99c68 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # judge-workers -This is one of the component of Coding Blocke Online Code Judge v2 +This is one of the components of Coding Blocks Online Code Judge v2 [![Build Status](https://travis-ci.org/coding-blocks/judge-workers.svg?branch=master)](https://travis-ci.org/coding-blocks/judge-workers) @@ -17,17 +17,18 @@ All workers are built on top of [alpine linux](https://alpinelinux.org/) 3.6 ## Supported Languages -Currently we have following images - - - - [c](containers/c) - - [cpp](containers/cpp) - - [c#](containers/csharp) - - [golang](containers/golang) - - [java8](containers/java8) - - [nodejs6](containers/nodejs6) - - [nodejs](containers/nodejs8) - - [perl](containers/perl) - - [py2](containers/py2) - - [py3](containers/py3) - - [ruby](containers/ruby) - - [rust](containers/rust) +Currently, we have following images - + + - [c](containers/judge-worker/c) + - [cpp](containers/judge-worker/cpp) + - [c#](containers/judge-worker/csharp) + - [golang](containers/judge-worker/golang) + - [java8](containers/judge-worker/java8) + - [kotlin](containers/judge-worker/kotlin) + - [nodejs6](containers/judge-worker/nodejs6) + - [nodejs](containers/judge-worker/nodejs8) + - [perl](containers/judge-worker/perl) + - [py2](containers/judge-worker/py2) + - [py3](containers/judge-worker/py3) + - [ruby](containers/judge-worker/ruby) + - [rust](containers/judge-worker/rust) diff --git a/build_workers.sh b/build_workers.sh index 2e924b0..849958a 100755 --- a/build_workers.sh +++ b/build_workers.sh @@ -2,8 +2,10 @@ cd $(dirname "$0") DIR=$(cd -) -for i in $(ls "$DIR/containers") +for type in $(ls "$DIR/containers") do - # docker image rm codingblocks/judge-worker-$i - docker build -t codingblocks/judge-worker-$i $DIR/containers/$i + for lang in $(ls "$DIR/containers/$type") + do + docker build -t codingblocks/$type-$lang $DIR/containers/$type/$lang + done done diff --git a/containers/golang/compile.sh b/containers/golang/compile.sh deleted file mode 100644 index c0067c6..0000000 --- a/containers/golang/compile.sh +++ /dev/null @@ -1 +0,0 @@ -#!/usr/bin/env bash diff --git a/containers/golang/run.sh b/containers/golang/run.sh deleted file mode 100644 index 41d6799..0000000 --- a/containers/golang/run.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -chmod 777 main.go -go run main.go diff --git a/containers/base/Dockerfile b/containers/judge-worker/base/Dockerfile similarity index 100% rename from containers/base/Dockerfile rename to containers/judge-worker/base/Dockerfile diff --git a/containers/base/judge.sh b/containers/judge-worker/base/judge.sh similarity index 64% rename from containers/base/judge.sh rename to containers/judge-worker/base/judge.sh index 1a92d59..07a314d 100755 --- a/containers/base/judge.sh +++ b/containers/judge-worker/base/judge.sh @@ -15,12 +15,12 @@ # time=5 -memory=1024 +memory=10485760 while getopts ":t:m:" opt; do case $opt in - t) time="$OPTARG" + t) time=$OPTARG ;; - m) memory="$OPTARG" + m) memory=$OPTARG ;; \?) echo "Invalid option -$OPTARG" >&2 ;; @@ -48,26 +48,49 @@ function compilecode { function runcode { INPUT_FILE=$1 OUTPUT_DIR=$2 + TIME_LIMIT=$3 + MEMORY_LIMIT=$4 + + time=$TIME_LIMIT + memory=$MEMORY_LIMIT touch $OUTPUT_DIR/runguard.code touch $OUTPUT_DIR/runguard.time + touch $OUTPUT_DIR/runguard.out + touch $OUTPUT_DIR/debug + echo $memory > $OUTPUT_DIR/debug runguard \ -t $time \ + -m $memory \ -E $OUTPUT_DIR/runguard.code \ -T $OUTPUT_DIR/runguard.time \ /bin/run.sh < $INPUT_FILE 2> $OUTPUT_DIR/run.stderr 1> $OUTPUT_DIR/run.stdout } function main { - compilecode + runguard \ + -t 10 \ + /bin/compile.sh 2> compile.stderr if [ -d "testcases" ]; then for testcase in testcases/*; do - runcode $testcase/stdin $testcase/ + if [ -r "$testcase/timelimit" ]; then + timelimit=`cat $testcase/timelimit` + else + timelimit="5" + fi + + if [ -r "$testcase/memorylimit" ]; then + memorylimit=`cat $testcase/memorylimit` + else + memorylimit=10485760 + fi + + runcode $testcase/stdin $testcase/ $timelimit $memorylimit done else - runcode run.stdin . + runcode run.stdin . "5" 10485760 fi } diff --git a/containers/base/runguard/runguard-config.h b/containers/judge-worker/base/runguard/runguard-config.h similarity index 100% rename from containers/base/runguard/runguard-config.h rename to containers/judge-worker/base/runguard/runguard-config.h diff --git a/containers/base/runguard/runguard.c b/containers/judge-worker/base/runguard/runguard.c similarity index 100% rename from containers/base/runguard/runguard.c rename to containers/judge-worker/base/runguard/runguard.c diff --git a/containers/c/Dockerfile b/containers/judge-worker/c/Dockerfile similarity index 100% rename from containers/c/Dockerfile rename to containers/judge-worker/c/Dockerfile diff --git a/containers/c/compile.sh b/containers/judge-worker/c/compile.sh similarity index 100% rename from containers/c/compile.sh rename to containers/judge-worker/c/compile.sh diff --git a/containers/c/run.sh b/containers/judge-worker/c/run.sh similarity index 100% rename from containers/c/run.sh rename to containers/judge-worker/c/run.sh diff --git a/containers/cpp/Dockerfile b/containers/judge-worker/cpp/Dockerfile similarity index 100% rename from containers/cpp/Dockerfile rename to containers/judge-worker/cpp/Dockerfile diff --git a/containers/cpp/compile.sh b/containers/judge-worker/cpp/compile.sh similarity index 100% rename from containers/cpp/compile.sh rename to containers/judge-worker/cpp/compile.sh diff --git a/containers/cpp/run.sh b/containers/judge-worker/cpp/run.sh similarity index 100% rename from containers/cpp/run.sh rename to containers/judge-worker/cpp/run.sh diff --git a/containers/csharp/Dockerfile b/containers/judge-worker/csharp/Dockerfile similarity index 100% rename from containers/csharp/Dockerfile rename to containers/judge-worker/csharp/Dockerfile diff --git a/containers/csharp/compile.sh b/containers/judge-worker/csharp/compile.sh similarity index 100% rename from containers/csharp/compile.sh rename to containers/judge-worker/csharp/compile.sh diff --git a/containers/csharp/run.sh b/containers/judge-worker/csharp/run.sh similarity index 100% rename from containers/csharp/run.sh rename to containers/judge-worker/csharp/run.sh diff --git a/containers/csv/Dockerfile b/containers/judge-worker/csv/Dockerfile similarity index 100% rename from containers/csv/Dockerfile rename to containers/judge-worker/csv/Dockerfile diff --git a/containers/csv/compile.sh b/containers/judge-worker/csv/compile.sh similarity index 100% rename from containers/csv/compile.sh rename to containers/judge-worker/csv/compile.sh diff --git a/containers/csv/run.sh b/containers/judge-worker/csv/run.sh similarity index 100% rename from containers/csv/run.sh rename to containers/judge-worker/csv/run.sh diff --git a/containers/golang/Dockerfile b/containers/judge-worker/golang/Dockerfile similarity index 100% rename from containers/golang/Dockerfile rename to containers/judge-worker/golang/Dockerfile diff --git a/containers/judge-worker/golang/compile.sh b/containers/judge-worker/golang/compile.sh new file mode 100644 index 0000000..1090bb0 --- /dev/null +++ b/containers/judge-worker/golang/compile.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +go build -buildmode=exe -o main diff --git a/containers/judge-worker/golang/run.sh b/containers/judge-worker/golang/run.sh new file mode 100644 index 0000000..f032a03 --- /dev/null +++ b/containers/judge-worker/golang/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +chmod 777 main +./main diff --git a/containers/java/Dockerfile b/containers/judge-worker/java/Dockerfile similarity index 100% rename from containers/java/Dockerfile rename to containers/judge-worker/java/Dockerfile diff --git a/containers/java/compile.sh b/containers/judge-worker/java/compile.sh similarity index 100% rename from containers/java/compile.sh rename to containers/judge-worker/java/compile.sh diff --git a/containers/java/run.sh b/containers/judge-worker/java/run.sh similarity index 100% rename from containers/java/run.sh rename to containers/judge-worker/java/run.sh diff --git a/containers/java8/Dockerfile b/containers/judge-worker/java8/Dockerfile similarity index 100% rename from containers/java8/Dockerfile rename to containers/judge-worker/java8/Dockerfile diff --git a/containers/java8/compile.sh b/containers/judge-worker/java8/compile.sh similarity index 100% rename from containers/java8/compile.sh rename to containers/judge-worker/java8/compile.sh diff --git a/containers/java8/run.sh b/containers/judge-worker/java8/run.sh similarity index 100% rename from containers/java8/run.sh rename to containers/judge-worker/java8/run.sh diff --git a/containers/kotlin/Dockerfile b/containers/judge-worker/kotlin/Dockerfile similarity index 94% rename from containers/kotlin/Dockerfile rename to containers/judge-worker/kotlin/Dockerfile index 5f13e1b..e8f3d5c 100644 --- a/containers/kotlin/Dockerfile +++ b/containers/judge-worker/kotlin/Dockerfile @@ -11,7 +11,7 @@ RUN apk add --no-cache bash && \ rm kotlin-compiler-*.zip && \ rm kotlinc/bin/*.bat && \ apk del --no-cache build-dependencies -ENV PATH $PATH:/usr/lib/kotlinc/bin +ENV PATH=$PATH:/usr/lib/kotlinc/bin COPY ./compile.sh /bin/compile.sh COPY ./run.sh /bin/run.sh diff --git a/containers/judge-worker/kotlin/compile.sh b/containers/judge-worker/kotlin/compile.sh new file mode 100644 index 0000000..2cde8b8 --- /dev/null +++ b/containers/judge-worker/kotlin/compile.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +kotlinc Main.kt -include-runtime -d Main.jar diff --git a/containers/kotlin/compile.sh b/containers/judge-worker/kotlin/run.sh similarity index 52% rename from containers/kotlin/compile.sh rename to containers/judge-worker/kotlin/run.sh index 5d117d2..290e60c 100644 --- a/containers/kotlin/compile.sh +++ b/containers/judge-worker/kotlin/run.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -kotlinc Main.kt \ No newline at end of file +java -jar Main.jar diff --git a/containers/judge-worker/mysql/Dockerfile b/containers/judge-worker/mysql/Dockerfile new file mode 100644 index 0000000..877a45d --- /dev/null +++ b/containers/judge-worker/mysql/Dockerfile @@ -0,0 +1,26 @@ +FROM codingblocks/judge-worker-base + +# Install bash, Node.js, and MySQL +RUN apk add --no-cache bash +RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.11/main/ nodejs=12.22.6-r0 npm=12.22.6-r0 +RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.11/main/ mysql=10.4.22-r0 mysql-client=10.4.22-r0 + +# Initialize MySQL data directory +RUN mkdir -p /run/mysqld && \ + chown -R mysql:mysql /run/mysqld && \ + mysql_install_db --user=mysql --datadir=/var/lib/mysql + +# so that mysql starts on port 3306 (default port) +# this line comments `skip-networking` line in the below file +# if we do not comment this `skip-networking`, mysql server will start on port 0 +RUN sed -i '/skip-networking/d' /etc/my.cnf.d/mariadb-server.cnf + +# Copy the custom script and make it executable +COPY ./compile.sh /bin/compile.sh +COPY ./pre-run /bin/pre-run +COPY ./run.sh /bin/run.sh + +RUN chmod 777 /bin/compile.sh; \ + chmod 777 /bin/run.sh + +RUN npm install --prefix /bin/pre-run diff --git a/containers/nodejs10/compile.sh b/containers/judge-worker/mysql/compile.sh similarity index 100% rename from containers/nodejs10/compile.sh rename to containers/judge-worker/mysql/compile.sh diff --git a/containers/judge-worker/mysql/pre-run/index.js b/containers/judge-worker/mysql/pre-run/index.js new file mode 100644 index 0000000..6857aa0 --- /dev/null +++ b/containers/judge-worker/mysql/pre-run/index.js @@ -0,0 +1,29 @@ +const mysql = require('mysql2/promise'); + +const TESTCASE = process.argv[2]; +const SOURCE = process.argv[3]; + +const init = async () => { + let connection; + try { + connection = await mysql.createConnection({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + database: process.env.DB_NAME, + password: process.env.DB_PASSWORD, + multipleStatements: true, + }) + + await connection.query(TESTCASE); + const [result] = await connection.query(SOURCE); + console.log(JSON.stringify(result)); + + } catch(err) { + console.error(err.sqlMessage ? err.sqlMessage: 'Something went wrong.') + } + if (connection) { + connection.destroy(); + } +} + +init(); \ No newline at end of file diff --git a/containers/judge-worker/mysql/pre-run/package-lock.json b/containers/judge-worker/mysql/pre-run/package-lock.json new file mode 100644 index 0000000..2beb674 --- /dev/null +++ b/containers/judge-worker/mysql/pre-run/package-lock.json @@ -0,0 +1,93 @@ +{ + "name": "pre-run", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==" + }, + "denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, + "long": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz", + "integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==" + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "lru.min": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.1.tgz", + "integrity": "sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==" + }, + "mysql2": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.12.0.tgz", + "integrity": "sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==", + "requires": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru.min": "^1.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + } + }, + "named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "requires": { + "lru-cache": "^7.14.1" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" + } + } +} diff --git a/containers/judge-worker/mysql/pre-run/package.json b/containers/judge-worker/mysql/pre-run/package.json new file mode 100644 index 0000000..59de493 --- /dev/null +++ b/containers/judge-worker/mysql/pre-run/package.json @@ -0,0 +1,15 @@ +{ + "name": "pre-run", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "mysql2": "^3.12.0" + } +} diff --git a/containers/judge-worker/mysql/run.sh b/containers/judge-worker/mysql/run.sh new file mode 100644 index 0000000..5d2ee7c --- /dev/null +++ b/containers/judge-worker/mysql/run.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# redirecting logs +mysqld --user=mysql > /var/log/mysql.log 2>&1 & + +# wait for mysql server to start +while ! mysqladmin ping --silent > /dev/null 2>&1; do + sleep 1 +done + +DB_NAME="mydatabase" +DB_USER="myuser" +DB_PASSWORD="mypassword" +DB_HOST="localhost" + +# setup database for the queries to execute +SETUP_DATABASE_COMMANDS=" +CREATE DATABASE IF NOT EXISTS $DB_NAME; +CREATE USER IF NOT EXISTS '$DB_USER'@'$DB_HOST' IDENTIFIED BY '$DB_PASSWORD'; +GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'$DB_HOST'; +FLUSH PRIVILEGES;" + +mysql -e "$SETUP_DATABASE_COMMANDS" + +# store the contents of testcase in the variable +TESTCASE=$(cat) +SOURCE=$( {rootDir}/setup.stdout 2> {rootDir}/setup.stderr', shell=True) + open(f'{rootDir}/setup.code', 'w').write(str(return_code)) + if return_code: + sys.exit(return_code) + +def runTestcases(rootDir, scripts, timeout): + os.mkdir(f'{rootDir}/result') + for i, script in enumerate(scripts): + os.mkdir(f'{rootDir}/result/{i}') + subprocess.call(f' \ + runguard \ + -t {timeout} \ + -E {rootDir}/result/{i}/run.code \ + -T {rootDir}/result/{i}/run.time \ + {script} 1> {rootDir}/result/{i}/run.stdout 2> {rootDir}/result/{i}/run.stderr \ + ', shell=True) + +def main(timeout): + rootDir = os.getcwd() + os.chdir('project') + + with open(f'{rootDir}/project.yml', 'r') as file: + config = yaml.full_load(file) + + beforeInstall(rootDir, config['project']['before-test']) + runTestcases(rootDir, config['project']['testcases'], timeout) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + parser.add_argument( + '-t', + '--timeout', + help='Timeout for the Code Run', + default=20 + ) + + args = parser.parse_args() + timeout = args.timeout + main(timeout) diff --git a/containers/project-worker/base/runguard/runguard-config.h b/containers/project-worker/base/runguard/runguard-config.h new file mode 100644 index 0000000..8da588c --- /dev/null +++ b/containers/project-worker/base/runguard/runguard-config.h @@ -0,0 +1,18 @@ +/* Runguard config for use with CodeRunner. Includes all necessary + * DOMJudge constants from config.h. + * Assumes all tests will be done as the Linux user "coderunner". + * It is assumed CHROOT will not be used so the CHROOT_PREFIX + * is not meaningfully set. + */ + +#ifndef _RUNGUARD_CONFIG_ +#define _RUNGUARD_CONFIG_ + +#define DOMJUDGE_VERSION "3" +#define REVISION "3.3" + +#define VALID_USERS "codingblocks,domjudge,jobe,jobe00,jobe01,jobe02,jobe03,jobe04,jobe05,jobe06,jobe07,jobe08,jobe09,jobe10,jobe11,jobe12,jobe13,jobe14,jobe15,jobe16,jobe17,jobe18,jobe19" + +#define CHROOT_PREFIX "/var/www/jobe/chrootjail" + +#endif /* _RUNGUARD_CONFIG_ */ diff --git a/containers/project-worker/base/runguard/runguard.c b/containers/project-worker/base/runguard/runguard.c new file mode 100644 index 0000000..1863e76 --- /dev/null +++ b/containers/project-worker/base/runguard/runguard.c @@ -0,0 +1,1054 @@ +/* + runguard -- run command with restrictions. + Copyright (C) 2004-2013 Jaap Eldering (eldering@a-eskwadraat.nl) + Copyright (C) 2013 Keith Johnson + + Multiple minor improvements ported from the DOMjudge-ETH tree. + + Based on an idea from the timeout program, written by Wietse Venema + as part of The Coroner's Toolkit. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + Program specifications: + + This program will run the specified command in a separate process + group (session) and apply the restrictions as specified after + forking, before executing the command. + + The stdin and stdout streams are passed to the command and runguard + does not read or write to these. Error and verbose messages from + runguard are by default written to stderr, hence mixed with stderr + output of the command, unless that is optionally redirected to file. + + The command and its children are sent a SIGTERM after the runtime + has passed, followed by a SIGKILL after 'killdelay'. + */ + +/* Some system/site specific config: VALID_USERS, CHROOT_PREFIX */ +#include "runguard-config.h" + +/* For chroot(), which is not POSIX. */ +#define _DEFAULT_SOURCE +/* For unshare(), only used when cgroups are enabled */ +#if ( USE_CGROUPS == 1 ) +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if ( USE_CGROUPS == 1 ) +#include +#include +#include +#else +#undef USE_CGROUPS +#endif + +#define PROGRAM "runguard" +#define VERSION DOMJUDGE_VERSION "/" REVISION +#define AUTHORS "Jaap Eldering" + +#define max(x,y) ((x) > (y) ? (x) : (y)) + +/* Array indices for input/output file descriptors as used by pipe() */ +#define PIPE_IN 1 +#define PIPE_OUT 0 + +#define BUF_SIZE 4*1024 +char buf[BUF_SIZE]; + +const struct timespec killdelay = { 0, 100000000L }; /* 0.1 seconds */ + +extern int errno; + +#ifndef _GNU_SOURCE +extern char **environ; +#endif + +const int exit_failure = -1; + +char *progname; +char *cmdname; +char **cmdargs; +char *rootdir; +char *stdoutfilename; +char *stderrfilename; +char *exitfilename; +char *timefilename; +#ifdef USE_CGROUPS +char *cgroupname; +const char *cpuset; +#endif + +int runuid; +int rungid; +int use_root; +int use_time; +int use_cputime; +int use_user; +int use_group; +int redir_stdout; +int redir_stderr; +int limit_streamsize; +int outputexit; +int outputtime; +int no_coredump; +int be_verbose; +int be_quiet; +int show_help; +int show_version; + +double runtime, cputime; /* in seconds */ +#ifdef USE_CGROUPS +int64_t memsize; +#else +rlim_t memsize; +#endif +rlim_t filesize; +rlim_t nproc; +size_t streamsize; + +pid_t child_pid; + +static volatile sig_atomic_t received_SIGCHLD = 0; + +FILE *child_stdout; +FILE *child_stderr; +int child_pipefd[3][2]; +int child_redirfd[3]; + +struct timeval starttime, endtime; +struct tms startticks, endticks; + +struct option const long_opts[] = { + {"root", required_argument, NULL, 'r'}, + {"user", required_argument, NULL, 'u'}, + {"group", required_argument, NULL, 'g'}, + {"time", required_argument, NULL, 't'}, + {"cputime", required_argument, NULL, 'C'}, + {"memsize", required_argument, NULL, 'm'}, + {"filesize", required_argument, NULL, 'f'}, + {"nproc", required_argument, NULL, 'p'}, + {"cpuset", required_argument, NULL, 'P'}, + {"no-core", no_argument, NULL, 'c'}, + {"stdout", required_argument, NULL, 'o'}, + {"stderr", required_argument, NULL, 'e'}, + {"streamsize", required_argument, NULL, 's'}, + {"outexit", required_argument, NULL, 'E'}, + {"outtime", required_argument, NULL, 'T'}, + {"verbose", no_argument, NULL, 'v'}, + {"quiet", no_argument, NULL, 'q'}, + {"help", no_argument, &show_help, 1 }, + {"version", no_argument, &show_version, 1 }, + { NULL, 0, NULL, 0 } +}; + +void warning( const char *, ...) __attribute__((format (printf, 1, 2))); +void verbose( const char *, ...) __attribute__((format (printf, 1, 2))); +void error(int, const char *, ...) __attribute__((format (printf, 2, 3))); + +void warning(const char *format, ...) +{ + va_list ap; + va_start(ap,format); + + if ( ! be_quiet ) { + fprintf(stderr,"%s: warning: ",progname); + vfprintf(stderr,format,ap); + fprintf(stderr,"\n"); + } + + va_end(ap); +} + +void verbose(const char *format, ...) +{ + va_list ap; + va_start(ap,format); + + if ( ! be_quiet && be_verbose ) { + fprintf(stderr,"%s: verbose: ",progname); + vfprintf(stderr,format,ap); + fprintf(stderr,"\n"); + } + + va_end(ap); +} + +void error(int errnum, const char *format, ...) +{ + va_list ap; + va_start(ap,format); + + fprintf(stderr,"%s",progname); + + if ( format!=NULL ) { + fprintf(stderr,": "); + vfprintf(stderr,format,ap); + } + if ( errnum!=0 ) { + fprintf(stderr,": %s",strerror(errnum)); + } + if ( format==NULL && errnum==0 ) { + fprintf(stderr,": unknown error"); + } + + fprintf(stderr,"\nTry `%s --help' for more information.\n",progname); + va_end(ap); + + exit(exit_failure); +} + +void version() +{ + printf("\ +%s -- version %s\n\ +Written by %s\n\n\ +%s comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n\ +are welcome to redistribute it under certain conditions. See the GNU\n\ +General Public Licence for details.\n",PROGRAM,VERSION,AUTHORS,PROGRAM); + exit(0); +} + +void usage() +{ + printf("\ +Usage: %s [OPTION]... COMMAND...\n\ +Run COMMAND with restrictions.\n\ +\n", progname); + printf("\ + -r, --root=ROOT run COMMAND with root directory set to ROOT\n\ + -u, --user=USER run COMMAND as user with username or ID USER\n\ + -g, --group=GROUP run COMMAND under group with name or ID GROUP\n\ + -t, --time=TIME kill COMMAND after TIME seconds (float)\n\ + -C, --cputime=TIME set maximum CPU time to TIME seconds (float)\n\ + -m, --memsize=SIZE set all (total, stack, etc) memory limits to SIZE kB\n\ + -f, --filesize=SIZE set maximum created filesize to SIZE kB;\n"); + printf("\ + -p, --nproc=N set maximum no. processes to N\n\ + -P, --cpuset=ID use only processor number ID\n\ + -c, --no-core disable core dumps\n\ + -o, --stdout=FILE redirect COMMAND stdout output to FILE\n\ + -e, --stderr=FILE redirect COMMAND stderr output to FILE\n\ + -s, --streamsize=SIZE truncate COMMAND stdout/stderr streams at SIZE kB\n\ + -E, --outexit=FILE write COMMAND exitcode to FILE\n\ + -T, --outtime=FILE write COMMAND runtime to FILE\n"); + printf("\ + -v, --verbose display some extra warnings and information\n\ + -q, --quiet suppress all warnings and verbose output\n\ + --help display this help and exit\n\ + --version output version information and exit\n"); + printf("\n\ +Note that root privileges are needed for the `root' and `user' options.\n\ +The COMMAND path is relative to the changed ROOT directory if specified.\n\ +When run setuid without the `user' option, the user ID is set to the\n\ +real user ID.\n"); + exit(0); +} + +void output_exit_time(int exitcode, double timediff) +{ + FILE *outputfile; + double userdiff, sysdiff; + unsigned long ticks_per_second = sysconf(_SC_CLK_TCK); + + verbose("command exited with exitcode %d",exitcode); + + if ( outputexit ) { + verbose("writing exitcode to file `%s'",exitfilename); + + if ( (outputfile = fopen(exitfilename,"w"))==NULL ) { + error(errno,"cannot open `%s'",exitfilename); + } + if ( fprintf(outputfile,"%d\n",exitcode)==0 ) { + error(0,"cannot write to file `%s'",exitfilename); + } + if ( fclose(outputfile) ) { + error(errno,"closing file `%s'",exitfilename); + } + } + + userdiff = (double)(endticks.tms_cutime - startticks.tms_cutime) / ticks_per_second; + sysdiff = (double)(endticks.tms_cstime - startticks.tms_cstime) / ticks_per_second; + + verbose("runtime is %.3f seconds real, %.3f user, %.3f sys", + timediff, userdiff, sysdiff); + + if ( use_cputime && (userdiff+sysdiff) > cputime ) { + warning("timelimit exceeded (cpu time)"); + } + + if ( outputtime ) { + verbose("writing runtime to file `%s'",timefilename); + + if ( (outputfile = fopen(timefilename,"w"))==NULL ) { + error(errno,"cannot open `%s'",timefilename); + } + if ( fprintf(outputfile,"%.3f\n",userdiff+sysdiff)==0 ) { + error(0,"cannot write to file `%s'",timefilename); + } + if ( fclose(outputfile) ) { + error(errno,"closing file `%s'",timefilename); + } + } +} + +#ifdef USE_CGROUPS +void output_cgroup_stats() +{ + int ret; + int64_t max_usage; + struct cgroup *cg; + struct cgroup_controller *cg_controller; + + cg = cgroup_new_cgroup(cgroupname); + if (!cg) { + error(0,"cgroup_new_cgroup"); + } + if ((ret = cgroup_get_cgroup(cg)) != 0) { + error(0,"get cgroup information: %s(%d)", cgroup_strerror(ret), ret); + } + cg_controller = cgroup_get_controller(cg, "memory"); + ret = cgroup_get_value_int64(cg_controller, "memory.memsw.max_usage_in_bytes", &max_usage); + if ( ret!=0 ) { + error(0,"get cgroup value: %s(%d)", cgroup_strerror(ret), ret); + } + + verbose("total memory used: %" PRId64 " kB", max_usage/1024); + + cgroup_free(&cg); +} + +void cgroup_create() +{ + int ret; + struct cgroup *cg; + struct cgroup_controller *cg_controller; + + cg = cgroup_new_cgroup(cgroupname); + if (!cg) { + error(0,"cgroup_new_cgroup"); + } + + /* Set up the memory restrictions; these two options limit ram use + and ram+swap use. They are the same so no swapping can occur */ + cg_controller = cgroup_add_controller(cg, "memory"); + cgroup_add_value_int64(cg_controller, "memory.limit_in_bytes", memsize); + cgroup_add_value_int64(cg_controller, "memory.memsw.limit_in_bytes", memsize); + + /* Set up cpu restrictions; we pin the task to a specific set of + cpus. We also give it exclusive access to those cores, and set + no limits on memory nodes */ + if ( cpuset!=NULL && strlen(cpuset)>0 ) { + cg_controller = cgroup_add_controller(cg, "cpuset"); + /* To make a cpuset exclusive, some additional setup outside of domjudge is + required, so for now, we will leave this commented out. */ + /* cgroup_add_value_int64(cg_controller, "cpuset.cpu_exclusive", 1); */ + cgroup_add_value_string(cg_controller, "cpuset.mems", "0"); + cgroup_add_value_string(cg_controller, "cpuset.cpus", cpuset); + } else { + verbose("cpuset undefined"); + } + + /* Perform the actual creation of the cgroup */ + ret = cgroup_create_cgroup(cg, 1); + if ( ret!=0 ) { + error(0,"creating cgroup: %s(%d)", cgroup_strerror(ret), ret); + } + + cgroup_free(&cg); +} + +void cgroup_attach() +{ + int ret; + struct cgroup *cg; + + cg = cgroup_new_cgroup(cgroupname); + if (!cg) { + error(0,"cgroup_new_cgroup"); + } + ret = cgroup_get_cgroup(cg); + if ( ret!=0 ) { + error(0,"get cgroup information: %s(%d)", cgroup_strerror(ret), ret); + } + + /* Attach task to the cgroup */ + ret = cgroup_attach_task(cg); + if ( ret!=0 ) { + error(0,"attach task to cgroup: %s(%d)", cgroup_strerror(ret), ret); + } + + cgroup_free(&cg); +} + +void cgroup_delete() +{ + int ret; + struct cgroup *cg; + + cg = cgroup_new_cgroup(cgroupname); + if (!cg) { + error(0,"cgroup_new_cgroup"); + } + ret = cgroup_get_cgroup(cg); + if ( ret!=0 ) { + error(0,"get cgroup information: %s(%d)", cgroup_strerror(ret), ret); + } + /* Clean up our cgroup */ + ret = cgroup_delete_cgroup(cg, 1); + if ( ret!=0 ) { + error(0,"deleting cgroup: %s(%d)", cgroup_strerror(ret), ret); + } + cgroup_free(&cg); +} +#endif // USE_CGROUPS + +void terminate(int sig) +{ + struct sigaction sigact; + + /* Reset signal handlers to default */ + sigact.sa_handler = SIG_DFL; + sigact.sa_flags = 0; + if ( sigemptyset(&sigact.sa_mask)!=0 ) { + warning("could not initialize signal mask"); + } + if ( sigaction(SIGTERM,&sigact,NULL)!=0 ) { + warning("could not restore signal handler"); + } + if ( sigaction(SIGALRM,&sigact,NULL)!=0 ) { + warning("could not restore signal handler"); + } + + if ( sig==SIGALRM ) { + warning("timelimit exceeded (wall time): aborting command"); + } else { + warning("received signal %d: aborting command",sig); + } + + /* First try to kill graciously, then hard */ + verbose("sending SIGTERM"); + if ( kill(-child_pid,SIGTERM)!=0 ) error(errno,"sending SIGTERM to command"); + + /* Prefer nanosleep over sleep because of higher resolution and + it does not interfere with signals. */ + nanosleep(&killdelay,NULL); + + verbose("sending SIGKILL"); + if ( kill(-child_pid,SIGKILL)!=0 ) error(errno,"sending SIGKILL to command"); + + /* Wait another while to make sure the process is killed by now. */ + nanosleep(&killdelay,NULL); +} + +static void child_handler(int sig) +{ + received_SIGCHLD = 1; +} + +int userid(char *name) +{ + struct passwd *pwd; + + errno = 0; /* per the linux GETPWNAM(3) man-page */ + pwd = getpwnam(name); + + if ( pwd==NULL || errno ) return -1; + + return (int) pwd->pw_uid; +} + +int groupid(char *name) +{ + struct group *grp; + + errno = 0; /* per the linux GETGRNAM(3) man-page */ + grp = getgrnam(name); + + if ( grp==NULL || errno ) return -1; + + return (int) grp->gr_gid; +} + +long readoptarg(const char *desc, long minval, long maxval) +{ + long arg; + char *ptr; + + arg = strtol(optarg,&ptr,10); + if ( errno || *ptr!='\0' || argmaxval ) { + error(errno,"invalid %s specified: `%s'",desc,optarg); + } + + return arg; +} + +void setrestrictions() +{ + char* savedEnvironmentVariables[] = {"PATH", "LANG", "LC_ALL", "LC_COLLATE", + "LC_CTYPE", "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME"}; + char* savedValues[sizeof(savedEnvironmentVariables) / sizeof(char*)]; + int numSavedVariables = sizeof(savedEnvironmentVariables) / sizeof(char*); + char cwd[PATH_MAX+1]; + char* path = NULL; + int i; + + struct rlimit lim; + + /* Clear environment to prevent all kinds of security holes, save PATH */ + /* RJL: Changed to save and restore all standard locale variables */ + //path = getenv("PATH"); + for (i = 0; i < numSavedVariables; i++) { + savedValues[i] = getenv(savedEnvironmentVariables[i]); + } + environ[0] = NULL; + /* FIXME: Clean path before setting it again? */ + //if ( path!=NULL ) setenv("PATH",path,1); + for (i = 0; i < numSavedVariables; i++) { + if (savedValues[i] != NULL) { + setenv(savedEnvironmentVariables[i], savedValues[i], 1); + } + } + + /* Set resource limits: must be root to raise hard limits. + Note that limits can thus be raised from the systems defaults! */ + + /* First define shorthand macro function */ +#define setlim(type) \ + if ( setrlimit(RLIMIT_ ## type, &lim)!=0 ) { \ + if ( errno==EPERM ) { \ + warning("no permission to set resource RLIMIT_" #type); \ + } else { \ + error(errno,"setting resource RLIMIT_" #type); \ + } \ + } + + if ( use_cputime ) { + rlim_t cputime_limit = (rlim_t)cputime + 1; + verbose("setting CPU-time limit to %d seconds",(int)cputime_limit); + lim.rlim_cur = lim.rlim_max = cputime_limit; + setlim(CPU); + } + + /* Memory limits may be handled by cgroups now */ +#ifndef USE_CGROUPS + if ( memsize!=RLIM_INFINITY ) { + verbose("setting memory limits to %d bytes",(int)memsize); + lim.rlim_cur = lim.rlim_max = memsize; + setlim(AS); + /* Commented out the next 2 lines - they cause problems + for multithreaded applications and don't add much + security. + setlim(DATA); + setlim(STACK);*/ + } +#else + /* Memory limits should be unlimited when using cgroups */ + lim.rlim_cur = lim.rlim_max = RLIM_INFINITY; + setlim(AS); + setlim(DATA); + setlim(STACK); +#endif + + if ( filesize!=RLIM_INFINITY ) { + verbose("setting filesize limit to %d bytes",(int)filesize); + lim.rlim_cur = lim.rlim_max = filesize; + setlim(FSIZE); + } + + if ( nproc!=RLIM_INFINITY ) { + verbose("setting process limit to %d",(int)nproc); + lim.rlim_cur = lim.rlim_max = nproc; + setlim(NPROC); + } + +#undef setlim + + if ( no_coredump ) { + verbose("disabling core dumps"); + lim.rlim_cur = lim.rlim_max = 0; + if ( setrlimit(RLIMIT_CORE,&lim)!=0 ) error(errno,"disabling core dumps"); + } + + /* Set root-directory and change directory to there. */ + if ( use_root ) { + /* Small security issue: when running setuid-root, people can find + out which directories exist from error message. */ + if ( chdir(rootdir)!=0 ) error(errno,"cannot chdir to `%s'",rootdir); + + /* Get absolute pathname of rootdir, by reading it. */ + if ( getcwd(cwd,PATH_MAX)==NULL ) error(errno,"cannot get directory"); + if ( cwd[strlen(cwd)-1]!='/' ) strcat(cwd,"/"); + + /* Canonicalize CHROOT_PREFIX. */ + if ( (path = (char *) malloc(PATH_MAX+1))==NULL ) { + error(errno,"allocating memory"); + } + if ( realpath(CHROOT_PREFIX,path)==NULL ) { + error(errno,"cannot canonicalize path '%s'",CHROOT_PREFIX); + } + + /* Check that we are within prescribed path. */ + if ( strncmp(cwd,path,strlen(path))!=0 ) { + error(0,"invalid root: must be within `%s'",path); + } + free(path); + + if ( chroot(".")!=0 ) error(errno,"cannot change root to `%s'",cwd); + /* Just to make sure and satisfy Coverity scan: */ + if ( chdir("/")!=0 ) error(errno,"cannot chdir to `/' in chroot"); + verbose("using root-directory `%s'",cwd); + } + + /* Set group-id (must be root for this, so before setting user). */ + if ( use_group ) { + if ( setgid(rungid) ) error(errno,"cannot set group ID to `%d'",rungid); + verbose("using group ID `%d'",rungid); + gid_t aux_groups[] = {rungid}; + if (setgroups(1, aux_groups)) error(errno, "cannot clear auxiliary groups"); + } + /* Set user-id (must be root for this). */ + if ( use_user ) { + if ( setuid(runuid) ) error(errno,"cannot set user ID to `%d'",runuid); + verbose("using user ID `%d' for command",runuid); + } else { + /* Permanently reset effective uid to real uid, to prevent + child command from having root privileges. + Note that this means that the child runs as the same user + as the watchdog process and can thus manipulate it, e.g. by + sending SIGSTOP/SIGCONT! */ + if ( setuid(getuid()) ) error(errno,"cannot reset real user ID"); + verbose("reset user ID to `%d' for command",getuid()); + } + + // if ( geteuid()==0 || getuid()==0 ) error(0,"root privileges not dropped. Do not run judgedaemon as root."); +} + +int main(int argc, char **argv) +{ + sigset_t sigmask, emptymask; + fd_set readfds; + pid_t pid; + int i, r, nfds; +#ifdef USE_CGROUPS + int ret; +#endif + int status; + int exitcode; + char *valid_users; + char *ptr; + int opt; + double timediff, tmpd; + size_t data_passed[3]; + ssize_t nread, nwritten; + + struct itimerval itimer; + struct sigaction sigact; + + progname = argv[0]; + + /* Parse command-line options */ + use_root = use_time = use_cputime = use_user = outputexit = outputtime = no_coredump = 0; + memsize = filesize = nproc = RLIM_INFINITY; + redir_stdout = redir_stderr = limit_streamsize = 0; + be_verbose = be_quiet = 0; + show_help = show_version = 0; + opterr = 0; + while ( (opt = getopt_long(argc,argv,"+r:u:g:t:C:m:f:p:P:c:o:e:s:E:T:v:q",long_opts,(int *) 0))!=-1 ) { + switch ( opt ) { + case 0: /* long-only option */ + break; + case 'r': /* rootdir option */ + use_root = 1; + rootdir = (char *) malloc(strlen(optarg)+2); + strcpy(rootdir,optarg); + break; + case 'u': /* user option: uid or string */ + use_user = 1; + runuid = strtol(optarg,&ptr,10); + if ( errno || *ptr!='\0' ) runuid = userid(optarg); + if ( runuid<0 ) error(0,"invalid username or ID specified: `%s'",optarg); + break; + case 'g': /* group option: gid or string */ + use_group = 1; + rungid = strtol(optarg,&ptr,10); + if ( errno || *ptr!='\0' ) rungid = groupid(optarg); + if ( rungid<0 ) error(0,"invalid groupname or ID specified: `%s'",optarg); + break; + case 't': /* time option */ + use_time = 1; + runtime = strtod(optarg,&ptr); + if ( errno || *ptr!='\0' || !finite(runtime) || runtime<=0 ) { + error(errno,"invalid runtime specified: `%s'",optarg); + } + break; + case 'C': /* CPU time option */ + use_cputime = 1; + cputime = strtod(optarg,&ptr); + if ( errno || *ptr!='\0' || !finite(cputime) || cputime<=0 ) { + error(errno,"invalid cputime specified: `%s'",optarg); + } + break; + case 'm': /* memsize option */ + memsize = (rlim_t) readoptarg("memory limit",1,LONG_MAX); + /* Convert limit from kB to bytes and check for overflow */ + if ( memsize!=(memsize*1024)/1024 ) { + memsize = RLIM_INFINITY; + } else { + memsize *= 1024; + } + break; + case 'f': /* filesize option */ + filesize = (rlim_t) readoptarg("filesize limit",1,LONG_MAX); + /* Convert limit from kB to bytes and check for overflow */ + if ( filesize!=(filesize*1024)/1024 ) { + filesize = RLIM_INFINITY; + } else { + filesize *= 1024; + } + break; + case 'p': /* nproc option */ + nproc = (rlim_t) readoptarg("process limit",1,LONG_MAX); + break; + case 'P': /* cpuset option */ + #ifdef USE_CGROUPS + cpuset = optarg; + #else + error(0,"option `-P' is only supported when compiled with cgroup support."); + #endif + break; + case 'c': /* no-core option */ + no_coredump = 1; + break; + case 'o': /* stdout option */ + redir_stdout = 1; + stdoutfilename = strdup(optarg); + break; + case 'e': /* stderr option */ + redir_stderr = 1; + stderrfilename = strdup(optarg); + break; + case 's': /* streamsize option */ + limit_streamsize = 1; + streamsize = (size_t) readoptarg("streamsize limit",0,LONG_MAX); + /* Convert limit from kB to bytes and check for overflow */ + if ( streamsize!=(streamsize*1024)/1024 ) { + streamsize = (size_t) LONG_MAX; + } else { + streamsize *= 1024; + } + break; + case 'E': /* outputexit option */ + outputexit = 1; + exitfilename = strdup(optarg); + break; + case 'T': /* outputtime option */ + outputtime = 1; + timefilename = strdup(optarg); + break; + case 'v': /* verbose option */ + be_verbose = 1; + break; + case 'q': /* quiet option */ + be_quiet = 1; + break; + case ':': /* getopt error */ + case '?': + error(0,"unknown option or missing argument `%c'",optopt); + break; + default: + error(0,"getopt returned character code `%c' ??",(char)opt); + } + } + + if ( show_help ) usage(); + if ( show_version ) version(); + + if ( argc<=optind ) error(0,"no command specified"); + + /* Command to be executed */ + cmdname = argv[optind]; + cmdargs = argv+optind; + + /* Check that new uid is in list of valid uid's. + This must be done before chroot for /etc/passwd lookup. */ + if ( use_user ) { + valid_users = strdup(VALID_USERS); + for(ptr=strtok(valid_users,","); ptr!=NULL; ptr=strtok(NULL,",")) { + if ( runuid==userid(ptr) ) break; + } + if ( ptr==NULL || runuid<=0 ) error(0,"illegal user specified: %d",runuid); + } + + /* Setup pipes connecting to child stdout/err streams (ignore stdin). */ + for(i=1; i<=2; i++) { + if ( pipe(child_pipefd[i])!=0 ) error(errno,"creating pipe for fd %d",i); + } + + if ( sigemptyset(&emptymask)!=0 ) error(errno,"creating empty signal mask"); + + /* unmask all signals, except SIGCHLD: detected in pselect() below */ + sigmask = emptymask; + if ( sigaddset(&sigmask, SIGCHLD)!=0 ) error(errno,"setting signal mask"); + if ( sigprocmask(SIG_SETMASK, &sigmask, NULL)!=0 ) { + error(errno,"unmasking signals"); + } + + /* Construct signal handler for SIGCHLD detection in pselect(). */ + received_SIGCHLD = 0; + sigact.sa_handler = child_handler; + sigact.sa_flags = 0; + sigact.sa_mask = emptymask; + if ( sigaction(SIGCHLD,&sigact,NULL)!=0 ) { + error(errno,"installing signal handler"); + } + +#ifdef USE_CGROUPS + /* Make libcgroup ready for use */ + ret = cgroup_init(); + if ( ret!=0 ) { + error(0,"libcgroup initialization failed: %s(%d)\n", cgroup_strerror(ret), ret); + } + /* Define the cgroup name that we will use */ + cgroupname = (char*)malloc(256); + if ( cgroupname==NULL ) { + error(errno,"allocating memory for cgroupname"); + } + /* Note: group names must have slashes! */ + snprintf(cgroupname, 256, "/domjudge/dj_cgroup_%d/", getpid()); + + cgroup_create(); + + unshare(CLONE_FILES|CLONE_FS|CLONE_NEWIPC|CLONE_NEWNET|CLONE_NEWNS|CLONE_NEWUTS|CLONE_SYSVSEM); +#endif + switch ( child_pid = fork() ) { + case -1: /* error */ + error(errno,"cannot fork"); + case 0: /* run controlled command */ + /* Connect pipes to command (stdin/)stdout/stderr and close unneeded fd's */ + for(i=1; i<=2; i++) { + if ( dup2(child_pipefd[i][PIPE_IN],i)<0 ) { + error(errno,"redirecting child fd %d",i); + } + if ( close(child_pipefd[i][PIPE_IN] )!=0 || + close(child_pipefd[i][PIPE_OUT])!=0 ) { + error(errno,"closing pipe for fd %d",i); + } + } + + /* Run the command in a separate process group so that the command + and all its children can be killed off with one signal. */ + if ( setsid()==-1 ) error(errno,"setsid failed"); + +#ifdef USE_CGROUPS + /* Put the child process in the cgroup */ + cgroup_attach(); +#endif + + /* Apply all restrictions for child process. */ + setrestrictions(); + + /* And execute child command. */ + execvp(cmdname,cmdargs); + error(errno,"cannot start `%s'",cmdname); + + default: /* become watchdog */ + /* Shed privileges, only if not using a separate child uid, + because in that case we may need root privileges to kill + the child process. Do not use Linux specific setresuid() + call with saved set-user-ID. */ + if ( !use_user ) { + if ( setuid(getuid())!=0 ) error(errno, "setting watchdog uid"); + verbose("watchdog using user ID `%d'",getuid()); + } + + if ( gettimeofday(&starttime,NULL) ) error(errno,"getting time"); + + /* Close unused file descriptors */ + for(i=1; i<=2; i++) { + if ( close(child_pipefd[i][PIPE_IN])!=0 ) { + error(errno,"closing pipe for fd %i",i); + } + } + + /* Redirect child stdout/stderr to file */ + for(i=1; i<=2; i++) { + child_redirfd[i] = i; /* Default: no redirects */ + data_passed[i] = 0; /* Reset data counters */ + } + if ( redir_stdout ) { + child_redirfd[STDOUT_FILENO] = creat(stdoutfilename, S_IRUSR | S_IWUSR); + if ( child_redirfd[STDOUT_FILENO]<0 ) { + error(errno,"opening file '%s'",stdoutfilename); + } + } + if ( redir_stderr ) { + child_redirfd[STDERR_FILENO] = creat(stderrfilename, S_IRUSR | S_IWUSR); + if ( child_redirfd[STDERR_FILENO]<0 ) { + error(errno,"opening file '%s'",stderrfilename); + } + } + + if ( sigemptyset(&emptymask)!=0 ) error(errno,"creating empty signal mask"); + + /* Construct one-time signal handler to terminate() for TERM + and ALRM signals. */ + sigmask = emptymask; + if ( sigaddset(&sigmask,SIGALRM)!=0 || + sigaddset(&sigmask,SIGTERM)!=0 ) error(errno,"setting signal mask"); + + sigact.sa_handler = terminate; + sigact.sa_flags = SA_RESETHAND | SA_RESTART; + sigact.sa_mask = sigmask; + + /* Kill child command when we receive SIGTERM */ + if ( sigaction(SIGTERM,&sigact,NULL)!=0 ) { + error(errno,"installing signal handler"); + } + + if ( use_time ) { + /* Kill child when we receive SIGALRM */ + if ( sigaction(SIGALRM,&sigact,NULL)!=0 ) { + error(errno,"installing signal handler"); + } + + /* Trigger SIGALRM via setitimer: */ + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_usec = 0; + itimer.it_value.tv_sec = (int) runtime; + itimer.it_value.tv_usec = (int)(modf(runtime,&tmpd) * 1E6); + + if ( setitimer(ITIMER_REAL,&itimer,NULL)!=0 ) { + error(errno,"setting timer"); + } + verbose("using timelimit of %.3f seconds",runtime); + } + + if ( times(&startticks)==(clock_t) -1 ) { + error(errno,"getting start clock ticks"); + } + + /* Wait for child data or exit. */ + while ( 1 ) { + + FD_ZERO(&readfds); + nfds = -1; + for(i=1; i<=2; i++) { + if ( child_pipefd[i][PIPE_OUT]>=0 ) { + FD_SET(child_pipefd[i][PIPE_OUT],&readfds); + nfds = max(nfds,child_pipefd[i][PIPE_OUT]); + } + } + + r = pselect(nfds+1, &readfds, NULL, NULL, NULL, &emptymask); + if ( r==-1 && errno!=EINTR ) error(errno,"waiting for child data"); + + if ( received_SIGCHLD ) { + if ( (pid = wait(&status))<0 ) error(errno,"waiting on child"); + if ( pid==child_pid ) break; + } + + /* Check to see if data is available and pass it on */ + for(i=1; i<=2; i++) { + if ( child_pipefd[i][PIPE_OUT] != -1 && FD_ISSET(child_pipefd[i][PIPE_OUT],&readfds) ) { + nread = read(child_pipefd[i][PIPE_OUT], buf, BUF_SIZE); + if ( nread==-1 ) error(errno,"reading child fd %d",i); + if ( nread==0 ) { + /* EOF detected: close fd and indicate this with -1 */ + if ( close(child_pipefd[i][PIPE_OUT])!=0 ) { + error(errno,"closing pipe for fd %d",i); + } + child_pipefd[i][PIPE_OUT] = -1; + continue; + } + if ( limit_streamsize && data_passed[i]+nread>=streamsize ) { + if ( data_passed[i]) { val enterValue = readLine() println("Hello $enterValue") -} \ No newline at end of file +} diff --git a/tests/perl/run.stdin b/tests/judge-worker/kotlin/run.stdin similarity index 100% rename from tests/perl/run.stdin rename to tests/judge-worker/kotlin/run.stdin diff --git a/tests/kotlin/run.stdin b/tests/judge-worker/nodejs10/run.stdin similarity index 100% rename from tests/kotlin/run.stdin rename to tests/judge-worker/nodejs10/run.stdin diff --git a/tests/nodejs10/script.js b/tests/judge-worker/nodejs10/script.js similarity index 100% rename from tests/nodejs10/script.js rename to tests/judge-worker/nodejs10/script.js diff --git a/tests/nodejs10/run.stdin b/tests/judge-worker/nodejs12/run.stdin similarity index 100% rename from tests/nodejs10/run.stdin rename to tests/judge-worker/nodejs12/run.stdin diff --git a/tests/nodejs8/script.js b/tests/judge-worker/nodejs12/script.js similarity index 100% rename from tests/nodejs8/script.js rename to tests/judge-worker/nodejs12/script.js diff --git a/tests/rust/run.stdin b/tests/judge-worker/perl/run.stdin similarity index 100% rename from tests/rust/run.stdin rename to tests/judge-worker/perl/run.stdin diff --git a/tests/perl/script.pl b/tests/judge-worker/perl/script.pl similarity index 100% rename from tests/perl/script.pl rename to tests/judge-worker/perl/script.pl diff --git a/tests/nodejs8/run.stdin b/tests/judge-worker/py2/run.stdin similarity index 100% rename from tests/nodejs8/run.stdin rename to tests/judge-worker/py2/run.stdin diff --git a/tests/py2/script.py b/tests/judge-worker/py2/script.py similarity index 100% rename from tests/py2/script.py rename to tests/judge-worker/py2/script.py diff --git a/tests/py2/run.stdin b/tests/judge-worker/py3/run.stdin similarity index 100% rename from tests/py2/run.stdin rename to tests/judge-worker/py3/run.stdin diff --git a/tests/py3/script.py b/tests/judge-worker/py3/script.py similarity index 100% rename from tests/py3/script.py rename to tests/judge-worker/py3/script.py diff --git a/tests/py3/run.stdin b/tests/judge-worker/ruby/run.stdin similarity index 100% rename from tests/py3/run.stdin rename to tests/judge-worker/ruby/run.stdin diff --git a/tests/ruby/script.rb b/tests/judge-worker/ruby/script.rb similarity index 100% rename from tests/ruby/script.rb rename to tests/judge-worker/ruby/script.rb diff --git a/tests/judge-worker/rust/run.stdin b/tests/judge-worker/rust/run.stdin new file mode 100644 index 0000000..216e97c --- /dev/null +++ b/tests/judge-worker/rust/run.stdin @@ -0,0 +1 @@ +World diff --git a/tests/rust/script.rs b/tests/judge-worker/rust/script.rs similarity index 100% rename from tests/rust/script.rs rename to tests/judge-worker/rust/script.rs diff --git a/tests/test_workers.sh b/tests/judge-worker/test_workers.sh similarity index 96% rename from tests/test_workers.sh rename to tests/judge-worker/test_workers.sh index 2a08394..2e65ba0 100755 --- a/tests/test_workers.sh +++ b/tests/judge-worker/test_workers.sh @@ -14,7 +14,7 @@ cp $DIR/$LANGUAGE/* $RUNBOX/ # Test Compile docker run \ --cpus="1" \ - --memory="100m" \ + --memory="500m" \ --ulimit nofile=64:64 \ --rm \ -v "$RUNBOX":/usr/src/runbox \ diff --git a/tests/project-worker/nodejs/project.yml b/tests/project-worker/nodejs/project.yml new file mode 100644 index 0000000..440b5cb --- /dev/null +++ b/tests/project-worker/nodejs/project.yml @@ -0,0 +1,8 @@ +project: + allowed-folders: + - src/ + before-test: + - yarn install + - yarn build + testcases: + - yarn test \ No newline at end of file diff --git a/tests/project-worker/nodejs/project/.gitignore b/tests/project-worker/nodejs/project/.gitignore new file mode 100644 index 0000000..fc9ce49 --- /dev/null +++ b/tests/project-worker/nodejs/project/.gitignore @@ -0,0 +1,82 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +#DynamoDB Local files +.dynamodb/ + +# MAC OS +.DS_Store diff --git a/tests/project-worker/nodejs/project/package.json b/tests/project-worker/nodejs/project/package.json new file mode 100644 index 0000000..e3a8868 --- /dev/null +++ b/tests/project-worker/nodejs/project/package.json @@ -0,0 +1,21 @@ +{ + "name": "nodejs-test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node src/index.js", + "build": "return 0", + "test": "mocha --exit test/*.spec.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "express": "^4.17.1" + }, + "devDependencies": { + "chai": "^4.2.0", + "chai-http": "^4.3.0", + "mocha": "^7.1.1" + } +} diff --git a/tests/project-worker/nodejs/project/src/index.js b/tests/project-worker/nodejs/project/src/index.js new file mode 100644 index 0000000..31cb637 --- /dev/null +++ b/tests/project-worker/nodejs/project/src/index.js @@ -0,0 +1,13 @@ +const express = require('express') + +const app = express() + +app.get('/users', (req, res) => { + // TODO: + res.json([{ name: 'jatin' }]) +}) + +app.listen(3000, () => console.log('App running')) + +module.exports = app + diff --git a/tests/project-worker/nodejs/project/test/user.spec.js b/tests/project-worker/nodejs/project/test/user.spec.js new file mode 100644 index 0000000..256df1b --- /dev/null +++ b/tests/project-worker/nodejs/project/test/user.spec.js @@ -0,0 +1,21 @@ +process.env.NODE_ENV = 'test'; + +const chai = require('chai'); +const chaiHttp = require('chai-http'); +const server = require('../src/index.js'); +const {expect} = chai + +chai.use(chaiHttp); + +describe('users', () => { + it('should get all Users', async () => { + const res = await chai + .request(server) + .get('/users') + + expect(res.status).to.be.equal(200) + expect(res.body).to.be.a('array') + expect(res.body.length).to.be.equal(1) + }) +}) + diff --git a/tests/project-worker/nodejs/project/yarn.lock b/tests/project-worker/nodejs/project/yarn.lock new file mode 100644 index 0000000..b91ea60 --- /dev/null +++ b/tests/project-worker/nodejs/project/yarn.lock @@ -0,0 +1,1270 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/chai@4": + version "4.2.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.11.tgz#d3614d6c5f500142358e6ed24e1bf16657536c50" + integrity sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw== + +"@types/cookiejar@*": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" + integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw== + +"@types/node@*": + version "13.13.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.2.tgz#160d82623610db590a64e8ca81784e11117e5a54" + integrity sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A== + +"@types/superagent@^3.8.3": + version "3.8.7" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-3.8.7.tgz#1f1ed44634d5459b3a672eb7235a8e7cfd97704c" + integrity sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +chai-http@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/chai-http/-/chai-http-4.3.0.tgz#3c37c675c1f4fe685185a307e345de7599337c1a" + integrity sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg== + dependencies: + "@types/chai" "4" + "@types/superagent" "^3.8.3" + cookiejar "^2.1.1" + is-ip "^2.0.0" + methods "^1.1.2" + qs "^6.5.1" + superagent "^3.7.0" + +chai@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" + integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" + get-func-name "^2.0.0" + pathval "^1.1.0" + type-detect "^4.0.5" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= + +chokidar@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" + integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.2.0" + optionalDependencies: + fsevents "~2.1.1" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +combined-stream@^1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +component-emitter@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +cookiejar@^2.1.0, cookiejar@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.2.6, debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +deep-eql@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== + dependencies: + type-detect "^4.0.0" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +diff@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: + version "1.17.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" + integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" + integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== + dependencies: + is-buffer "~2.0.3" + +form-data@^2.3.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +formidable@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" + integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" + integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= + +glob-parent@~5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + +glob@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ip-regex@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-buffer@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" + integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== + +is-callable@^1.1.4, is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-2.0.0.tgz#68eea07e8a0a0a94c2d080dd674c731ab2a461ab" + integrity sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas= + dependencies: + ip-regex "^2.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== + dependencies: + has "^1.0.3" + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-yaml@3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash@^4.17.15: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +log-symbols@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" + integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== + dependencies: + chalk "^2.4.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +mime-db@1.43.0: + version "1.43.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" + integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== + +mime-types@^2.1.12, mime-types@~2.1.24: + version "2.1.26" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" + integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== + dependencies: + mime-db "1.43.0" + +mime@1.6.0, mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.3.tgz#5a514b7179259287952881e94410ec5465659f8c" + integrity sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg== + dependencies: + minimist "^1.2.5" + +mocha@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.1.1.tgz#89fbb30d09429845b1bb893a830bf5771049a441" + integrity sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA== + dependencies: + ansi-colors "3.2.3" + browser-stdout "1.3.1" + chokidar "3.3.0" + debug "3.2.6" + diff "3.5.0" + escape-string-regexp "1.0.5" + find-up "3.0.0" + glob "7.1.3" + growl "1.10.5" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "3.0.0" + minimatch "3.0.4" + mkdirp "0.5.3" + ms "2.1.1" + node-environment-flags "1.0.6" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.3.2" + yargs-parser "13.1.2" + yargs-unparser "1.6.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +node-environment-flags@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" + integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw== + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +object-inspect@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@4.1.0, object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +pathval@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= + +picomatch@^2.0.4: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +qs@^6.5.1: + version "6.9.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e" + integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw== + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^2.3.5: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" + integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== + dependencies: + picomatch "^2.0.4" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.trimend@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trimleft@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" + integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + string.prototype.trimstart "^1.0.0" + +string.prototype.trimright@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" + integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + string.prototype.trimend "^1.0.0" + +string.prototype.trimstart@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-json-comments@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +superagent@^3.7.0: + version "3.8.3" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" + integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== + dependencies: + component-emitter "^1.2.0" + cookiejar "^2.1.0" + debug "^3.1.0" + extend "^3.0.0" + form-data "^2.3.1" + formidable "^1.2.0" + methods "^1.1.1" + mime "^1.4.1" + qs "^6.5.1" + readable-stream "^2.3.5" + +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" + integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== + dependencies: + has-flag "^3.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yargs-parser@13.1.2, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-unparser@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" + integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== + dependencies: + flat "^4.1.0" + lodash "^4.17.15" + yargs "^13.3.0" + +yargs@13.3.2, yargs@^13.3.0: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + 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.2" diff --git a/tests/project-worker/python/project.yml b/tests/project-worker/python/project.yml new file mode 100644 index 0000000..195980f --- /dev/null +++ b/tests/project-worker/python/project.yml @@ -0,0 +1,7 @@ +project: + allowed-folders: + - src/ + before-test: + - pip install -r requirements.txt + testcases: + - python manage.py test tests/* \ No newline at end of file diff --git a/tests/project-worker/python/project/main/__init__.py b/tests/project-worker/python/project/main/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/project-worker/python/project/main/admin.py b/tests/project-worker/python/project/main/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/tests/project-worker/python/project/main/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/tests/project-worker/python/project/main/apps.py b/tests/project-worker/python/project/main/apps.py new file mode 100644 index 0000000..833bff6 --- /dev/null +++ b/tests/project-worker/python/project/main/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class MainConfig(AppConfig): + name = 'main' diff --git a/tests/project-worker/python/project/main/migrations/0001_initial.py b/tests/project-worker/python/project/main/migrations/0001_initial.py new file mode 100644 index 0000000..db8cf04 --- /dev/null +++ b/tests/project-worker/python/project/main/migrations/0001_initial.py @@ -0,0 +1,22 @@ +# Generated by Django 3.0.8 on 2020-07-08 13:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Animal', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=1024)), + ('sound', models.CharField(max_length=1024)), + ], + ), + ] diff --git a/tests/project-worker/python/project/main/migrations/__init__.py b/tests/project-worker/python/project/main/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/project-worker/python/project/main/models.py b/tests/project-worker/python/project/main/models.py new file mode 100644 index 0000000..9bbe6a1 --- /dev/null +++ b/tests/project-worker/python/project/main/models.py @@ -0,0 +1,10 @@ +from django.db import models + +# Create your models here. +class Animal(models.Model): + name = models.CharField(max_length = 1024) + sound = models.CharField(max_length = 1024) + + def speak(self): + return f'The {self.name} says \"{self.sound}\"' + \ No newline at end of file diff --git a/tests/project-worker/python/project/main/tests.py b/tests/project-worker/python/project/main/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/tests/project-worker/python/project/main/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/tests/project-worker/python/project/main/views.py b/tests/project-worker/python/project/main/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/tests/project-worker/python/project/main/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/tests/project-worker/python/project/manage.py b/tests/project-worker/python/project/manage.py new file mode 100755 index 0000000..73e8ff1 --- /dev/null +++ b/tests/project-worker/python/project/manage.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/tests/project-worker/python/project/requirements.txt b/tests/project-worker/python/project/requirements.txt new file mode 100644 index 0000000..68d357c --- /dev/null +++ b/tests/project-worker/python/project/requirements.txt @@ -0,0 +1 @@ +django \ No newline at end of file diff --git a/tests/project-worker/python/project/sample/__init__.py b/tests/project-worker/python/project/sample/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/project-worker/python/project/sample/asgi.py b/tests/project-worker/python/project/sample/asgi.py new file mode 100644 index 0000000..d143751 --- /dev/null +++ b/tests/project-worker/python/project/sample/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for sample project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample.settings') + +application = get_asgi_application() diff --git a/tests/project-worker/python/project/sample/settings.py b/tests/project-worker/python/project/sample/settings.py new file mode 100644 index 0000000..2c99cdd --- /dev/null +++ b/tests/project-worker/python/project/sample/settings.py @@ -0,0 +1,122 @@ +""" +Django settings for sample project. + +Generated by 'django-admin startproject' using Django 3.0.8. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.0/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'j_#@8u(ux_slp$7yp&b(sxexkj2c$65u83q5c-xv6jmyeyi4*b' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'main', + + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'sample.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'sample.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/3.0/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/3.0/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.0/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/tests/project-worker/python/project/sample/urls.py b/tests/project-worker/python/project/sample/urls.py new file mode 100644 index 0000000..54df2ce --- /dev/null +++ b/tests/project-worker/python/project/sample/urls.py @@ -0,0 +1,21 @@ +"""sample URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path + +urlpatterns = [ + path('admin/', admin.site.urls), +] diff --git a/tests/project-worker/python/project/sample/wsgi.py b/tests/project-worker/python/project/sample/wsgi.py new file mode 100644 index 0000000..ba7663b --- /dev/null +++ b/tests/project-worker/python/project/sample/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for sample project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample.settings') + +application = get_wsgi_application() diff --git a/tests/project-worker/python/project/tests/main/test_animal.py b/tests/project-worker/python/project/tests/main/test_animal.py new file mode 100644 index 0000000..4fad006 --- /dev/null +++ b/tests/project-worker/python/project/tests/main/test_animal.py @@ -0,0 +1,14 @@ +from django.test import TestCase +from main.models import Animal + +class AnimalTestCase(TestCase): + def setUp(self): + Animal.objects.create(name="lion", sound="roar") + Animal.objects.create(name="cat", sound="meow") + + def test_animals_can_speak(self): + """Animals that can speak are correctly identified""" + lion = Animal.objects.get(name="lion") + cat = Animal.objects.get(name="cat") + self.assertEqual(lion.speak(), 'The lion says "roar"') + self.assertEqual(cat.speak(), 'The cat says "meow"') \ No newline at end of file diff --git a/tests/project-worker/test_workers.sh b/tests/project-worker/test_workers.sh new file mode 100755 index 0000000..6e3d1b2 --- /dev/null +++ b/tests/project-worker/test_workers.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +pushd $(dirname "$0") +DIR=$(pwd) +RUNBOX="${DIR}/runbox" +LANGUAGE=$1 + +echo $RUNBOX +# Create runbox +mkdir -p $RUNBOX + +# Copy source to runbox +cp -r $DIR/$LANGUAGE/* $RUNBOX/ + +# Test Compile +docker run \ + --cpus="1" \ + --memory="500m" \ + --rm \ + -v "$RUNBOX":/usr/src/runbox \ + -w /usr/src/runbox codingblocks/project-worker-"$LANGUAGE" \ + /bin/judge.py + +ls -lh ${RUNBOX} + +cat ${RUNBOX}/result.code +cat ${RUNBOX}/result.stderr + +# Delete runbox +rm -rf $RUNBOX diff --git a/tests/ruby/run.stdin b/tests/ruby/run.stdin deleted file mode 100644 index beef906..0000000 --- a/tests/ruby/run.stdin +++ /dev/null @@ -1 +0,0 @@ -World \ No newline at end of file