├── .gitignore ├── .travis.yml ├── .vscode └── settings.json ├── README.md ├── bats ├── bin │ └── bats └── libexec │ ├── bats │ ├── bats-exec-suite │ ├── bats-exec-test │ ├── bats-format-tap-stream │ └── bats-preprocess ├── build_workers.sh ├── containers ├── judge-worker │ ├── base │ │ ├── Dockerfile │ │ ├── judge.sh │ │ └── runguard │ │ │ ├── runguard-config.h │ │ │ └── runguard.c │ ├── c │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── cpp │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── csharp │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── csv │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── golang │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── java │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── java8 │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── kotlin │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── mysql │ │ ├── Dockerfile │ │ ├── compile.sh │ │ ├── pre-run │ │ │ ├── index.js │ │ │ ├── package-lock.json │ │ │ └── package.json │ │ └── run.sh │ ├── nodejs10 │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── nodejs12 │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── perl │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── py2 │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── py3 │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ ├── ruby │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh │ └── rust │ │ ├── Dockerfile │ │ ├── compile.sh │ │ └── run.sh └── project-worker │ ├── base │ ├── Dockerfile │ ├── judge.py │ └── runguard │ │ ├── runguard-config.h │ │ └── runguard.c │ ├── nodejs │ └── Dockerfile │ └── python │ └── Dockerfile ├── package-lock.json ├── push_docker_images.sh ├── test.sh └── tests ├── judge-worker ├── c │ ├── run.stdin │ └── source.c ├── cpp │ ├── run.stdin │ └── source.cpp ├── csharp │ ├── program.cs │ └── run.stdin ├── golang │ ├── main.go │ └── run.stdin ├── java │ ├── Main.java │ └── run.stdin ├── java8 │ ├── Main.java │ └── run.stdin ├── kotlin │ ├── Main.kt │ └── run.stdin ├── nodejs10 │ ├── run.stdin │ └── script.js ├── nodejs12 │ ├── run.stdin │ └── script.js ├── perl │ ├── run.stdin │ └── script.pl ├── py2 │ ├── run.stdin │ └── script.py ├── py3 │ ├── run.stdin │ └── script.py ├── ruby │ ├── run.stdin │ └── script.rb ├── rust │ ├── run.stdin │ └── script.rs └── test_workers.sh └── project-worker ├── nodejs ├── project.yml └── project │ ├── .gitignore │ ├── package.json │ ├── src │ └── index.js │ ├── test │ └── user.spec.js │ └── yarn.lock ├── python ├── project.yml └── project │ ├── main │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py │ ├── manage.py │ ├── requirements.txt │ ├── sample │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py │ └── tests │ └── main │ └── test_animal.py └── test_workers.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | *.pyc 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | sudo: required 3 | env: 4 | global: 5 | - PATH=${TRAVIS_BUILD_DIR/bats/bin}:${PATH} 6 | addons: 7 | apt: 8 | packages: 9 | - bash 10 | services: 11 | - docker 12 | 13 | install: 14 | - "./build_workers.sh" 15 | 16 | script: 17 | - "test.sh" 18 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "iostream": "cpp" 4 | } 5 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # judge-workers 2 | 3 | This is one of the components of Coding Blocks Online Code Judge v2 4 | 5 | [![Build Status](https://travis-ci.org/coding-blocks/judge-workers.svg?branch=master)](https://travis-ci.org/coding-blocks/judge-workers) 6 | 7 | ## Workers 8 | 9 | Workers are docker containers that run the code. They have simple requirements 10 | 11 | - They have one compile.sh file that compiles (if required) the source 12 | - They have a run.sh file that runs the source or the binary 13 | 14 | ## Composition 15 | 16 | All workers are built on top of [alpine linux](https://alpinelinux.org/) 3.6 17 | 18 | ## Supported Languages 19 | 20 | Currently, we have following images - 21 | 22 | - [c](containers/judge-worker/c) 23 | - [cpp](containers/judge-worker/cpp) 24 | - [c#](containers/judge-worker/csharp) 25 | - [golang](containers/judge-worker/golang) 26 | - [java8](containers/judge-worker/java8) 27 | - [kotlin](containers/judge-worker/kotlin) 28 | - [nodejs6](containers/judge-worker/nodejs6) 29 | - [nodejs](containers/judge-worker/nodejs8) 30 | - [perl](containers/judge-worker/perl) 31 | - [py2](containers/judge-worker/py2) 32 | - [py3](containers/judge-worker/py3) 33 | - [ruby](containers/judge-worker/ruby) 34 | - [rust](containers/judge-worker/rust) 35 | -------------------------------------------------------------------------------- /bats/bin/bats: -------------------------------------------------------------------------------- 1 | ../libexec/bats -------------------------------------------------------------------------------- /bats/libexec/bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | version() { 5 | echo "Bats 0.4.0" 6 | } 7 | 8 | usage() { 9 | version 10 | echo "Usage: bats [-c] [-p | -t] [ ...]" 11 | } 12 | 13 | help() { 14 | usage 15 | echo 16 | echo " is the path to a Bats test file, or the path to a directory" 17 | echo " containing Bats test files." 18 | echo 19 | echo " -c, --count Count the number of test cases without running any tests" 20 | echo " -h, --help Display this help message" 21 | echo " -p, --pretty Show results in pretty format (default for terminals)" 22 | echo " -t, --tap Show results in TAP format" 23 | echo " -v, --version Display the version number" 24 | echo 25 | echo " For more information, see https://github.com/sstephenson/bats" 26 | echo 27 | } 28 | 29 | resolve_link() { 30 | $(type -p greadlink readlink | head -1) "$1" 31 | } 32 | 33 | abs_dirname() { 34 | local cwd="$(pwd)" 35 | local path="$1" 36 | 37 | while [ -n "$path" ]; do 38 | cd "${path%/*}" 39 | local name="${path##*/}" 40 | path="$(resolve_link "$name" || true)" 41 | done 42 | 43 | pwd 44 | cd "$cwd" 45 | } 46 | 47 | expand_path() { 48 | { cd "$(dirname "$1")" 2>/dev/null 49 | local dirname="$PWD" 50 | cd "$OLDPWD" 51 | echo "$dirname/$(basename "$1")" 52 | } || echo "$1" 53 | } 54 | 55 | BATS_LIBEXEC="$(abs_dirname "$0")" 56 | export BATS_PREFIX="$(abs_dirname "$BATS_LIBEXEC")" 57 | export BATS_CWD="$(abs_dirname .)" 58 | export PATH="$BATS_LIBEXEC:$PATH" 59 | 60 | options=() 61 | arguments=() 62 | for arg in "$@"; do 63 | if [ "${arg:0:1}" = "-" ]; then 64 | if [ "${arg:1:1}" = "-" ]; then 65 | options[${#options[*]}]="${arg:2}" 66 | else 67 | index=1 68 | while option="${arg:$index:1}"; do 69 | [ -n "$option" ] || break 70 | options[${#options[*]}]="$option" 71 | let index+=1 72 | done 73 | fi 74 | else 75 | arguments[${#arguments[*]}]="$arg" 76 | fi 77 | done 78 | 79 | unset count_flag pretty 80 | [ -t 0 ] && [ -t 1 ] && pretty="1" 81 | [ -n "$CI" ] && pretty="" 82 | 83 | for option in "${options[@]}"; do 84 | case "$option" in 85 | "h" | "help" ) 86 | help 87 | exit 0 88 | ;; 89 | "v" | "version" ) 90 | version 91 | exit 0 92 | ;; 93 | "c" | "count" ) 94 | count_flag="-c" 95 | ;; 96 | "t" | "tap" ) 97 | pretty="" 98 | ;; 99 | "p" | "pretty" ) 100 | pretty="1" 101 | ;; 102 | * ) 103 | usage >&2 104 | exit 1 105 | ;; 106 | esac 107 | done 108 | 109 | if [ "${#arguments[@]}" -eq 0 ]; then 110 | usage >&2 111 | exit 1 112 | fi 113 | 114 | filenames=() 115 | for filename in "${arguments[@]}"; do 116 | if [ -d "$filename" ]; then 117 | shopt -s nullglob 118 | for suite_filename in "$(expand_path "$filename")"/*.bats; do 119 | filenames["${#filenames[@]}"]="$suite_filename" 120 | done 121 | shopt -u nullglob 122 | else 123 | filenames["${#filenames[@]}"]="$(expand_path "$filename")" 124 | fi 125 | done 126 | 127 | if [ "${#filenames[@]}" -eq 1 ]; then 128 | command="bats-exec-test" 129 | else 130 | command="bats-exec-suite" 131 | fi 132 | 133 | if [ -n "$pretty" ]; then 134 | extended_syntax_flag="-x" 135 | formatter="bats-format-tap-stream" 136 | else 137 | extended_syntax_flag="" 138 | formatter="cat" 139 | fi 140 | 141 | set -o pipefail execfail 142 | exec "$command" $count_flag $extended_syntax_flag "${filenames[@]}" | "$formatter" 143 | -------------------------------------------------------------------------------- /bats/libexec/bats-exec-suite: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | count_only_flag="" 5 | if [ "$1" = "-c" ]; then 6 | count_only_flag=1 7 | shift 8 | fi 9 | 10 | extended_syntax_flag="" 11 | if [ "$1" = "-x" ]; then 12 | extended_syntax_flag="-x" 13 | shift 14 | fi 15 | 16 | trap "kill 0; exit 1" int 17 | 18 | count=0 19 | for filename in "$@"; do 20 | let count+="$(bats-exec-test -c "$filename")" 21 | done 22 | 23 | if [ -n "$count_only_flag" ]; then 24 | echo "$count" 25 | exit 26 | fi 27 | 28 | echo "1..$count" 29 | status=0 30 | offset=0 31 | for filename in "$@"; do 32 | index=0 33 | { 34 | IFS= read -r # 1..n 35 | while IFS= read -r line; do 36 | case "$line" in 37 | "begin "* ) 38 | let index+=1 39 | echo "${line/ $index / $(($offset + $index)) }" 40 | ;; 41 | "ok "* | "not ok "* ) 42 | [ -n "$extended_syntax_flag" ] || let index+=1 43 | echo "${line/ $index / $(($offset + $index)) }" 44 | [ "${line:0:6}" != "not ok" ] || status=1 45 | ;; 46 | * ) 47 | echo "$line" 48 | ;; 49 | esac 50 | done 51 | } < <( bats-exec-test $extended_syntax_flag "$filename" ) 52 | offset=$(($offset + $index)) 53 | done 54 | 55 | exit "$status" 56 | -------------------------------------------------------------------------------- /bats/libexec/bats-exec-test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | set -E 4 | set -T 5 | 6 | BATS_COUNT_ONLY="" 7 | if [ "$1" = "-c" ]; then 8 | BATS_COUNT_ONLY=1 9 | shift 10 | fi 11 | 12 | BATS_EXTENDED_SYNTAX="" 13 | if [ "$1" = "-x" ]; then 14 | BATS_EXTENDED_SYNTAX="$1" 15 | shift 16 | fi 17 | 18 | BATS_TEST_FILENAME="$1" 19 | if [ -z "$BATS_TEST_FILENAME" ]; then 20 | echo "usage: bats-exec " >&2 21 | exit 1 22 | elif [ ! -f "$BATS_TEST_FILENAME" ]; then 23 | echo "bats: $BATS_TEST_FILENAME does not exist" >&2 24 | exit 1 25 | else 26 | shift 27 | fi 28 | 29 | BATS_TEST_DIRNAME="$(dirname "$BATS_TEST_FILENAME")" 30 | BATS_TEST_NAMES=() 31 | 32 | load() { 33 | local name="$1" 34 | local filename 35 | 36 | if [ "${name:0:1}" = "/" ]; then 37 | filename="${name}" 38 | else 39 | filename="$BATS_TEST_DIRNAME/${name}.bash" 40 | fi 41 | 42 | [ -f "$filename" ] || { 43 | echo "bats: $filename does not exist" >&2 44 | exit 1 45 | } 46 | 47 | source "${filename}" 48 | } 49 | 50 | run() { 51 | local e E T oldIFS 52 | [[ ! "$-" =~ e ]] || e=1 53 | [[ ! "$-" =~ E ]] || E=1 54 | [[ ! "$-" =~ T ]] || T=1 55 | set +e 56 | set +E 57 | set +T 58 | output="$("$@" 2>&1)" 59 | status="$?" 60 | oldIFS=$IFS 61 | IFS=$'\n' lines=($output) 62 | [ -z "$e" ] || set -e 63 | [ -z "$E" ] || set -E 64 | [ -z "$T" ] || set -T 65 | IFS=$oldIFS 66 | } 67 | 68 | setup() { 69 | true 70 | } 71 | 72 | teardown() { 73 | true 74 | } 75 | 76 | skip() { 77 | BATS_TEST_SKIPPED=${1:-1} 78 | BATS_TEST_COMPLETED=1 79 | exit 0 80 | } 81 | 82 | bats_test_begin() { 83 | BATS_TEST_DESCRIPTION="$1" 84 | if [ -n "$BATS_EXTENDED_SYNTAX" ]; then 85 | echo "begin $BATS_TEST_NUMBER $BATS_TEST_DESCRIPTION" >&3 86 | fi 87 | setup 88 | } 89 | 90 | bats_test_function() { 91 | local test_name="$1" 92 | BATS_TEST_NAMES["${#BATS_TEST_NAMES[@]}"]="$test_name" 93 | } 94 | 95 | bats_capture_stack_trace() { 96 | BATS_PREVIOUS_STACK_TRACE=( "${BATS_CURRENT_STACK_TRACE[@]}" ) 97 | BATS_CURRENT_STACK_TRACE=() 98 | 99 | local test_pattern=" $BATS_TEST_NAME $BATS_TEST_SOURCE" 100 | local setup_pattern=" setup $BATS_TEST_SOURCE" 101 | local teardown_pattern=" teardown $BATS_TEST_SOURCE" 102 | 103 | local frame 104 | local index=1 105 | 106 | while frame="$(caller "$index")"; do 107 | BATS_CURRENT_STACK_TRACE["${#BATS_CURRENT_STACK_TRACE[@]}"]="$frame" 108 | if [[ "$frame" = *"$test_pattern" || \ 109 | "$frame" = *"$setup_pattern" || \ 110 | "$frame" = *"$teardown_pattern" ]]; then 111 | break 112 | else 113 | let index+=1 114 | fi 115 | done 116 | 117 | BATS_SOURCE="$(bats_frame_filename "${BATS_CURRENT_STACK_TRACE[0]}")" 118 | BATS_LINENO="$(bats_frame_lineno "${BATS_CURRENT_STACK_TRACE[0]}")" 119 | } 120 | 121 | bats_print_stack_trace() { 122 | local frame 123 | local index=1 124 | local count="${#@}" 125 | 126 | for frame in "$@"; do 127 | local filename="$(bats_trim_filename "$(bats_frame_filename "$frame")")" 128 | local lineno="$(bats_frame_lineno "$frame")" 129 | 130 | if [ $index -eq 1 ]; then 131 | echo -n "# (" 132 | else 133 | echo -n "# " 134 | fi 135 | 136 | local fn="$(bats_frame_function "$frame")" 137 | if [ "$fn" != "$BATS_TEST_NAME" ]; then 138 | echo -n "from function \`$fn' " 139 | fi 140 | 141 | if [ $index -eq $count ]; then 142 | echo "in test file $filename, line $lineno)" 143 | else 144 | echo "in file $filename, line $lineno," 145 | fi 146 | 147 | let index+=1 148 | done 149 | } 150 | 151 | bats_print_failed_command() { 152 | local frame="$1" 153 | local status="$2" 154 | local filename="$(bats_frame_filename "$frame")" 155 | local lineno="$(bats_frame_lineno "$frame")" 156 | 157 | local failed_line="$(bats_extract_line "$filename" "$lineno")" 158 | local failed_command="$(bats_strip_string "$failed_line")" 159 | echo -n "# \`${failed_command}' " 160 | 161 | if [ $status -eq 1 ]; then 162 | echo "failed" 163 | else 164 | echo "failed with status $status" 165 | fi 166 | } 167 | 168 | bats_frame_lineno() { 169 | local frame="$1" 170 | local lineno="${frame%% *}" 171 | echo "$lineno" 172 | } 173 | 174 | bats_frame_function() { 175 | local frame="$1" 176 | local rest="${frame#* }" 177 | local fn="${rest%% *}" 178 | echo "$fn" 179 | } 180 | 181 | bats_frame_filename() { 182 | local frame="$1" 183 | local rest="${frame#* }" 184 | local filename="${rest#* }" 185 | 186 | if [ "$filename" = "$BATS_TEST_SOURCE" ]; then 187 | echo "$BATS_TEST_FILENAME" 188 | else 189 | echo "$filename" 190 | fi 191 | } 192 | 193 | bats_extract_line() { 194 | local filename="$1" 195 | local lineno="$2" 196 | sed -n "${lineno}p" "$filename" 197 | } 198 | 199 | bats_strip_string() { 200 | local string="$1" 201 | printf "%s" "$string" | sed -e "s/^[ "$'\t'"]*//" -e "s/[ "$'\t'"]*$//" 202 | } 203 | 204 | bats_trim_filename() { 205 | local filename="$1" 206 | local length="${#BATS_CWD}" 207 | 208 | if [ "${filename:0:length+1}" = "${BATS_CWD}/" ]; then 209 | echo "${filename:length+1}" 210 | else 211 | echo "$filename" 212 | fi 213 | } 214 | 215 | bats_debug_trap() { 216 | if [ "$BASH_SOURCE" != "$1" ]; then 217 | bats_capture_stack_trace 218 | fi 219 | } 220 | 221 | bats_error_trap() { 222 | BATS_ERROR_STATUS="$?" 223 | BATS_ERROR_STACK_TRACE=( "${BATS_PREVIOUS_STACK_TRACE[@]}" ) 224 | trap - debug 225 | } 226 | 227 | bats_teardown_trap() { 228 | trap "bats_exit_trap" exit 229 | local status=0 230 | teardown >>"$BATS_OUT" 2>&1 || status="$?" 231 | 232 | if [ $status -eq 0 ]; then 233 | BATS_TEARDOWN_COMPLETED=1 234 | elif [ -n "$BATS_TEST_COMPLETED" ]; then 235 | BATS_ERROR_STATUS="$status" 236 | BATS_ERROR_STACK_TRACE=( "${BATS_CURRENT_STACK_TRACE[@]}" ) 237 | fi 238 | 239 | bats_exit_trap 240 | } 241 | 242 | bats_exit_trap() { 243 | local status 244 | local skipped 245 | trap - err exit 246 | 247 | skipped="" 248 | if [ -n "$BATS_TEST_SKIPPED" ]; then 249 | skipped=" # skip" 250 | if [ "1" != "$BATS_TEST_SKIPPED" ]; then 251 | skipped+=" ($BATS_TEST_SKIPPED)" 252 | fi 253 | fi 254 | 255 | if [ -z "$BATS_TEST_COMPLETED" ] || [ -z "$BATS_TEARDOWN_COMPLETED" ]; then 256 | echo "not ok $BATS_TEST_NUMBER $BATS_TEST_DESCRIPTION" >&3 257 | bats_print_stack_trace "${BATS_ERROR_STACK_TRACE[@]}" >&3 258 | bats_print_failed_command "${BATS_ERROR_STACK_TRACE[${#BATS_ERROR_STACK_TRACE[@]}-1]}" "$BATS_ERROR_STATUS" >&3 259 | sed -e "s/^/# /" < "$BATS_OUT" >&3 260 | status=1 261 | else 262 | echo "ok ${BATS_TEST_NUMBER}${skipped} ${BATS_TEST_DESCRIPTION}" >&3 263 | status=0 264 | fi 265 | 266 | rm -f "$BATS_OUT" 267 | exit "$status" 268 | } 269 | 270 | bats_perform_tests() { 271 | echo "1..$#" 272 | test_number=1 273 | status=0 274 | for test_name in "$@"; do 275 | "$0" $BATS_EXTENDED_SYNTAX "$BATS_TEST_FILENAME" "$test_name" "$test_number" || status=1 276 | let test_number+=1 277 | done 278 | exit "$status" 279 | } 280 | 281 | bats_perform_test() { 282 | BATS_TEST_NAME="$1" 283 | if [ "$(type -t "$BATS_TEST_NAME" || true)" = "function" ]; then 284 | BATS_TEST_NUMBER="$2" 285 | if [ -z "$BATS_TEST_NUMBER" ]; then 286 | echo "1..1" 287 | BATS_TEST_NUMBER="1" 288 | fi 289 | 290 | BATS_TEST_COMPLETED="" 291 | BATS_TEARDOWN_COMPLETED="" 292 | trap "bats_debug_trap \"\$BASH_SOURCE\"" debug 293 | trap "bats_error_trap" err 294 | trap "bats_teardown_trap" exit 295 | "$BATS_TEST_NAME" >>"$BATS_OUT" 2>&1 296 | BATS_TEST_COMPLETED=1 297 | 298 | else 299 | echo "bats: unknown test name \`$BATS_TEST_NAME'" >&2 300 | exit 1 301 | fi 302 | } 303 | 304 | if [ -z "$TMPDIR" ]; then 305 | BATS_TMPDIR="/tmp" 306 | else 307 | BATS_TMPDIR="${TMPDIR%/}" 308 | fi 309 | 310 | BATS_TMPNAME="$BATS_TMPDIR/bats.$$" 311 | BATS_PARENT_TMPNAME="$BATS_TMPDIR/bats.$PPID" 312 | BATS_OUT="${BATS_TMPNAME}.out" 313 | 314 | bats_preprocess_source() { 315 | BATS_TEST_SOURCE="${BATS_TMPNAME}.src" 316 | { tr -d '\r' < "$BATS_TEST_FILENAME"; echo; } | bats-preprocess > "$BATS_TEST_SOURCE" 317 | trap "bats_cleanup_preprocessed_source" err exit 318 | trap "bats_cleanup_preprocessed_source; exit 1" int 319 | } 320 | 321 | bats_cleanup_preprocessed_source() { 322 | rm -f "$BATS_TEST_SOURCE" 323 | } 324 | 325 | bats_evaluate_preprocessed_source() { 326 | if [ -z "$BATS_TEST_SOURCE" ]; then 327 | BATS_TEST_SOURCE="${BATS_PARENT_TMPNAME}.src" 328 | fi 329 | source "$BATS_TEST_SOURCE" 330 | } 331 | 332 | exec 3<&1 333 | 334 | if [ "$#" -eq 0 ]; then 335 | bats_preprocess_source 336 | bats_evaluate_preprocessed_source 337 | 338 | if [ -n "$BATS_COUNT_ONLY" ]; then 339 | echo "${#BATS_TEST_NAMES[@]}" 340 | else 341 | bats_perform_tests "${BATS_TEST_NAMES[@]}" 342 | fi 343 | else 344 | bats_evaluate_preprocessed_source 345 | bats_perform_test "$@" 346 | fi 347 | -------------------------------------------------------------------------------- /bats/libexec/bats-format-tap-stream: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # Just stream the TAP output (sans extended syntax) if tput is missing 5 | command -v tput >/dev/null || exec grep -v "^begin " 6 | 7 | header_pattern='[0-9]+\.\.[0-9]+' 8 | IFS= read -r header 9 | 10 | if [[ "$header" =~ $header_pattern ]]; then 11 | count="${header:3}" 12 | index=0 13 | failures=0 14 | skipped=0 15 | name="" 16 | count_column_width=$(( ${#count} * 2 + 2 )) 17 | else 18 | # If the first line isn't a TAP plan, print it and pass the rest through 19 | printf "%s\n" "$header" 20 | exec cat 21 | fi 22 | 23 | update_screen_width() { 24 | screen_width="$(tput cols)" 25 | count_column_left=$(( $screen_width - $count_column_width )) 26 | } 27 | 28 | trap update_screen_width WINCH 29 | update_screen_width 30 | 31 | begin() { 32 | go_to_column 0 33 | printf_with_truncation $(( $count_column_left - 1 )) " %s" "$name" 34 | clear_to_end_of_line 35 | go_to_column $count_column_left 36 | printf "%${#count}s/${count}" "$index" 37 | go_to_column 1 38 | } 39 | 40 | pass() { 41 | go_to_column 0 42 | printf " ✓ %s" "$name" 43 | advance 44 | } 45 | 46 | skip() { 47 | local reason="$1" 48 | [ -z "$reason" ] || reason=": $reason" 49 | go_to_column 0 50 | printf " - %s (skipped%s)" "$name" "$reason" 51 | advance 52 | } 53 | 54 | fail() { 55 | go_to_column 0 56 | set_color 1 bold 57 | printf " ✗ %s" "$name" 58 | advance 59 | } 60 | 61 | log() { 62 | set_color 1 63 | printf " %s\n" "$1" 64 | clear_color 65 | } 66 | 67 | summary() { 68 | printf "\n%d test%s" "$count" "$(plural "$count")" 69 | 70 | printf ", %d failure%s" "$failures" "$(plural "$failures")" 71 | 72 | if [ "$skipped" -gt 0 ]; then 73 | printf ", %d skipped" "$skipped" 74 | fi 75 | 76 | printf "\n" 77 | } 78 | 79 | printf_with_truncation() { 80 | local width="$1" 81 | shift 82 | local string="$(printf "$@")" 83 | 84 | if [ "${#string}" -gt "$width" ]; then 85 | printf "%s..." "${string:0:$(( $width - 4 ))}" 86 | else 87 | printf "%s" "$string" 88 | fi 89 | } 90 | 91 | go_to_column() { 92 | local column="$1" 93 | printf "\x1B[%dG" $(( $column + 1 )) 94 | } 95 | 96 | clear_to_end_of_line() { 97 | printf "\x1B[K" 98 | } 99 | 100 | advance() { 101 | clear_to_end_of_line 102 | echo 103 | clear_color 104 | } 105 | 106 | set_color() { 107 | local color="$1" 108 | local weight="$2" 109 | printf "\x1B[%d;%dm" $(( 30 + $color )) "$( [ "$weight" = "bold" ] && echo 1 || echo 22 )" 110 | } 111 | 112 | clear_color() { 113 | printf "\x1B[0m" 114 | } 115 | 116 | plural() { 117 | [ "$1" -eq 1 ] || echo "s" 118 | } 119 | 120 | _buffer="" 121 | 122 | buffer() { 123 | _buffer="${_buffer}$("$@")" 124 | } 125 | 126 | flush() { 127 | printf "%s" "$_buffer" 128 | _buffer="" 129 | } 130 | 131 | finish() { 132 | flush 133 | printf "\n" 134 | } 135 | 136 | trap finish EXIT 137 | 138 | while IFS= read -r line; do 139 | case "$line" in 140 | "begin "* ) 141 | let index+=1 142 | name="${line#* $index }" 143 | buffer begin 144 | flush 145 | ;; 146 | "ok "* ) 147 | skip_expr="ok $index # skip (\(([^)]*)\))?" 148 | if [[ "$line" =~ $skip_expr ]]; then 149 | let skipped+=1 150 | buffer skip "${BASH_REMATCH[2]}" 151 | else 152 | buffer pass 153 | fi 154 | ;; 155 | "not ok "* ) 156 | let failures+=1 157 | buffer fail 158 | ;; 159 | "# "* ) 160 | buffer log "${line:2}" 161 | ;; 162 | esac 163 | done 164 | 165 | buffer summary 166 | -------------------------------------------------------------------------------- /bats/libexec/bats-preprocess: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | encode_name() { 5 | local name="$1" 6 | local result="test_" 7 | 8 | if [[ ! "$name" =~ [^[:alnum:]\ _-] ]]; then 9 | name="${name//_/-5f}" 10 | name="${name//-/-2d}" 11 | name="${name// /_}" 12 | result+="$name" 13 | else 14 | local length="${#name}" 15 | local char i 16 | 17 | for ((i=0; i&2 26 | ;; 27 | esac 28 | done 29 | 30 | ####################################### 31 | # Run compilation script 32 | # Outputs: 33 | # Writes error to //stderr 34 | ####################################### 35 | function compilecode { 36 | /bin/compile.sh 2> compile.stderr || exit 1 37 | } 38 | 39 | ####################################### 40 | # Runs code against given INPUT 41 | # Arguments: 42 | # INPUT_FILE (input file) 43 | # OUTPUT_DIR (output location) 44 | # 45 | # Outputs: 46 | # Writes location to stdout 47 | ####################################### 48 | function runcode { 49 | INPUT_FILE=$1 50 | OUTPUT_DIR=$2 51 | TIME_LIMIT=$3 52 | MEMORY_LIMIT=$4 53 | 54 | time=$TIME_LIMIT 55 | memory=$MEMORY_LIMIT 56 | 57 | touch $OUTPUT_DIR/runguard.code 58 | touch $OUTPUT_DIR/runguard.time 59 | touch $OUTPUT_DIR/runguard.out 60 | touch $OUTPUT_DIR/debug 61 | echo $memory > $OUTPUT_DIR/debug 62 | 63 | runguard \ 64 | -t $time \ 65 | -m $memory \ 66 | -E $OUTPUT_DIR/runguard.code \ 67 | -T $OUTPUT_DIR/runguard.time \ 68 | /bin/run.sh < $INPUT_FILE 2> $OUTPUT_DIR/run.stderr 1> $OUTPUT_DIR/run.stdout 69 | } 70 | 71 | function main { 72 | runguard \ 73 | -t 10 \ 74 | /bin/compile.sh 2> compile.stderr 75 | 76 | if [ -d "testcases" ]; then 77 | for testcase in testcases/*; do 78 | if [ -r "$testcase/timelimit" ]; then 79 | timelimit=`cat $testcase/timelimit` 80 | else 81 | timelimit="5" 82 | fi 83 | 84 | if [ -r "$testcase/memorylimit" ]; then 85 | memorylimit=`cat $testcase/memorylimit` 86 | else 87 | memorylimit=10485760 88 | fi 89 | 90 | runcode $testcase/stdin $testcase/ $timelimit $memorylimit 91 | done 92 | else 93 | runcode run.stdin . "5" 10485760 94 | fi 95 | } 96 | 97 | main 98 | 99 | -------------------------------------------------------------------------------- /containers/judge-worker/base/runguard/runguard-config.h: -------------------------------------------------------------------------------- 1 | /* Runguard config for use with CodeRunner. Includes all necessary 2 | * DOMJudge constants from config.h. 3 | * Assumes all tests will be done as the Linux user "coderunner". 4 | * It is assumed CHROOT will not be used so the CHROOT_PREFIX 5 | * is not meaningfully set. 6 | */ 7 | 8 | #ifndef _RUNGUARD_CONFIG_ 9 | #define _RUNGUARD_CONFIG_ 10 | 11 | #define DOMJUDGE_VERSION "3" 12 | #define REVISION "3.3" 13 | 14 | #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" 15 | 16 | #define CHROOT_PREFIX "/var/www/jobe/chrootjail" 17 | 18 | #endif /* _RUNGUARD_CONFIG_ */ 19 | -------------------------------------------------------------------------------- /containers/judge-worker/base/runguard/runguard.c: -------------------------------------------------------------------------------- 1 | /* 2 | runguard -- run command with restrictions. 3 | Copyright (C) 2004-2013 Jaap Eldering (eldering@a-eskwadraat.nl) 4 | Copyright (C) 2013 Keith Johnson 5 | 6 | Multiple minor improvements ported from the DOMjudge-ETH tree. 7 | 8 | Based on an idea from the timeout program, written by Wietse Venema 9 | as part of The Coroner's Toolkit. 10 | 11 | This program is free software; you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation; either version 2, or (at your option) 14 | any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with this program; if not, write to the Free Software Foundation, 23 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 24 | 25 | 26 | Program specifications: 27 | 28 | This program will run the specified command in a separate process 29 | group (session) and apply the restrictions as specified after 30 | forking, before executing the command. 31 | 32 | The stdin and stdout streams are passed to the command and runguard 33 | does not read or write to these. Error and verbose messages from 34 | runguard are by default written to stderr, hence mixed with stderr 35 | output of the command, unless that is optionally redirected to file. 36 | 37 | The command and its children are sent a SIGTERM after the runtime 38 | has passed, followed by a SIGKILL after 'killdelay'. 39 | */ 40 | 41 | /* Some system/site specific config: VALID_USERS, CHROOT_PREFIX */ 42 | #include "runguard-config.h" 43 | 44 | /* For chroot(), which is not POSIX. */ 45 | #define _DEFAULT_SOURCE 46 | /* For unshare(), only used when cgroups are enabled */ 47 | #if ( USE_CGROUPS == 1 ) 48 | #define _GNU_SOURCE 49 | #endif 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #if ( USE_CGROUPS == 1 ) 74 | #include 75 | #include 76 | #include 77 | #else 78 | #undef USE_CGROUPS 79 | #endif 80 | 81 | #define PROGRAM "runguard" 82 | #define VERSION DOMJUDGE_VERSION "/" REVISION 83 | #define AUTHORS "Jaap Eldering" 84 | 85 | #define max(x,y) ((x) > (y) ? (x) : (y)) 86 | 87 | /* Array indices for input/output file descriptors as used by pipe() */ 88 | #define PIPE_IN 1 89 | #define PIPE_OUT 0 90 | 91 | #define BUF_SIZE 4*1024 92 | char buf[BUF_SIZE]; 93 | 94 | const struct timespec killdelay = { 0, 100000000L }; /* 0.1 seconds */ 95 | 96 | extern int errno; 97 | 98 | #ifndef _GNU_SOURCE 99 | extern char **environ; 100 | #endif 101 | 102 | const int exit_failure = -1; 103 | 104 | char *progname; 105 | char *cmdname; 106 | char **cmdargs; 107 | char *rootdir; 108 | char *stdoutfilename; 109 | char *stderrfilename; 110 | char *exitfilename; 111 | char *timefilename; 112 | #ifdef USE_CGROUPS 113 | char *cgroupname; 114 | const char *cpuset; 115 | #endif 116 | 117 | int runuid; 118 | int rungid; 119 | int use_root; 120 | int use_time; 121 | int use_cputime; 122 | int use_user; 123 | int use_group; 124 | int redir_stdout; 125 | int redir_stderr; 126 | int limit_streamsize; 127 | int outputexit; 128 | int outputtime; 129 | int no_coredump; 130 | int be_verbose; 131 | int be_quiet; 132 | int show_help; 133 | int show_version; 134 | 135 | double runtime, cputime; /* in seconds */ 136 | #ifdef USE_CGROUPS 137 | int64_t memsize; 138 | #else 139 | rlim_t memsize; 140 | #endif 141 | rlim_t filesize; 142 | rlim_t nproc; 143 | size_t streamsize; 144 | 145 | pid_t child_pid; 146 | 147 | static volatile sig_atomic_t received_SIGCHLD = 0; 148 | 149 | FILE *child_stdout; 150 | FILE *child_stderr; 151 | int child_pipefd[3][2]; 152 | int child_redirfd[3]; 153 | 154 | struct timeval starttime, endtime; 155 | struct tms startticks, endticks; 156 | 157 | struct option const long_opts[] = { 158 | {"root", required_argument, NULL, 'r'}, 159 | {"user", required_argument, NULL, 'u'}, 160 | {"group", required_argument, NULL, 'g'}, 161 | {"time", required_argument, NULL, 't'}, 162 | {"cputime", required_argument, NULL, 'C'}, 163 | {"memsize", required_argument, NULL, 'm'}, 164 | {"filesize", required_argument, NULL, 'f'}, 165 | {"nproc", required_argument, NULL, 'p'}, 166 | {"cpuset", required_argument, NULL, 'P'}, 167 | {"no-core", no_argument, NULL, 'c'}, 168 | {"stdout", required_argument, NULL, 'o'}, 169 | {"stderr", required_argument, NULL, 'e'}, 170 | {"streamsize", required_argument, NULL, 's'}, 171 | {"outexit", required_argument, NULL, 'E'}, 172 | {"outtime", required_argument, NULL, 'T'}, 173 | {"verbose", no_argument, NULL, 'v'}, 174 | {"quiet", no_argument, NULL, 'q'}, 175 | {"help", no_argument, &show_help, 1 }, 176 | {"version", no_argument, &show_version, 1 }, 177 | { NULL, 0, NULL, 0 } 178 | }; 179 | 180 | void warning( const char *, ...) __attribute__((format (printf, 1, 2))); 181 | void verbose( const char *, ...) __attribute__((format (printf, 1, 2))); 182 | void error(int, const char *, ...) __attribute__((format (printf, 2, 3))); 183 | 184 | void warning(const char *format, ...) 185 | { 186 | va_list ap; 187 | va_start(ap,format); 188 | 189 | if ( ! be_quiet ) { 190 | fprintf(stderr,"%s: warning: ",progname); 191 | vfprintf(stderr,format,ap); 192 | fprintf(stderr,"\n"); 193 | } 194 | 195 | va_end(ap); 196 | } 197 | 198 | void verbose(const char *format, ...) 199 | { 200 | va_list ap; 201 | va_start(ap,format); 202 | 203 | if ( ! be_quiet && be_verbose ) { 204 | fprintf(stderr,"%s: verbose: ",progname); 205 | vfprintf(stderr,format,ap); 206 | fprintf(stderr,"\n"); 207 | } 208 | 209 | va_end(ap); 210 | } 211 | 212 | void error(int errnum, const char *format, ...) 213 | { 214 | va_list ap; 215 | va_start(ap,format); 216 | 217 | fprintf(stderr,"%s",progname); 218 | 219 | if ( format!=NULL ) { 220 | fprintf(stderr,": "); 221 | vfprintf(stderr,format,ap); 222 | } 223 | if ( errnum!=0 ) { 224 | fprintf(stderr,": %s",strerror(errnum)); 225 | } 226 | if ( format==NULL && errnum==0 ) { 227 | fprintf(stderr,": unknown error"); 228 | } 229 | 230 | fprintf(stderr,"\nTry `%s --help' for more information.\n",progname); 231 | va_end(ap); 232 | 233 | exit(exit_failure); 234 | } 235 | 236 | void version() 237 | { 238 | printf("\ 239 | %s -- version %s\n\ 240 | Written by %s\n\n\ 241 | %s comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n\ 242 | are welcome to redistribute it under certain conditions. See the GNU\n\ 243 | General Public Licence for details.\n",PROGRAM,VERSION,AUTHORS,PROGRAM); 244 | exit(0); 245 | } 246 | 247 | void usage() 248 | { 249 | printf("\ 250 | Usage: %s [OPTION]... COMMAND...\n\ 251 | Run COMMAND with restrictions.\n\ 252 | \n", progname); 253 | printf("\ 254 | -r, --root=ROOT run COMMAND with root directory set to ROOT\n\ 255 | -u, --user=USER run COMMAND as user with username or ID USER\n\ 256 | -g, --group=GROUP run COMMAND under group with name or ID GROUP\n\ 257 | -t, --time=TIME kill COMMAND after TIME seconds (float)\n\ 258 | -C, --cputime=TIME set maximum CPU time to TIME seconds (float)\n\ 259 | -m, --memsize=SIZE set all (total, stack, etc) memory limits to SIZE kB\n\ 260 | -f, --filesize=SIZE set maximum created filesize to SIZE kB;\n"); 261 | printf("\ 262 | -p, --nproc=N set maximum no. processes to N\n\ 263 | -P, --cpuset=ID use only processor number ID\n\ 264 | -c, --no-core disable core dumps\n\ 265 | -o, --stdout=FILE redirect COMMAND stdout output to FILE\n\ 266 | -e, --stderr=FILE redirect COMMAND stderr output to FILE\n\ 267 | -s, --streamsize=SIZE truncate COMMAND stdout/stderr streams at SIZE kB\n\ 268 | -E, --outexit=FILE write COMMAND exitcode to FILE\n\ 269 | -T, --outtime=FILE write COMMAND runtime to FILE\n"); 270 | printf("\ 271 | -v, --verbose display some extra warnings and information\n\ 272 | -q, --quiet suppress all warnings and verbose output\n\ 273 | --help display this help and exit\n\ 274 | --version output version information and exit\n"); 275 | printf("\n\ 276 | Note that root privileges are needed for the `root' and `user' options.\n\ 277 | The COMMAND path is relative to the changed ROOT directory if specified.\n\ 278 | When run setuid without the `user' option, the user ID is set to the\n\ 279 | real user ID.\n"); 280 | exit(0); 281 | } 282 | 283 | void output_exit_time(int exitcode, double timediff) 284 | { 285 | FILE *outputfile; 286 | double userdiff, sysdiff; 287 | unsigned long ticks_per_second = sysconf(_SC_CLK_TCK); 288 | 289 | verbose("command exited with exitcode %d",exitcode); 290 | 291 | if ( outputexit ) { 292 | verbose("writing exitcode to file `%s'",exitfilename); 293 | 294 | if ( (outputfile = fopen(exitfilename,"w"))==NULL ) { 295 | error(errno,"cannot open `%s'",exitfilename); 296 | } 297 | if ( fprintf(outputfile,"%d\n",exitcode)==0 ) { 298 | error(0,"cannot write to file `%s'",exitfilename); 299 | } 300 | if ( fclose(outputfile) ) { 301 | error(errno,"closing file `%s'",exitfilename); 302 | } 303 | } 304 | 305 | userdiff = (double)(endticks.tms_cutime - startticks.tms_cutime) / ticks_per_second; 306 | sysdiff = (double)(endticks.tms_cstime - startticks.tms_cstime) / ticks_per_second; 307 | 308 | verbose("runtime is %.3f seconds real, %.3f user, %.3f sys", 309 | timediff, userdiff, sysdiff); 310 | 311 | if ( use_cputime && (userdiff+sysdiff) > cputime ) { 312 | warning("timelimit exceeded (cpu time)"); 313 | } 314 | 315 | if ( outputtime ) { 316 | verbose("writing runtime to file `%s'",timefilename); 317 | 318 | if ( (outputfile = fopen(timefilename,"w"))==NULL ) { 319 | error(errno,"cannot open `%s'",timefilename); 320 | } 321 | if ( fprintf(outputfile,"%.3f\n",userdiff+sysdiff)==0 ) { 322 | error(0,"cannot write to file `%s'",timefilename); 323 | } 324 | if ( fclose(outputfile) ) { 325 | error(errno,"closing file `%s'",timefilename); 326 | } 327 | } 328 | } 329 | 330 | #ifdef USE_CGROUPS 331 | void output_cgroup_stats() 332 | { 333 | int ret; 334 | int64_t max_usage; 335 | struct cgroup *cg; 336 | struct cgroup_controller *cg_controller; 337 | 338 | cg = cgroup_new_cgroup(cgroupname); 339 | if (!cg) { 340 | error(0,"cgroup_new_cgroup"); 341 | } 342 | if ((ret = cgroup_get_cgroup(cg)) != 0) { 343 | error(0,"get cgroup information: %s(%d)", cgroup_strerror(ret), ret); 344 | } 345 | cg_controller = cgroup_get_controller(cg, "memory"); 346 | ret = cgroup_get_value_int64(cg_controller, "memory.memsw.max_usage_in_bytes", &max_usage); 347 | if ( ret!=0 ) { 348 | error(0,"get cgroup value: %s(%d)", cgroup_strerror(ret), ret); 349 | } 350 | 351 | verbose("total memory used: %" PRId64 " kB", max_usage/1024); 352 | 353 | cgroup_free(&cg); 354 | } 355 | 356 | void cgroup_create() 357 | { 358 | int ret; 359 | struct cgroup *cg; 360 | struct cgroup_controller *cg_controller; 361 | 362 | cg = cgroup_new_cgroup(cgroupname); 363 | if (!cg) { 364 | error(0,"cgroup_new_cgroup"); 365 | } 366 | 367 | /* Set up the memory restrictions; these two options limit ram use 368 | and ram+swap use. They are the same so no swapping can occur */ 369 | cg_controller = cgroup_add_controller(cg, "memory"); 370 | cgroup_add_value_int64(cg_controller, "memory.limit_in_bytes", memsize); 371 | cgroup_add_value_int64(cg_controller, "memory.memsw.limit_in_bytes", memsize); 372 | 373 | /* Set up cpu restrictions; we pin the task to a specific set of 374 | cpus. We also give it exclusive access to those cores, and set 375 | no limits on memory nodes */ 376 | if ( cpuset!=NULL && strlen(cpuset)>0 ) { 377 | cg_controller = cgroup_add_controller(cg, "cpuset"); 378 | /* To make a cpuset exclusive, some additional setup outside of domjudge is 379 | required, so for now, we will leave this commented out. */ 380 | /* cgroup_add_value_int64(cg_controller, "cpuset.cpu_exclusive", 1); */ 381 | cgroup_add_value_string(cg_controller, "cpuset.mems", "0"); 382 | cgroup_add_value_string(cg_controller, "cpuset.cpus", cpuset); 383 | } else { 384 | verbose("cpuset undefined"); 385 | } 386 | 387 | /* Perform the actual creation of the cgroup */ 388 | ret = cgroup_create_cgroup(cg, 1); 389 | if ( ret!=0 ) { 390 | error(0,"creating cgroup: %s(%d)", cgroup_strerror(ret), ret); 391 | } 392 | 393 | cgroup_free(&cg); 394 | } 395 | 396 | void cgroup_attach() 397 | { 398 | int ret; 399 | struct cgroup *cg; 400 | 401 | cg = cgroup_new_cgroup(cgroupname); 402 | if (!cg) { 403 | error(0,"cgroup_new_cgroup"); 404 | } 405 | ret = cgroup_get_cgroup(cg); 406 | if ( ret!=0 ) { 407 | error(0,"get cgroup information: %s(%d)", cgroup_strerror(ret), ret); 408 | } 409 | 410 | /* Attach task to the cgroup */ 411 | ret = cgroup_attach_task(cg); 412 | if ( ret!=0 ) { 413 | error(0,"attach task to cgroup: %s(%d)", cgroup_strerror(ret), ret); 414 | } 415 | 416 | cgroup_free(&cg); 417 | } 418 | 419 | void cgroup_delete() 420 | { 421 | int ret; 422 | struct cgroup *cg; 423 | 424 | cg = cgroup_new_cgroup(cgroupname); 425 | if (!cg) { 426 | error(0,"cgroup_new_cgroup"); 427 | } 428 | ret = cgroup_get_cgroup(cg); 429 | if ( ret!=0 ) { 430 | error(0,"get cgroup information: %s(%d)", cgroup_strerror(ret), ret); 431 | } 432 | /* Clean up our cgroup */ 433 | ret = cgroup_delete_cgroup(cg, 1); 434 | if ( ret!=0 ) { 435 | error(0,"deleting cgroup: %s(%d)", cgroup_strerror(ret), ret); 436 | } 437 | cgroup_free(&cg); 438 | } 439 | #endif // USE_CGROUPS 440 | 441 | void terminate(int sig) 442 | { 443 | struct sigaction sigact; 444 | 445 | /* Reset signal handlers to default */ 446 | sigact.sa_handler = SIG_DFL; 447 | sigact.sa_flags = 0; 448 | if ( sigemptyset(&sigact.sa_mask)!=0 ) { 449 | warning("could not initialize signal mask"); 450 | } 451 | if ( sigaction(SIGTERM,&sigact,NULL)!=0 ) { 452 | warning("could not restore signal handler"); 453 | } 454 | if ( sigaction(SIGALRM,&sigact,NULL)!=0 ) { 455 | warning("could not restore signal handler"); 456 | } 457 | 458 | if ( sig==SIGALRM ) { 459 | warning("timelimit exceeded (wall time): aborting command"); 460 | } else { 461 | warning("received signal %d: aborting command",sig); 462 | } 463 | 464 | /* First try to kill graciously, then hard */ 465 | verbose("sending SIGTERM"); 466 | if ( kill(-child_pid,SIGTERM)!=0 ) error(errno,"sending SIGTERM to command"); 467 | 468 | /* Prefer nanosleep over sleep because of higher resolution and 469 | it does not interfere with signals. */ 470 | nanosleep(&killdelay,NULL); 471 | 472 | verbose("sending SIGKILL"); 473 | if ( kill(-child_pid,SIGKILL)!=0 ) error(errno,"sending SIGKILL to command"); 474 | 475 | /* Wait another while to make sure the process is killed by now. */ 476 | nanosleep(&killdelay,NULL); 477 | } 478 | 479 | static void child_handler(int sig) 480 | { 481 | received_SIGCHLD = 1; 482 | } 483 | 484 | int userid(char *name) 485 | { 486 | struct passwd *pwd; 487 | 488 | errno = 0; /* per the linux GETPWNAM(3) man-page */ 489 | pwd = getpwnam(name); 490 | 491 | if ( pwd==NULL || errno ) return -1; 492 | 493 | return (int) pwd->pw_uid; 494 | } 495 | 496 | int groupid(char *name) 497 | { 498 | struct group *grp; 499 | 500 | errno = 0; /* per the linux GETGRNAM(3) man-page */ 501 | grp = getgrnam(name); 502 | 503 | if ( grp==NULL || errno ) return -1; 504 | 505 | return (int) grp->gr_gid; 506 | } 507 | 508 | long readoptarg(const char *desc, long minval, long maxval) 509 | { 510 | long arg; 511 | char *ptr; 512 | 513 | arg = strtol(optarg,&ptr,10); 514 | if ( errno || *ptr!='\0' || argmaxval ) { 515 | error(errno,"invalid %s specified: `%s'",desc,optarg); 516 | } 517 | 518 | return arg; 519 | } 520 | 521 | void setrestrictions() 522 | { 523 | char* savedEnvironmentVariables[] = {"PATH", "LANG", "LC_ALL", "LC_COLLATE", 524 | "LC_CTYPE", "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME"}; 525 | char* savedValues[sizeof(savedEnvironmentVariables) / sizeof(char*)]; 526 | int numSavedVariables = sizeof(savedEnvironmentVariables) / sizeof(char*); 527 | char cwd[PATH_MAX+1]; 528 | char* path = NULL; 529 | int i; 530 | 531 | struct rlimit lim; 532 | 533 | /* Clear environment to prevent all kinds of security holes, save PATH */ 534 | /* RJL: Changed to save and restore all standard locale variables */ 535 | //path = getenv("PATH"); 536 | for (i = 0; i < numSavedVariables; i++) { 537 | savedValues[i] = getenv(savedEnvironmentVariables[i]); 538 | } 539 | environ[0] = NULL; 540 | /* FIXME: Clean path before setting it again? */ 541 | //if ( path!=NULL ) setenv("PATH",path,1); 542 | for (i = 0; i < numSavedVariables; i++) { 543 | if (savedValues[i] != NULL) { 544 | setenv(savedEnvironmentVariables[i], savedValues[i], 1); 545 | } 546 | } 547 | 548 | /* Set resource limits: must be root to raise hard limits. 549 | Note that limits can thus be raised from the systems defaults! */ 550 | 551 | /* First define shorthand macro function */ 552 | #define setlim(type) \ 553 | if ( setrlimit(RLIMIT_ ## type, &lim)!=0 ) { \ 554 | if ( errno==EPERM ) { \ 555 | warning("no permission to set resource RLIMIT_" #type); \ 556 | } else { \ 557 | error(errno,"setting resource RLIMIT_" #type); \ 558 | } \ 559 | } 560 | 561 | if ( use_cputime ) { 562 | rlim_t cputime_limit = (rlim_t)cputime + 1; 563 | verbose("setting CPU-time limit to %d seconds",(int)cputime_limit); 564 | lim.rlim_cur = lim.rlim_max = cputime_limit; 565 | setlim(CPU); 566 | } 567 | 568 | /* Memory limits may be handled by cgroups now */ 569 | #ifndef USE_CGROUPS 570 | if ( memsize!=RLIM_INFINITY ) { 571 | verbose("setting memory limits to %d bytes",(int)memsize); 572 | lim.rlim_cur = lim.rlim_max = memsize; 573 | setlim(AS); 574 | /* Commented out the next 2 lines - they cause problems 575 | for multithreaded applications and don't add much 576 | security. 577 | setlim(DATA); 578 | setlim(STACK);*/ 579 | } 580 | #else 581 | /* Memory limits should be unlimited when using cgroups */ 582 | lim.rlim_cur = lim.rlim_max = RLIM_INFINITY; 583 | setlim(AS); 584 | setlim(DATA); 585 | setlim(STACK); 586 | #endif 587 | 588 | if ( filesize!=RLIM_INFINITY ) { 589 | verbose("setting filesize limit to %d bytes",(int)filesize); 590 | lim.rlim_cur = lim.rlim_max = filesize; 591 | setlim(FSIZE); 592 | } 593 | 594 | if ( nproc!=RLIM_INFINITY ) { 595 | verbose("setting process limit to %d",(int)nproc); 596 | lim.rlim_cur = lim.rlim_max = nproc; 597 | setlim(NPROC); 598 | } 599 | 600 | #undef setlim 601 | 602 | if ( no_coredump ) { 603 | verbose("disabling core dumps"); 604 | lim.rlim_cur = lim.rlim_max = 0; 605 | if ( setrlimit(RLIMIT_CORE,&lim)!=0 ) error(errno,"disabling core dumps"); 606 | } 607 | 608 | /* Set root-directory and change directory to there. */ 609 | if ( use_root ) { 610 | /* Small security issue: when running setuid-root, people can find 611 | out which directories exist from error message. */ 612 | if ( chdir(rootdir)!=0 ) error(errno,"cannot chdir to `%s'",rootdir); 613 | 614 | /* Get absolute pathname of rootdir, by reading it. */ 615 | if ( getcwd(cwd,PATH_MAX)==NULL ) error(errno,"cannot get directory"); 616 | if ( cwd[strlen(cwd)-1]!='/' ) strcat(cwd,"/"); 617 | 618 | /* Canonicalize CHROOT_PREFIX. */ 619 | if ( (path = (char *) malloc(PATH_MAX+1))==NULL ) { 620 | error(errno,"allocating memory"); 621 | } 622 | if ( realpath(CHROOT_PREFIX,path)==NULL ) { 623 | error(errno,"cannot canonicalize path '%s'",CHROOT_PREFIX); 624 | } 625 | 626 | /* Check that we are within prescribed path. */ 627 | if ( strncmp(cwd,path,strlen(path))!=0 ) { 628 | error(0,"invalid root: must be within `%s'",path); 629 | } 630 | free(path); 631 | 632 | if ( chroot(".")!=0 ) error(errno,"cannot change root to `%s'",cwd); 633 | /* Just to make sure and satisfy Coverity scan: */ 634 | if ( chdir("/")!=0 ) error(errno,"cannot chdir to `/' in chroot"); 635 | verbose("using root-directory `%s'",cwd); 636 | } 637 | 638 | /* Set group-id (must be root for this, so before setting user). */ 639 | if ( use_group ) { 640 | if ( setgid(rungid) ) error(errno,"cannot set group ID to `%d'",rungid); 641 | verbose("using group ID `%d'",rungid); 642 | gid_t aux_groups[] = {rungid}; 643 | if (setgroups(1, aux_groups)) error(errno, "cannot clear auxiliary groups"); 644 | } 645 | /* Set user-id (must be root for this). */ 646 | if ( use_user ) { 647 | if ( setuid(runuid) ) error(errno,"cannot set user ID to `%d'",runuid); 648 | verbose("using user ID `%d' for command",runuid); 649 | } else { 650 | /* Permanently reset effective uid to real uid, to prevent 651 | child command from having root privileges. 652 | Note that this means that the child runs as the same user 653 | as the watchdog process and can thus manipulate it, e.g. by 654 | sending SIGSTOP/SIGCONT! */ 655 | if ( setuid(getuid()) ) error(errno,"cannot reset real user ID"); 656 | verbose("reset user ID to `%d' for command",getuid()); 657 | } 658 | 659 | // if ( geteuid()==0 || getuid()==0 ) error(0,"root privileges not dropped. Do not run judgedaemon as root."); 660 | } 661 | 662 | int main(int argc, char **argv) 663 | { 664 | sigset_t sigmask, emptymask; 665 | fd_set readfds; 666 | pid_t pid; 667 | int i, r, nfds; 668 | #ifdef USE_CGROUPS 669 | int ret; 670 | #endif 671 | int status; 672 | int exitcode; 673 | char *valid_users; 674 | char *ptr; 675 | int opt; 676 | double timediff, tmpd; 677 | size_t data_passed[3]; 678 | ssize_t nread, nwritten; 679 | 680 | struct itimerval itimer; 681 | struct sigaction sigact; 682 | 683 | progname = argv[0]; 684 | 685 | /* Parse command-line options */ 686 | use_root = use_time = use_cputime = use_user = outputexit = outputtime = no_coredump = 0; 687 | memsize = filesize = nproc = RLIM_INFINITY; 688 | redir_stdout = redir_stderr = limit_streamsize = 0; 689 | be_verbose = be_quiet = 0; 690 | show_help = show_version = 0; 691 | opterr = 0; 692 | 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 ) { 693 | switch ( opt ) { 694 | case 0: /* long-only option */ 695 | break; 696 | case 'r': /* rootdir option */ 697 | use_root = 1; 698 | rootdir = (char *) malloc(strlen(optarg)+2); 699 | strcpy(rootdir,optarg); 700 | break; 701 | case 'u': /* user option: uid or string */ 702 | use_user = 1; 703 | runuid = strtol(optarg,&ptr,10); 704 | if ( errno || *ptr!='\0' ) runuid = userid(optarg); 705 | if ( runuid<0 ) error(0,"invalid username or ID specified: `%s'",optarg); 706 | break; 707 | case 'g': /* group option: gid or string */ 708 | use_group = 1; 709 | rungid = strtol(optarg,&ptr,10); 710 | if ( errno || *ptr!='\0' ) rungid = groupid(optarg); 711 | if ( rungid<0 ) error(0,"invalid groupname or ID specified: `%s'",optarg); 712 | break; 713 | case 't': /* time option */ 714 | use_time = 1; 715 | runtime = strtod(optarg,&ptr); 716 | if ( errno || *ptr!='\0' || !finite(runtime) || runtime<=0 ) { 717 | error(errno,"invalid runtime specified: `%s'",optarg); 718 | } 719 | break; 720 | case 'C': /* CPU time option */ 721 | use_cputime = 1; 722 | cputime = strtod(optarg,&ptr); 723 | if ( errno || *ptr!='\0' || !finite(cputime) || cputime<=0 ) { 724 | error(errno,"invalid cputime specified: `%s'",optarg); 725 | } 726 | break; 727 | case 'm': /* memsize option */ 728 | memsize = (rlim_t) readoptarg("memory limit",1,LONG_MAX); 729 | /* Convert limit from kB to bytes and check for overflow */ 730 | if ( memsize!=(memsize*1024)/1024 ) { 731 | memsize = RLIM_INFINITY; 732 | } else { 733 | memsize *= 1024; 734 | } 735 | break; 736 | case 'f': /* filesize option */ 737 | filesize = (rlim_t) readoptarg("filesize limit",1,LONG_MAX); 738 | /* Convert limit from kB to bytes and check for overflow */ 739 | if ( filesize!=(filesize*1024)/1024 ) { 740 | filesize = RLIM_INFINITY; 741 | } else { 742 | filesize *= 1024; 743 | } 744 | break; 745 | case 'p': /* nproc option */ 746 | nproc = (rlim_t) readoptarg("process limit",1,LONG_MAX); 747 | break; 748 | case 'P': /* cpuset option */ 749 | #ifdef USE_CGROUPS 750 | cpuset = optarg; 751 | #else 752 | error(0,"option `-P' is only supported when compiled with cgroup support."); 753 | #endif 754 | break; 755 | case 'c': /* no-core option */ 756 | no_coredump = 1; 757 | break; 758 | case 'o': /* stdout option */ 759 | redir_stdout = 1; 760 | stdoutfilename = strdup(optarg); 761 | break; 762 | case 'e': /* stderr option */ 763 | redir_stderr = 1; 764 | stderrfilename = strdup(optarg); 765 | break; 766 | case 's': /* streamsize option */ 767 | limit_streamsize = 1; 768 | streamsize = (size_t) readoptarg("streamsize limit",0,LONG_MAX); 769 | /* Convert limit from kB to bytes and check for overflow */ 770 | if ( streamsize!=(streamsize*1024)/1024 ) { 771 | streamsize = (size_t) LONG_MAX; 772 | } else { 773 | streamsize *= 1024; 774 | } 775 | break; 776 | case 'E': /* outputexit option */ 777 | outputexit = 1; 778 | exitfilename = strdup(optarg); 779 | break; 780 | case 'T': /* outputtime option */ 781 | outputtime = 1; 782 | timefilename = strdup(optarg); 783 | break; 784 | case 'v': /* verbose option */ 785 | be_verbose = 1; 786 | break; 787 | case 'q': /* quiet option */ 788 | be_quiet = 1; 789 | break; 790 | case ':': /* getopt error */ 791 | case '?': 792 | error(0,"unknown option or missing argument `%c'",optopt); 793 | break; 794 | default: 795 | error(0,"getopt returned character code `%c' ??",(char)opt); 796 | } 797 | } 798 | 799 | if ( show_help ) usage(); 800 | if ( show_version ) version(); 801 | 802 | if ( argc<=optind ) error(0,"no command specified"); 803 | 804 | /* Command to be executed */ 805 | cmdname = argv[optind]; 806 | cmdargs = argv+optind; 807 | 808 | /* Check that new uid is in list of valid uid's. 809 | This must be done before chroot for /etc/passwd lookup. */ 810 | if ( use_user ) { 811 | valid_users = strdup(VALID_USERS); 812 | for(ptr=strtok(valid_users,","); ptr!=NULL; ptr=strtok(NULL,",")) { 813 | if ( runuid==userid(ptr) ) break; 814 | } 815 | if ( ptr==NULL || runuid<=0 ) error(0,"illegal user specified: %d",runuid); 816 | } 817 | 818 | /* Setup pipes connecting to child stdout/err streams (ignore stdin). */ 819 | for(i=1; i<=2; i++) { 820 | if ( pipe(child_pipefd[i])!=0 ) error(errno,"creating pipe for fd %d",i); 821 | } 822 | 823 | if ( sigemptyset(&emptymask)!=0 ) error(errno,"creating empty signal mask"); 824 | 825 | /* unmask all signals, except SIGCHLD: detected in pselect() below */ 826 | sigmask = emptymask; 827 | if ( sigaddset(&sigmask, SIGCHLD)!=0 ) error(errno,"setting signal mask"); 828 | if ( sigprocmask(SIG_SETMASK, &sigmask, NULL)!=0 ) { 829 | error(errno,"unmasking signals"); 830 | } 831 | 832 | /* Construct signal handler for SIGCHLD detection in pselect(). */ 833 | received_SIGCHLD = 0; 834 | sigact.sa_handler = child_handler; 835 | sigact.sa_flags = 0; 836 | sigact.sa_mask = emptymask; 837 | if ( sigaction(SIGCHLD,&sigact,NULL)!=0 ) { 838 | error(errno,"installing signal handler"); 839 | } 840 | 841 | #ifdef USE_CGROUPS 842 | /* Make libcgroup ready for use */ 843 | ret = cgroup_init(); 844 | if ( ret!=0 ) { 845 | error(0,"libcgroup initialization failed: %s(%d)\n", cgroup_strerror(ret), ret); 846 | } 847 | /* Define the cgroup name that we will use */ 848 | cgroupname = (char*)malloc(256); 849 | if ( cgroupname==NULL ) { 850 | error(errno,"allocating memory for cgroupname"); 851 | } 852 | /* Note: group names must have slashes! */ 853 | snprintf(cgroupname, 256, "/domjudge/dj_cgroup_%d/", getpid()); 854 | 855 | cgroup_create(); 856 | 857 | unshare(CLONE_FILES|CLONE_FS|CLONE_NEWIPC|CLONE_NEWNET|CLONE_NEWNS|CLONE_NEWUTS|CLONE_SYSVSEM); 858 | #endif 859 | switch ( child_pid = fork() ) { 860 | case -1: /* error */ 861 | error(errno,"cannot fork"); 862 | case 0: /* run controlled command */ 863 | /* Connect pipes to command (stdin/)stdout/stderr and close unneeded fd's */ 864 | for(i=1; i<=2; i++) { 865 | if ( dup2(child_pipefd[i][PIPE_IN],i)<0 ) { 866 | error(errno,"redirecting child fd %d",i); 867 | } 868 | if ( close(child_pipefd[i][PIPE_IN] )!=0 || 869 | close(child_pipefd[i][PIPE_OUT])!=0 ) { 870 | error(errno,"closing pipe for fd %d",i); 871 | } 872 | } 873 | 874 | /* Run the command in a separate process group so that the command 875 | and all its children can be killed off with one signal. */ 876 | if ( setsid()==-1 ) error(errno,"setsid failed"); 877 | 878 | #ifdef USE_CGROUPS 879 | /* Put the child process in the cgroup */ 880 | cgroup_attach(); 881 | #endif 882 | 883 | /* Apply all restrictions for child process. */ 884 | setrestrictions(); 885 | 886 | /* And execute child command. */ 887 | execvp(cmdname,cmdargs); 888 | error(errno,"cannot start `%s'",cmdname); 889 | 890 | default: /* become watchdog */ 891 | /* Shed privileges, only if not using a separate child uid, 892 | because in that case we may need root privileges to kill 893 | the child process. Do not use Linux specific setresuid() 894 | call with saved set-user-ID. */ 895 | if ( !use_user ) { 896 | if ( setuid(getuid())!=0 ) error(errno, "setting watchdog uid"); 897 | verbose("watchdog using user ID `%d'",getuid()); 898 | } 899 | 900 | if ( gettimeofday(&starttime,NULL) ) error(errno,"getting time"); 901 | 902 | /* Close unused file descriptors */ 903 | for(i=1; i<=2; i++) { 904 | if ( close(child_pipefd[i][PIPE_IN])!=0 ) { 905 | error(errno,"closing pipe for fd %i",i); 906 | } 907 | } 908 | 909 | /* Redirect child stdout/stderr to file */ 910 | for(i=1; i<=2; i++) { 911 | child_redirfd[i] = i; /* Default: no redirects */ 912 | data_passed[i] = 0; /* Reset data counters */ 913 | } 914 | if ( redir_stdout ) { 915 | child_redirfd[STDOUT_FILENO] = creat(stdoutfilename, S_IRUSR | S_IWUSR); 916 | if ( child_redirfd[STDOUT_FILENO]<0 ) { 917 | error(errno,"opening file '%s'",stdoutfilename); 918 | } 919 | } 920 | if ( redir_stderr ) { 921 | child_redirfd[STDERR_FILENO] = creat(stderrfilename, S_IRUSR | S_IWUSR); 922 | if ( child_redirfd[STDERR_FILENO]<0 ) { 923 | error(errno,"opening file '%s'",stderrfilename); 924 | } 925 | } 926 | 927 | if ( sigemptyset(&emptymask)!=0 ) error(errno,"creating empty signal mask"); 928 | 929 | /* Construct one-time signal handler to terminate() for TERM 930 | and ALRM signals. */ 931 | sigmask = emptymask; 932 | if ( sigaddset(&sigmask,SIGALRM)!=0 || 933 | sigaddset(&sigmask,SIGTERM)!=0 ) error(errno,"setting signal mask"); 934 | 935 | sigact.sa_handler = terminate; 936 | sigact.sa_flags = SA_RESETHAND | SA_RESTART; 937 | sigact.sa_mask = sigmask; 938 | 939 | /* Kill child command when we receive SIGTERM */ 940 | if ( sigaction(SIGTERM,&sigact,NULL)!=0 ) { 941 | error(errno,"installing signal handler"); 942 | } 943 | 944 | if ( use_time ) { 945 | /* Kill child when we receive SIGALRM */ 946 | if ( sigaction(SIGALRM,&sigact,NULL)!=0 ) { 947 | error(errno,"installing signal handler"); 948 | } 949 | 950 | /* Trigger SIGALRM via setitimer: */ 951 | itimer.it_interval.tv_sec = 0; 952 | itimer.it_interval.tv_usec = 0; 953 | itimer.it_value.tv_sec = (int) runtime; 954 | itimer.it_value.tv_usec = (int)(modf(runtime,&tmpd) * 1E6); 955 | 956 | if ( setitimer(ITIMER_REAL,&itimer,NULL)!=0 ) { 957 | error(errno,"setting timer"); 958 | } 959 | verbose("using timelimit of %.3f seconds",runtime); 960 | } 961 | 962 | if ( times(&startticks)==(clock_t) -1 ) { 963 | error(errno,"getting start clock ticks"); 964 | } 965 | 966 | /* Wait for child data or exit. */ 967 | while ( 1 ) { 968 | 969 | FD_ZERO(&readfds); 970 | nfds = -1; 971 | for(i=1; i<=2; i++) { 972 | if ( child_pipefd[i][PIPE_OUT]>=0 ) { 973 | FD_SET(child_pipefd[i][PIPE_OUT],&readfds); 974 | nfds = max(nfds,child_pipefd[i][PIPE_OUT]); 975 | } 976 | } 977 | 978 | r = pselect(nfds+1, &readfds, NULL, NULL, NULL, &emptymask); 979 | if ( r==-1 && errno!=EINTR ) error(errno,"waiting for child data"); 980 | 981 | if ( received_SIGCHLD ) { 982 | if ( (pid = wait(&status))<0 ) error(errno,"waiting on child"); 983 | if ( pid==child_pid ) break; 984 | } 985 | 986 | /* Check to see if data is available and pass it on */ 987 | for(i=1; i<=2; i++) { 988 | if ( child_pipefd[i][PIPE_OUT] != -1 && FD_ISSET(child_pipefd[i][PIPE_OUT],&readfds) ) { 989 | nread = read(child_pipefd[i][PIPE_OUT], buf, BUF_SIZE); 990 | if ( nread==-1 ) error(errno,"reading child fd %d",i); 991 | if ( nread==0 ) { 992 | /* EOF detected: close fd and indicate this with -1 */ 993 | if ( close(child_pipefd[i][PIPE_OUT])!=0 ) { 994 | error(errno,"closing pipe for fd %d",i); 995 | } 996 | child_pipefd[i][PIPE_OUT] = -1; 997 | continue; 998 | } 999 | if ( limit_streamsize && data_passed[i]+nread>=streamsize ) { 1000 | if ( data_passed[i]> /etc/apk/repositories 4 | RUN apk add --no-cache gcc mono=5.20.1.19-r1 5 | RUN mono --version 6 | 7 | COPY ./compile.sh /bin/compile.sh 8 | COPY ./run.sh /bin/run.sh 9 | 10 | RUN chmod 777 /bin/compile.sh; \ 11 | chmod 777 /bin/run.sh 12 | -------------------------------------------------------------------------------- /containers/judge-worker/csharp/compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | csc program.cs 4 | -------------------------------------------------------------------------------- /containers/judge-worker/csharp/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | chmod 777 program.exe 4 | mono program.exe 5 | -------------------------------------------------------------------------------- /containers/judge-worker/csv/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM codingblocks/judge-worker-base 2 | RUN apk update && apk add --no-cache python3 bash coreutils 3 | COPY ./compile.sh /bin/compile.sh 4 | COPY ./run.sh /bin/run.sh 5 | RUN chmod 777 /bin/compile.sh; \ 6 | chmod 777 /bin/run.sh -------------------------------------------------------------------------------- /containers/judge-worker/csv/compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | csplit run.stdin '/^|;;$/' ; tail -n +2 xx01 > ref.csv 3 | mv xx00 user.csv 4 | rm -rf x* 5 | -------------------------------------------------------------------------------- /containers/judge-worker/csv/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | python3 script.py user.csv ref.csv 3 | -------------------------------------------------------------------------------- /containers/judge-worker/golang/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM codingblocks/judge-worker-base 2 | 3 | RUN apk add --no-cache musl-dev bash go 4 | 5 | COPY ./compile.sh /bin/compile.sh 6 | COPY ./run.sh /bin/run.sh 7 | 8 | RUN chmod 777 /bin/compile.sh; \ 9 | chmod 777 /bin/run.sh 10 | -------------------------------------------------------------------------------- /containers/judge-worker/golang/compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | go build -buildmode=exe -o main 3 | -------------------------------------------------------------------------------- /containers/judge-worker/golang/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | chmod 777 main 4 | ./main 5 | -------------------------------------------------------------------------------- /containers/judge-worker/java/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM codingblocks/judge-worker-base 2 | 3 | RUN apk add --no-cache openjdk8 bash 4 | ENV PATH="/usr/lib/jvm/java-1.8-openjdk/bin:${PATH}" 5 | 6 | COPY ./compile.sh /bin/compile.sh 7 | COPY ./run.sh /bin/run.sh 8 | 9 | RUN chmod 777 /bin/compile.sh; \ 10 | chmod 777 /bin/run.sh 11 | -------------------------------------------------------------------------------- /containers/judge-worker/java/compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | javac Main.java 4 | -------------------------------------------------------------------------------- /containers/judge-worker/java/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | java Main 4 | -------------------------------------------------------------------------------- /containers/judge-worker/java8/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM codingblocks/judge-worker-base 2 | 3 | RUN apk add --no-cache openjdk8 bash 4 | ENV PATH="/usr/lib/jvm/java-1.8-openjdk/bin:${PATH}" 5 | 6 | COPY ./compile.sh /bin/compile.sh 7 | COPY ./run.sh /bin/run.sh 8 | 9 | RUN chmod 777 /bin/compile.sh; \ 10 | chmod 777 /bin/run.sh 11 | -------------------------------------------------------------------------------- /containers/judge-worker/java8/compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | javac Main.java 4 | -------------------------------------------------------------------------------- /containers/judge-worker/java8/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | java Main 4 | -------------------------------------------------------------------------------- /containers/judge-worker/kotlin/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM codingblocks/judge-worker-base 2 | 3 | RUN apk add --no-cache openjdk8 bash 4 | ENV PATH="/usr/lib/jvm/java-1.8-openjdk/bin:${PATH}" 5 | 6 | RUN apk add --no-cache bash && \ 7 | apk add --no-cache -t build-dependencies wget && \ 8 | cd /usr/lib && \ 9 | wget https://github.com/JetBrains/kotlin/releases/download/v1.2.70-eap-4/kotlin-compiler-1.2.70-eap-4.zip && \ 10 | unzip kotlin-compiler-*.zip && \ 11 | rm kotlin-compiler-*.zip && \ 12 | rm kotlinc/bin/*.bat && \ 13 | apk del --no-cache build-dependencies 14 | ENV PATH=$PATH:/usr/lib/kotlinc/bin 15 | 16 | COPY ./compile.sh /bin/compile.sh 17 | COPY ./run.sh /bin/run.sh 18 | 19 | RUN chmod 777 /bin/compile.sh; \ 20 | chmod 777 /bin/run.sh 21 | -------------------------------------------------------------------------------- /containers/judge-worker/kotlin/compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | kotlinc Main.kt -include-runtime -d Main.jar 4 | -------------------------------------------------------------------------------- /containers/judge-worker/kotlin/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | java -jar Main.jar 4 | -------------------------------------------------------------------------------- /containers/judge-worker/mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM codingblocks/judge-worker-base 2 | 3 | # Install bash, Node.js, and MySQL 4 | RUN apk add --no-cache bash 5 | 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 6 | 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 7 | 8 | # Initialize MySQL data directory 9 | RUN mkdir -p /run/mysqld && \ 10 | chown -R mysql:mysql /run/mysqld && \ 11 | mysql_install_db --user=mysql --datadir=/var/lib/mysql 12 | 13 | # so that mysql starts on port 3306 (default port) 14 | # this line comments `skip-networking` line in the below file 15 | # if we do not comment this `skip-networking`, mysql server will start on port 0 16 | RUN sed -i '/skip-networking/d' /etc/my.cnf.d/mariadb-server.cnf 17 | 18 | # Copy the custom script and make it executable 19 | COPY ./compile.sh /bin/compile.sh 20 | COPY ./pre-run /bin/pre-run 21 | COPY ./run.sh /bin/run.sh 22 | 23 | RUN chmod 777 /bin/compile.sh; \ 24 | chmod 777 /bin/run.sh 25 | 26 | RUN npm install --prefix /bin/pre-run 27 | -------------------------------------------------------------------------------- /containers/judge-worker/mysql/compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | -------------------------------------------------------------------------------- /containers/judge-worker/mysql/pre-run/index.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql2/promise'); 2 | 3 | const TESTCASE = process.argv[2]; 4 | const SOURCE = process.argv[3]; 5 | 6 | const init = async () => { 7 | let connection; 8 | try { 9 | connection = await mysql.createConnection({ 10 | host: process.env.DB_HOST, 11 | user: process.env.DB_USER, 12 | database: process.env.DB_NAME, 13 | password: process.env.DB_PASSWORD, 14 | multipleStatements: true, 15 | }) 16 | 17 | await connection.query(TESTCASE); 18 | const [result] = await connection.query(SOURCE); 19 | console.log(JSON.stringify(result)); 20 | 21 | } catch(err) { 22 | console.error(err.sqlMessage ? err.sqlMessage: 'Something went wrong.') 23 | } 24 | if (connection) { 25 | connection.destroy(); 26 | } 27 | } 28 | 29 | init(); -------------------------------------------------------------------------------- /containers/judge-worker/mysql/pre-run/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pre-run", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "aws-ssl-profiles": { 8 | "version": "1.1.2", 9 | "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", 10 | "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==" 11 | }, 12 | "denque": { 13 | "version": "2.1.0", 14 | "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", 15 | "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" 16 | }, 17 | "generate-function": { 18 | "version": "2.3.1", 19 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", 20 | "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", 21 | "requires": { 22 | "is-property": "^1.0.2" 23 | } 24 | }, 25 | "iconv-lite": { 26 | "version": "0.6.3", 27 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 28 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 29 | "requires": { 30 | "safer-buffer": ">= 2.1.2 < 3.0.0" 31 | } 32 | }, 33 | "is-property": { 34 | "version": "1.0.2", 35 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 36 | "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" 37 | }, 38 | "long": { 39 | "version": "5.2.4", 40 | "resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz", 41 | "integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==" 42 | }, 43 | "lru-cache": { 44 | "version": "7.18.3", 45 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", 46 | "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" 47 | }, 48 | "lru.min": { 49 | "version": "1.1.1", 50 | "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.1.tgz", 51 | "integrity": "sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==" 52 | }, 53 | "mysql2": { 54 | "version": "3.12.0", 55 | "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.12.0.tgz", 56 | "integrity": "sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==", 57 | "requires": { 58 | "aws-ssl-profiles": "^1.1.1", 59 | "denque": "^2.1.0", 60 | "generate-function": "^2.3.1", 61 | "iconv-lite": "^0.6.3", 62 | "long": "^5.2.1", 63 | "lru.min": "^1.0.0", 64 | "named-placeholders": "^1.1.3", 65 | "seq-queue": "^0.0.5", 66 | "sqlstring": "^2.3.2" 67 | } 68 | }, 69 | "named-placeholders": { 70 | "version": "1.1.3", 71 | "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", 72 | "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", 73 | "requires": { 74 | "lru-cache": "^7.14.1" 75 | } 76 | }, 77 | "safer-buffer": { 78 | "version": "2.1.2", 79 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 80 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 81 | }, 82 | "seq-queue": { 83 | "version": "0.0.5", 84 | "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", 85 | "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" 86 | }, 87 | "sqlstring": { 88 | "version": "2.3.3", 89 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", 90 | "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /containers/judge-worker/mysql/pre-run/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pre-run", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "mysql2": "^3.12.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /containers/judge-worker/mysql/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # redirecting logs 4 | mysqld --user=mysql > /var/log/mysql.log 2>&1 & 5 | 6 | # wait for mysql server to start 7 | while ! mysqladmin ping --silent > /dev/null 2>&1; do 8 | sleep 1 9 | done 10 | 11 | DB_NAME="mydatabase" 12 | DB_USER="myuser" 13 | DB_PASSWORD="mypassword" 14 | DB_HOST="localhost" 15 | 16 | # setup database for the queries to execute 17 | SETUP_DATABASE_COMMANDS=" 18 | CREATE DATABASE IF NOT EXISTS $DB_NAME; 19 | CREATE USER IF NOT EXISTS '$DB_USER'@'$DB_HOST' IDENTIFIED BY '$DB_PASSWORD'; 20 | GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'$DB_HOST'; 21 | FLUSH PRIVILEGES;" 22 | 23 | mysql -e "$SETUP_DATABASE_COMMANDS" 24 | 25 | # store the contents of testcase in the variable 26 | TESTCASE=$(cat) 27 | SOURCE=$( {rootDir}/setup.stdout 2> {rootDir}/setup.stderr', shell=True) 12 | open(f'{rootDir}/setup.code', 'w').write(str(return_code)) 13 | if return_code: 14 | sys.exit(return_code) 15 | 16 | def runTestcases(rootDir, scripts, timeout): 17 | os.mkdir(f'{rootDir}/result') 18 | for i, script in enumerate(scripts): 19 | os.mkdir(f'{rootDir}/result/{i}') 20 | subprocess.call(f' \ 21 | runguard \ 22 | -t {timeout} \ 23 | -E {rootDir}/result/{i}/run.code \ 24 | -T {rootDir}/result/{i}/run.time \ 25 | {script} 1> {rootDir}/result/{i}/run.stdout 2> {rootDir}/result/{i}/run.stderr \ 26 | ', shell=True) 27 | 28 | def main(timeout): 29 | rootDir = os.getcwd() 30 | os.chdir('project') 31 | 32 | with open(f'{rootDir}/project.yml', 'r') as file: 33 | config = yaml.full_load(file) 34 | 35 | beforeInstall(rootDir, config['project']['before-test']) 36 | runTestcases(rootDir, config['project']['testcases'], timeout) 37 | 38 | if __name__ == '__main__': 39 | parser = argparse.ArgumentParser() 40 | 41 | parser.add_argument( 42 | '-t', 43 | '--timeout', 44 | help='Timeout for the Code Run', 45 | default=20 46 | ) 47 | 48 | args = parser.parse_args() 49 | timeout = args.timeout 50 | main(timeout) 51 | -------------------------------------------------------------------------------- /containers/project-worker/base/runguard/runguard-config.h: -------------------------------------------------------------------------------- 1 | /* Runguard config for use with CodeRunner. Includes all necessary 2 | * DOMJudge constants from config.h. 3 | * Assumes all tests will be done as the Linux user "coderunner". 4 | * It is assumed CHROOT will not be used so the CHROOT_PREFIX 5 | * is not meaningfully set. 6 | */ 7 | 8 | #ifndef _RUNGUARD_CONFIG_ 9 | #define _RUNGUARD_CONFIG_ 10 | 11 | #define DOMJUDGE_VERSION "3" 12 | #define REVISION "3.3" 13 | 14 | #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" 15 | 16 | #define CHROOT_PREFIX "/var/www/jobe/chrootjail" 17 | 18 | #endif /* _RUNGUARD_CONFIG_ */ 19 | -------------------------------------------------------------------------------- /containers/project-worker/base/runguard/runguard.c: -------------------------------------------------------------------------------- 1 | /* 2 | runguard -- run command with restrictions. 3 | Copyright (C) 2004-2013 Jaap Eldering (eldering@a-eskwadraat.nl) 4 | Copyright (C) 2013 Keith Johnson 5 | 6 | Multiple minor improvements ported from the DOMjudge-ETH tree. 7 | 8 | Based on an idea from the timeout program, written by Wietse Venema 9 | as part of The Coroner's Toolkit. 10 | 11 | This program is free software; you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation; either version 2, or (at your option) 14 | any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with this program; if not, write to the Free Software Foundation, 23 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 24 | 25 | 26 | Program specifications: 27 | 28 | This program will run the specified command in a separate process 29 | group (session) and apply the restrictions as specified after 30 | forking, before executing the command. 31 | 32 | The stdin and stdout streams are passed to the command and runguard 33 | does not read or write to these. Error and verbose messages from 34 | runguard are by default written to stderr, hence mixed with stderr 35 | output of the command, unless that is optionally redirected to file. 36 | 37 | The command and its children are sent a SIGTERM after the runtime 38 | has passed, followed by a SIGKILL after 'killdelay'. 39 | */ 40 | 41 | /* Some system/site specific config: VALID_USERS, CHROOT_PREFIX */ 42 | #include "runguard-config.h" 43 | 44 | /* For chroot(), which is not POSIX. */ 45 | #define _DEFAULT_SOURCE 46 | /* For unshare(), only used when cgroups are enabled */ 47 | #if ( USE_CGROUPS == 1 ) 48 | #define _GNU_SOURCE 49 | #endif 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #if ( USE_CGROUPS == 1 ) 74 | #include 75 | #include 76 | #include 77 | #else 78 | #undef USE_CGROUPS 79 | #endif 80 | 81 | #define PROGRAM "runguard" 82 | #define VERSION DOMJUDGE_VERSION "/" REVISION 83 | #define AUTHORS "Jaap Eldering" 84 | 85 | #define max(x,y) ((x) > (y) ? (x) : (y)) 86 | 87 | /* Array indices for input/output file descriptors as used by pipe() */ 88 | #define PIPE_IN 1 89 | #define PIPE_OUT 0 90 | 91 | #define BUF_SIZE 4*1024 92 | char buf[BUF_SIZE]; 93 | 94 | const struct timespec killdelay = { 0, 100000000L }; /* 0.1 seconds */ 95 | 96 | extern int errno; 97 | 98 | #ifndef _GNU_SOURCE 99 | extern char **environ; 100 | #endif 101 | 102 | const int exit_failure = -1; 103 | 104 | char *progname; 105 | char *cmdname; 106 | char **cmdargs; 107 | char *rootdir; 108 | char *stdoutfilename; 109 | char *stderrfilename; 110 | char *exitfilename; 111 | char *timefilename; 112 | #ifdef USE_CGROUPS 113 | char *cgroupname; 114 | const char *cpuset; 115 | #endif 116 | 117 | int runuid; 118 | int rungid; 119 | int use_root; 120 | int use_time; 121 | int use_cputime; 122 | int use_user; 123 | int use_group; 124 | int redir_stdout; 125 | int redir_stderr; 126 | int limit_streamsize; 127 | int outputexit; 128 | int outputtime; 129 | int no_coredump; 130 | int be_verbose; 131 | int be_quiet; 132 | int show_help; 133 | int show_version; 134 | 135 | double runtime, cputime; /* in seconds */ 136 | #ifdef USE_CGROUPS 137 | int64_t memsize; 138 | #else 139 | rlim_t memsize; 140 | #endif 141 | rlim_t filesize; 142 | rlim_t nproc; 143 | size_t streamsize; 144 | 145 | pid_t child_pid; 146 | 147 | static volatile sig_atomic_t received_SIGCHLD = 0; 148 | 149 | FILE *child_stdout; 150 | FILE *child_stderr; 151 | int child_pipefd[3][2]; 152 | int child_redirfd[3]; 153 | 154 | struct timeval starttime, endtime; 155 | struct tms startticks, endticks; 156 | 157 | struct option const long_opts[] = { 158 | {"root", required_argument, NULL, 'r'}, 159 | {"user", required_argument, NULL, 'u'}, 160 | {"group", required_argument, NULL, 'g'}, 161 | {"time", required_argument, NULL, 't'}, 162 | {"cputime", required_argument, NULL, 'C'}, 163 | {"memsize", required_argument, NULL, 'm'}, 164 | {"filesize", required_argument, NULL, 'f'}, 165 | {"nproc", required_argument, NULL, 'p'}, 166 | {"cpuset", required_argument, NULL, 'P'}, 167 | {"no-core", no_argument, NULL, 'c'}, 168 | {"stdout", required_argument, NULL, 'o'}, 169 | {"stderr", required_argument, NULL, 'e'}, 170 | {"streamsize", required_argument, NULL, 's'}, 171 | {"outexit", required_argument, NULL, 'E'}, 172 | {"outtime", required_argument, NULL, 'T'}, 173 | {"verbose", no_argument, NULL, 'v'}, 174 | {"quiet", no_argument, NULL, 'q'}, 175 | {"help", no_argument, &show_help, 1 }, 176 | {"version", no_argument, &show_version, 1 }, 177 | { NULL, 0, NULL, 0 } 178 | }; 179 | 180 | void warning( const char *, ...) __attribute__((format (printf, 1, 2))); 181 | void verbose( const char *, ...) __attribute__((format (printf, 1, 2))); 182 | void error(int, const char *, ...) __attribute__((format (printf, 2, 3))); 183 | 184 | void warning(const char *format, ...) 185 | { 186 | va_list ap; 187 | va_start(ap,format); 188 | 189 | if ( ! be_quiet ) { 190 | fprintf(stderr,"%s: warning: ",progname); 191 | vfprintf(stderr,format,ap); 192 | fprintf(stderr,"\n"); 193 | } 194 | 195 | va_end(ap); 196 | } 197 | 198 | void verbose(const char *format, ...) 199 | { 200 | va_list ap; 201 | va_start(ap,format); 202 | 203 | if ( ! be_quiet && be_verbose ) { 204 | fprintf(stderr,"%s: verbose: ",progname); 205 | vfprintf(stderr,format,ap); 206 | fprintf(stderr,"\n"); 207 | } 208 | 209 | va_end(ap); 210 | } 211 | 212 | void error(int errnum, const char *format, ...) 213 | { 214 | va_list ap; 215 | va_start(ap,format); 216 | 217 | fprintf(stderr,"%s",progname); 218 | 219 | if ( format!=NULL ) { 220 | fprintf(stderr,": "); 221 | vfprintf(stderr,format,ap); 222 | } 223 | if ( errnum!=0 ) { 224 | fprintf(stderr,": %s",strerror(errnum)); 225 | } 226 | if ( format==NULL && errnum==0 ) { 227 | fprintf(stderr,": unknown error"); 228 | } 229 | 230 | fprintf(stderr,"\nTry `%s --help' for more information.\n",progname); 231 | va_end(ap); 232 | 233 | exit(exit_failure); 234 | } 235 | 236 | void version() 237 | { 238 | printf("\ 239 | %s -- version %s\n\ 240 | Written by %s\n\n\ 241 | %s comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n\ 242 | are welcome to redistribute it under certain conditions. See the GNU\n\ 243 | General Public Licence for details.\n",PROGRAM,VERSION,AUTHORS,PROGRAM); 244 | exit(0); 245 | } 246 | 247 | void usage() 248 | { 249 | printf("\ 250 | Usage: %s [OPTION]... COMMAND...\n\ 251 | Run COMMAND with restrictions.\n\ 252 | \n", progname); 253 | printf("\ 254 | -r, --root=ROOT run COMMAND with root directory set to ROOT\n\ 255 | -u, --user=USER run COMMAND as user with username or ID USER\n\ 256 | -g, --group=GROUP run COMMAND under group with name or ID GROUP\n\ 257 | -t, --time=TIME kill COMMAND after TIME seconds (float)\n\ 258 | -C, --cputime=TIME set maximum CPU time to TIME seconds (float)\n\ 259 | -m, --memsize=SIZE set all (total, stack, etc) memory limits to SIZE kB\n\ 260 | -f, --filesize=SIZE set maximum created filesize to SIZE kB;\n"); 261 | printf("\ 262 | -p, --nproc=N set maximum no. processes to N\n\ 263 | -P, --cpuset=ID use only processor number ID\n\ 264 | -c, --no-core disable core dumps\n\ 265 | -o, --stdout=FILE redirect COMMAND stdout output to FILE\n\ 266 | -e, --stderr=FILE redirect COMMAND stderr output to FILE\n\ 267 | -s, --streamsize=SIZE truncate COMMAND stdout/stderr streams at SIZE kB\n\ 268 | -E, --outexit=FILE write COMMAND exitcode to FILE\n\ 269 | -T, --outtime=FILE write COMMAND runtime to FILE\n"); 270 | printf("\ 271 | -v, --verbose display some extra warnings and information\n\ 272 | -q, --quiet suppress all warnings and verbose output\n\ 273 | --help display this help and exit\n\ 274 | --version output version information and exit\n"); 275 | printf("\n\ 276 | Note that root privileges are needed for the `root' and `user' options.\n\ 277 | The COMMAND path is relative to the changed ROOT directory if specified.\n\ 278 | When run setuid without the `user' option, the user ID is set to the\n\ 279 | real user ID.\n"); 280 | exit(0); 281 | } 282 | 283 | void output_exit_time(int exitcode, double timediff) 284 | { 285 | FILE *outputfile; 286 | double userdiff, sysdiff; 287 | unsigned long ticks_per_second = sysconf(_SC_CLK_TCK); 288 | 289 | verbose("command exited with exitcode %d",exitcode); 290 | 291 | if ( outputexit ) { 292 | verbose("writing exitcode to file `%s'",exitfilename); 293 | 294 | if ( (outputfile = fopen(exitfilename,"w"))==NULL ) { 295 | error(errno,"cannot open `%s'",exitfilename); 296 | } 297 | if ( fprintf(outputfile,"%d\n",exitcode)==0 ) { 298 | error(0,"cannot write to file `%s'",exitfilename); 299 | } 300 | if ( fclose(outputfile) ) { 301 | error(errno,"closing file `%s'",exitfilename); 302 | } 303 | } 304 | 305 | userdiff = (double)(endticks.tms_cutime - startticks.tms_cutime) / ticks_per_second; 306 | sysdiff = (double)(endticks.tms_cstime - startticks.tms_cstime) / ticks_per_second; 307 | 308 | verbose("runtime is %.3f seconds real, %.3f user, %.3f sys", 309 | timediff, userdiff, sysdiff); 310 | 311 | if ( use_cputime && (userdiff+sysdiff) > cputime ) { 312 | warning("timelimit exceeded (cpu time)"); 313 | } 314 | 315 | if ( outputtime ) { 316 | verbose("writing runtime to file `%s'",timefilename); 317 | 318 | if ( (outputfile = fopen(timefilename,"w"))==NULL ) { 319 | error(errno,"cannot open `%s'",timefilename); 320 | } 321 | if ( fprintf(outputfile,"%.3f\n",userdiff+sysdiff)==0 ) { 322 | error(0,"cannot write to file `%s'",timefilename); 323 | } 324 | if ( fclose(outputfile) ) { 325 | error(errno,"closing file `%s'",timefilename); 326 | } 327 | } 328 | } 329 | 330 | #ifdef USE_CGROUPS 331 | void output_cgroup_stats() 332 | { 333 | int ret; 334 | int64_t max_usage; 335 | struct cgroup *cg; 336 | struct cgroup_controller *cg_controller; 337 | 338 | cg = cgroup_new_cgroup(cgroupname); 339 | if (!cg) { 340 | error(0,"cgroup_new_cgroup"); 341 | } 342 | if ((ret = cgroup_get_cgroup(cg)) != 0) { 343 | error(0,"get cgroup information: %s(%d)", cgroup_strerror(ret), ret); 344 | } 345 | cg_controller = cgroup_get_controller(cg, "memory"); 346 | ret = cgroup_get_value_int64(cg_controller, "memory.memsw.max_usage_in_bytes", &max_usage); 347 | if ( ret!=0 ) { 348 | error(0,"get cgroup value: %s(%d)", cgroup_strerror(ret), ret); 349 | } 350 | 351 | verbose("total memory used: %" PRId64 " kB", max_usage/1024); 352 | 353 | cgroup_free(&cg); 354 | } 355 | 356 | void cgroup_create() 357 | { 358 | int ret; 359 | struct cgroup *cg; 360 | struct cgroup_controller *cg_controller; 361 | 362 | cg = cgroup_new_cgroup(cgroupname); 363 | if (!cg) { 364 | error(0,"cgroup_new_cgroup"); 365 | } 366 | 367 | /* Set up the memory restrictions; these two options limit ram use 368 | and ram+swap use. They are the same so no swapping can occur */ 369 | cg_controller = cgroup_add_controller(cg, "memory"); 370 | cgroup_add_value_int64(cg_controller, "memory.limit_in_bytes", memsize); 371 | cgroup_add_value_int64(cg_controller, "memory.memsw.limit_in_bytes", memsize); 372 | 373 | /* Set up cpu restrictions; we pin the task to a specific set of 374 | cpus. We also give it exclusive access to those cores, and set 375 | no limits on memory nodes */ 376 | if ( cpuset!=NULL && strlen(cpuset)>0 ) { 377 | cg_controller = cgroup_add_controller(cg, "cpuset"); 378 | /* To make a cpuset exclusive, some additional setup outside of domjudge is 379 | required, so for now, we will leave this commented out. */ 380 | /* cgroup_add_value_int64(cg_controller, "cpuset.cpu_exclusive", 1); */ 381 | cgroup_add_value_string(cg_controller, "cpuset.mems", "0"); 382 | cgroup_add_value_string(cg_controller, "cpuset.cpus", cpuset); 383 | } else { 384 | verbose("cpuset undefined"); 385 | } 386 | 387 | /* Perform the actual creation of the cgroup */ 388 | ret = cgroup_create_cgroup(cg, 1); 389 | if ( ret!=0 ) { 390 | error(0,"creating cgroup: %s(%d)", cgroup_strerror(ret), ret); 391 | } 392 | 393 | cgroup_free(&cg); 394 | } 395 | 396 | void cgroup_attach() 397 | { 398 | int ret; 399 | struct cgroup *cg; 400 | 401 | cg = cgroup_new_cgroup(cgroupname); 402 | if (!cg) { 403 | error(0,"cgroup_new_cgroup"); 404 | } 405 | ret = cgroup_get_cgroup(cg); 406 | if ( ret!=0 ) { 407 | error(0,"get cgroup information: %s(%d)", cgroup_strerror(ret), ret); 408 | } 409 | 410 | /* Attach task to the cgroup */ 411 | ret = cgroup_attach_task(cg); 412 | if ( ret!=0 ) { 413 | error(0,"attach task to cgroup: %s(%d)", cgroup_strerror(ret), ret); 414 | } 415 | 416 | cgroup_free(&cg); 417 | } 418 | 419 | void cgroup_delete() 420 | { 421 | int ret; 422 | struct cgroup *cg; 423 | 424 | cg = cgroup_new_cgroup(cgroupname); 425 | if (!cg) { 426 | error(0,"cgroup_new_cgroup"); 427 | } 428 | ret = cgroup_get_cgroup(cg); 429 | if ( ret!=0 ) { 430 | error(0,"get cgroup information: %s(%d)", cgroup_strerror(ret), ret); 431 | } 432 | /* Clean up our cgroup */ 433 | ret = cgroup_delete_cgroup(cg, 1); 434 | if ( ret!=0 ) { 435 | error(0,"deleting cgroup: %s(%d)", cgroup_strerror(ret), ret); 436 | } 437 | cgroup_free(&cg); 438 | } 439 | #endif // USE_CGROUPS 440 | 441 | void terminate(int sig) 442 | { 443 | struct sigaction sigact; 444 | 445 | /* Reset signal handlers to default */ 446 | sigact.sa_handler = SIG_DFL; 447 | sigact.sa_flags = 0; 448 | if ( sigemptyset(&sigact.sa_mask)!=0 ) { 449 | warning("could not initialize signal mask"); 450 | } 451 | if ( sigaction(SIGTERM,&sigact,NULL)!=0 ) { 452 | warning("could not restore signal handler"); 453 | } 454 | if ( sigaction(SIGALRM,&sigact,NULL)!=0 ) { 455 | warning("could not restore signal handler"); 456 | } 457 | 458 | if ( sig==SIGALRM ) { 459 | warning("timelimit exceeded (wall time): aborting command"); 460 | } else { 461 | warning("received signal %d: aborting command",sig); 462 | } 463 | 464 | /* First try to kill graciously, then hard */ 465 | verbose("sending SIGTERM"); 466 | if ( kill(-child_pid,SIGTERM)!=0 ) error(errno,"sending SIGTERM to command"); 467 | 468 | /* Prefer nanosleep over sleep because of higher resolution and 469 | it does not interfere with signals. */ 470 | nanosleep(&killdelay,NULL); 471 | 472 | verbose("sending SIGKILL"); 473 | if ( kill(-child_pid,SIGKILL)!=0 ) error(errno,"sending SIGKILL to command"); 474 | 475 | /* Wait another while to make sure the process is killed by now. */ 476 | nanosleep(&killdelay,NULL); 477 | } 478 | 479 | static void child_handler(int sig) 480 | { 481 | received_SIGCHLD = 1; 482 | } 483 | 484 | int userid(char *name) 485 | { 486 | struct passwd *pwd; 487 | 488 | errno = 0; /* per the linux GETPWNAM(3) man-page */ 489 | pwd = getpwnam(name); 490 | 491 | if ( pwd==NULL || errno ) return -1; 492 | 493 | return (int) pwd->pw_uid; 494 | } 495 | 496 | int groupid(char *name) 497 | { 498 | struct group *grp; 499 | 500 | errno = 0; /* per the linux GETGRNAM(3) man-page */ 501 | grp = getgrnam(name); 502 | 503 | if ( grp==NULL || errno ) return -1; 504 | 505 | return (int) grp->gr_gid; 506 | } 507 | 508 | long readoptarg(const char *desc, long minval, long maxval) 509 | { 510 | long arg; 511 | char *ptr; 512 | 513 | arg = strtol(optarg,&ptr,10); 514 | if ( errno || *ptr!='\0' || argmaxval ) { 515 | error(errno,"invalid %s specified: `%s'",desc,optarg); 516 | } 517 | 518 | return arg; 519 | } 520 | 521 | void setrestrictions() 522 | { 523 | char* savedEnvironmentVariables[] = {"PATH", "LANG", "LC_ALL", "LC_COLLATE", 524 | "LC_CTYPE", "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME"}; 525 | char* savedValues[sizeof(savedEnvironmentVariables) / sizeof(char*)]; 526 | int numSavedVariables = sizeof(savedEnvironmentVariables) / sizeof(char*); 527 | char cwd[PATH_MAX+1]; 528 | char* path = NULL; 529 | int i; 530 | 531 | struct rlimit lim; 532 | 533 | /* Clear environment to prevent all kinds of security holes, save PATH */ 534 | /* RJL: Changed to save and restore all standard locale variables */ 535 | //path = getenv("PATH"); 536 | for (i = 0; i < numSavedVariables; i++) { 537 | savedValues[i] = getenv(savedEnvironmentVariables[i]); 538 | } 539 | environ[0] = NULL; 540 | /* FIXME: Clean path before setting it again? */ 541 | //if ( path!=NULL ) setenv("PATH",path,1); 542 | for (i = 0; i < numSavedVariables; i++) { 543 | if (savedValues[i] != NULL) { 544 | setenv(savedEnvironmentVariables[i], savedValues[i], 1); 545 | } 546 | } 547 | 548 | /* Set resource limits: must be root to raise hard limits. 549 | Note that limits can thus be raised from the systems defaults! */ 550 | 551 | /* First define shorthand macro function */ 552 | #define setlim(type) \ 553 | if ( setrlimit(RLIMIT_ ## type, &lim)!=0 ) { \ 554 | if ( errno==EPERM ) { \ 555 | warning("no permission to set resource RLIMIT_" #type); \ 556 | } else { \ 557 | error(errno,"setting resource RLIMIT_" #type); \ 558 | } \ 559 | } 560 | 561 | if ( use_cputime ) { 562 | rlim_t cputime_limit = (rlim_t)cputime + 1; 563 | verbose("setting CPU-time limit to %d seconds",(int)cputime_limit); 564 | lim.rlim_cur = lim.rlim_max = cputime_limit; 565 | setlim(CPU); 566 | } 567 | 568 | /* Memory limits may be handled by cgroups now */ 569 | #ifndef USE_CGROUPS 570 | if ( memsize!=RLIM_INFINITY ) { 571 | verbose("setting memory limits to %d bytes",(int)memsize); 572 | lim.rlim_cur = lim.rlim_max = memsize; 573 | setlim(AS); 574 | /* Commented out the next 2 lines - they cause problems 575 | for multithreaded applications and don't add much 576 | security. 577 | setlim(DATA); 578 | setlim(STACK);*/ 579 | } 580 | #else 581 | /* Memory limits should be unlimited when using cgroups */ 582 | lim.rlim_cur = lim.rlim_max = RLIM_INFINITY; 583 | setlim(AS); 584 | setlim(DATA); 585 | setlim(STACK); 586 | #endif 587 | 588 | if ( filesize!=RLIM_INFINITY ) { 589 | verbose("setting filesize limit to %d bytes",(int)filesize); 590 | lim.rlim_cur = lim.rlim_max = filesize; 591 | setlim(FSIZE); 592 | } 593 | 594 | if ( nproc!=RLIM_INFINITY ) { 595 | verbose("setting process limit to %d",(int)nproc); 596 | lim.rlim_cur = lim.rlim_max = nproc; 597 | setlim(NPROC); 598 | } 599 | 600 | #undef setlim 601 | 602 | if ( no_coredump ) { 603 | verbose("disabling core dumps"); 604 | lim.rlim_cur = lim.rlim_max = 0; 605 | if ( setrlimit(RLIMIT_CORE,&lim)!=0 ) error(errno,"disabling core dumps"); 606 | } 607 | 608 | /* Set root-directory and change directory to there. */ 609 | if ( use_root ) { 610 | /* Small security issue: when running setuid-root, people can find 611 | out which directories exist from error message. */ 612 | if ( chdir(rootdir)!=0 ) error(errno,"cannot chdir to `%s'",rootdir); 613 | 614 | /* Get absolute pathname of rootdir, by reading it. */ 615 | if ( getcwd(cwd,PATH_MAX)==NULL ) error(errno,"cannot get directory"); 616 | if ( cwd[strlen(cwd)-1]!='/' ) strcat(cwd,"/"); 617 | 618 | /* Canonicalize CHROOT_PREFIX. */ 619 | if ( (path = (char *) malloc(PATH_MAX+1))==NULL ) { 620 | error(errno,"allocating memory"); 621 | } 622 | if ( realpath(CHROOT_PREFIX,path)==NULL ) { 623 | error(errno,"cannot canonicalize path '%s'",CHROOT_PREFIX); 624 | } 625 | 626 | /* Check that we are within prescribed path. */ 627 | if ( strncmp(cwd,path,strlen(path))!=0 ) { 628 | error(0,"invalid root: must be within `%s'",path); 629 | } 630 | free(path); 631 | 632 | if ( chroot(".")!=0 ) error(errno,"cannot change root to `%s'",cwd); 633 | /* Just to make sure and satisfy Coverity scan: */ 634 | if ( chdir("/")!=0 ) error(errno,"cannot chdir to `/' in chroot"); 635 | verbose("using root-directory `%s'",cwd); 636 | } 637 | 638 | /* Set group-id (must be root for this, so before setting user). */ 639 | if ( use_group ) { 640 | if ( setgid(rungid) ) error(errno,"cannot set group ID to `%d'",rungid); 641 | verbose("using group ID `%d'",rungid); 642 | gid_t aux_groups[] = {rungid}; 643 | if (setgroups(1, aux_groups)) error(errno, "cannot clear auxiliary groups"); 644 | } 645 | /* Set user-id (must be root for this). */ 646 | if ( use_user ) { 647 | if ( setuid(runuid) ) error(errno,"cannot set user ID to `%d'",runuid); 648 | verbose("using user ID `%d' for command",runuid); 649 | } else { 650 | /* Permanently reset effective uid to real uid, to prevent 651 | child command from having root privileges. 652 | Note that this means that the child runs as the same user 653 | as the watchdog process and can thus manipulate it, e.g. by 654 | sending SIGSTOP/SIGCONT! */ 655 | if ( setuid(getuid()) ) error(errno,"cannot reset real user ID"); 656 | verbose("reset user ID to `%d' for command",getuid()); 657 | } 658 | 659 | // if ( geteuid()==0 || getuid()==0 ) error(0,"root privileges not dropped. Do not run judgedaemon as root."); 660 | } 661 | 662 | int main(int argc, char **argv) 663 | { 664 | sigset_t sigmask, emptymask; 665 | fd_set readfds; 666 | pid_t pid; 667 | int i, r, nfds; 668 | #ifdef USE_CGROUPS 669 | int ret; 670 | #endif 671 | int status; 672 | int exitcode; 673 | char *valid_users; 674 | char *ptr; 675 | int opt; 676 | double timediff, tmpd; 677 | size_t data_passed[3]; 678 | ssize_t nread, nwritten; 679 | 680 | struct itimerval itimer; 681 | struct sigaction sigact; 682 | 683 | progname = argv[0]; 684 | 685 | /* Parse command-line options */ 686 | use_root = use_time = use_cputime = use_user = outputexit = outputtime = no_coredump = 0; 687 | memsize = filesize = nproc = RLIM_INFINITY; 688 | redir_stdout = redir_stderr = limit_streamsize = 0; 689 | be_verbose = be_quiet = 0; 690 | show_help = show_version = 0; 691 | opterr = 0; 692 | 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 ) { 693 | switch ( opt ) { 694 | case 0: /* long-only option */ 695 | break; 696 | case 'r': /* rootdir option */ 697 | use_root = 1; 698 | rootdir = (char *) malloc(strlen(optarg)+2); 699 | strcpy(rootdir,optarg); 700 | break; 701 | case 'u': /* user option: uid or string */ 702 | use_user = 1; 703 | runuid = strtol(optarg,&ptr,10); 704 | if ( errno || *ptr!='\0' ) runuid = userid(optarg); 705 | if ( runuid<0 ) error(0,"invalid username or ID specified: `%s'",optarg); 706 | break; 707 | case 'g': /* group option: gid or string */ 708 | use_group = 1; 709 | rungid = strtol(optarg,&ptr,10); 710 | if ( errno || *ptr!='\0' ) rungid = groupid(optarg); 711 | if ( rungid<0 ) error(0,"invalid groupname or ID specified: `%s'",optarg); 712 | break; 713 | case 't': /* time option */ 714 | use_time = 1; 715 | runtime = strtod(optarg,&ptr); 716 | if ( errno || *ptr!='\0' || !finite(runtime) || runtime<=0 ) { 717 | error(errno,"invalid runtime specified: `%s'",optarg); 718 | } 719 | break; 720 | case 'C': /* CPU time option */ 721 | use_cputime = 1; 722 | cputime = strtod(optarg,&ptr); 723 | if ( errno || *ptr!='\0' || !finite(cputime) || cputime<=0 ) { 724 | error(errno,"invalid cputime specified: `%s'",optarg); 725 | } 726 | break; 727 | case 'm': /* memsize option */ 728 | memsize = (rlim_t) readoptarg("memory limit",1,LONG_MAX); 729 | /* Convert limit from kB to bytes and check for overflow */ 730 | if ( memsize!=(memsize*1024)/1024 ) { 731 | memsize = RLIM_INFINITY; 732 | } else { 733 | memsize *= 1024; 734 | } 735 | break; 736 | case 'f': /* filesize option */ 737 | filesize = (rlim_t) readoptarg("filesize limit",1,LONG_MAX); 738 | /* Convert limit from kB to bytes and check for overflow */ 739 | if ( filesize!=(filesize*1024)/1024 ) { 740 | filesize = RLIM_INFINITY; 741 | } else { 742 | filesize *= 1024; 743 | } 744 | break; 745 | case 'p': /* nproc option */ 746 | nproc = (rlim_t) readoptarg("process limit",1,LONG_MAX); 747 | break; 748 | case 'P': /* cpuset option */ 749 | #ifdef USE_CGROUPS 750 | cpuset = optarg; 751 | #else 752 | error(0,"option `-P' is only supported when compiled with cgroup support."); 753 | #endif 754 | break; 755 | case 'c': /* no-core option */ 756 | no_coredump = 1; 757 | break; 758 | case 'o': /* stdout option */ 759 | redir_stdout = 1; 760 | stdoutfilename = strdup(optarg); 761 | break; 762 | case 'e': /* stderr option */ 763 | redir_stderr = 1; 764 | stderrfilename = strdup(optarg); 765 | break; 766 | case 's': /* streamsize option */ 767 | limit_streamsize = 1; 768 | streamsize = (size_t) readoptarg("streamsize limit",0,LONG_MAX); 769 | /* Convert limit from kB to bytes and check for overflow */ 770 | if ( streamsize!=(streamsize*1024)/1024 ) { 771 | streamsize = (size_t) LONG_MAX; 772 | } else { 773 | streamsize *= 1024; 774 | } 775 | break; 776 | case 'E': /* outputexit option */ 777 | outputexit = 1; 778 | exitfilename = strdup(optarg); 779 | break; 780 | case 'T': /* outputtime option */ 781 | outputtime = 1; 782 | timefilename = strdup(optarg); 783 | break; 784 | case 'v': /* verbose option */ 785 | be_verbose = 1; 786 | break; 787 | case 'q': /* quiet option */ 788 | be_quiet = 1; 789 | break; 790 | case ':': /* getopt error */ 791 | case '?': 792 | error(0,"unknown option or missing argument `%c'",optopt); 793 | break; 794 | default: 795 | error(0,"getopt returned character code `%c' ??",(char)opt); 796 | } 797 | } 798 | 799 | if ( show_help ) usage(); 800 | if ( show_version ) version(); 801 | 802 | if ( argc<=optind ) error(0,"no command specified"); 803 | 804 | /* Command to be executed */ 805 | cmdname = argv[optind]; 806 | cmdargs = argv+optind; 807 | 808 | /* Check that new uid is in list of valid uid's. 809 | This must be done before chroot for /etc/passwd lookup. */ 810 | if ( use_user ) { 811 | valid_users = strdup(VALID_USERS); 812 | for(ptr=strtok(valid_users,","); ptr!=NULL; ptr=strtok(NULL,",")) { 813 | if ( runuid==userid(ptr) ) break; 814 | } 815 | if ( ptr==NULL || runuid<=0 ) error(0,"illegal user specified: %d",runuid); 816 | } 817 | 818 | /* Setup pipes connecting to child stdout/err streams (ignore stdin). */ 819 | for(i=1; i<=2; i++) { 820 | if ( pipe(child_pipefd[i])!=0 ) error(errno,"creating pipe for fd %d",i); 821 | } 822 | 823 | if ( sigemptyset(&emptymask)!=0 ) error(errno,"creating empty signal mask"); 824 | 825 | /* unmask all signals, except SIGCHLD: detected in pselect() below */ 826 | sigmask = emptymask; 827 | if ( sigaddset(&sigmask, SIGCHLD)!=0 ) error(errno,"setting signal mask"); 828 | if ( sigprocmask(SIG_SETMASK, &sigmask, NULL)!=0 ) { 829 | error(errno,"unmasking signals"); 830 | } 831 | 832 | /* Construct signal handler for SIGCHLD detection in pselect(). */ 833 | received_SIGCHLD = 0; 834 | sigact.sa_handler = child_handler; 835 | sigact.sa_flags = 0; 836 | sigact.sa_mask = emptymask; 837 | if ( sigaction(SIGCHLD,&sigact,NULL)!=0 ) { 838 | error(errno,"installing signal handler"); 839 | } 840 | 841 | #ifdef USE_CGROUPS 842 | /* Make libcgroup ready for use */ 843 | ret = cgroup_init(); 844 | if ( ret!=0 ) { 845 | error(0,"libcgroup initialization failed: %s(%d)\n", cgroup_strerror(ret), ret); 846 | } 847 | /* Define the cgroup name that we will use */ 848 | cgroupname = (char*)malloc(256); 849 | if ( cgroupname==NULL ) { 850 | error(errno,"allocating memory for cgroupname"); 851 | } 852 | /* Note: group names must have slashes! */ 853 | snprintf(cgroupname, 256, "/domjudge/dj_cgroup_%d/", getpid()); 854 | 855 | cgroup_create(); 856 | 857 | unshare(CLONE_FILES|CLONE_FS|CLONE_NEWIPC|CLONE_NEWNET|CLONE_NEWNS|CLONE_NEWUTS|CLONE_SYSVSEM); 858 | #endif 859 | switch ( child_pid = fork() ) { 860 | case -1: /* error */ 861 | error(errno,"cannot fork"); 862 | case 0: /* run controlled command */ 863 | /* Connect pipes to command (stdin/)stdout/stderr and close unneeded fd's */ 864 | for(i=1; i<=2; i++) { 865 | if ( dup2(child_pipefd[i][PIPE_IN],i)<0 ) { 866 | error(errno,"redirecting child fd %d",i); 867 | } 868 | if ( close(child_pipefd[i][PIPE_IN] )!=0 || 869 | close(child_pipefd[i][PIPE_OUT])!=0 ) { 870 | error(errno,"closing pipe for fd %d",i); 871 | } 872 | } 873 | 874 | /* Run the command in a separate process group so that the command 875 | and all its children can be killed off with one signal. */ 876 | if ( setsid()==-1 ) error(errno,"setsid failed"); 877 | 878 | #ifdef USE_CGROUPS 879 | /* Put the child process in the cgroup */ 880 | cgroup_attach(); 881 | #endif 882 | 883 | /* Apply all restrictions for child process. */ 884 | setrestrictions(); 885 | 886 | /* And execute child command. */ 887 | execvp(cmdname,cmdargs); 888 | error(errno,"cannot start `%s'",cmdname); 889 | 890 | default: /* become watchdog */ 891 | /* Shed privileges, only if not using a separate child uid, 892 | because in that case we may need root privileges to kill 893 | the child process. Do not use Linux specific setresuid() 894 | call with saved set-user-ID. */ 895 | if ( !use_user ) { 896 | if ( setuid(getuid())!=0 ) error(errno, "setting watchdog uid"); 897 | verbose("watchdog using user ID `%d'",getuid()); 898 | } 899 | 900 | if ( gettimeofday(&starttime,NULL) ) error(errno,"getting time"); 901 | 902 | /* Close unused file descriptors */ 903 | for(i=1; i<=2; i++) { 904 | if ( close(child_pipefd[i][PIPE_IN])!=0 ) { 905 | error(errno,"closing pipe for fd %i",i); 906 | } 907 | } 908 | 909 | /* Redirect child stdout/stderr to file */ 910 | for(i=1; i<=2; i++) { 911 | child_redirfd[i] = i; /* Default: no redirects */ 912 | data_passed[i] = 0; /* Reset data counters */ 913 | } 914 | if ( redir_stdout ) { 915 | child_redirfd[STDOUT_FILENO] = creat(stdoutfilename, S_IRUSR | S_IWUSR); 916 | if ( child_redirfd[STDOUT_FILENO]<0 ) { 917 | error(errno,"opening file '%s'",stdoutfilename); 918 | } 919 | } 920 | if ( redir_stderr ) { 921 | child_redirfd[STDERR_FILENO] = creat(stderrfilename, S_IRUSR | S_IWUSR); 922 | if ( child_redirfd[STDERR_FILENO]<0 ) { 923 | error(errno,"opening file '%s'",stderrfilename); 924 | } 925 | } 926 | 927 | if ( sigemptyset(&emptymask)!=0 ) error(errno,"creating empty signal mask"); 928 | 929 | /* Construct one-time signal handler to terminate() for TERM 930 | and ALRM signals. */ 931 | sigmask = emptymask; 932 | if ( sigaddset(&sigmask,SIGALRM)!=0 || 933 | sigaddset(&sigmask,SIGTERM)!=0 ) error(errno,"setting signal mask"); 934 | 935 | sigact.sa_handler = terminate; 936 | sigact.sa_flags = SA_RESETHAND | SA_RESTART; 937 | sigact.sa_mask = sigmask; 938 | 939 | /* Kill child command when we receive SIGTERM */ 940 | if ( sigaction(SIGTERM,&sigact,NULL)!=0 ) { 941 | error(errno,"installing signal handler"); 942 | } 943 | 944 | if ( use_time ) { 945 | /* Kill child when we receive SIGALRM */ 946 | if ( sigaction(SIGALRM,&sigact,NULL)!=0 ) { 947 | error(errno,"installing signal handler"); 948 | } 949 | 950 | /* Trigger SIGALRM via setitimer: */ 951 | itimer.it_interval.tv_sec = 0; 952 | itimer.it_interval.tv_usec = 0; 953 | itimer.it_value.tv_sec = (int) runtime; 954 | itimer.it_value.tv_usec = (int)(modf(runtime,&tmpd) * 1E6); 955 | 956 | if ( setitimer(ITIMER_REAL,&itimer,NULL)!=0 ) { 957 | error(errno,"setting timer"); 958 | } 959 | verbose("using timelimit of %.3f seconds",runtime); 960 | } 961 | 962 | if ( times(&startticks)==(clock_t) -1 ) { 963 | error(errno,"getting start clock ticks"); 964 | } 965 | 966 | /* Wait for child data or exit. */ 967 | while ( 1 ) { 968 | 969 | FD_ZERO(&readfds); 970 | nfds = -1; 971 | for(i=1; i<=2; i++) { 972 | if ( child_pipefd[i][PIPE_OUT]>=0 ) { 973 | FD_SET(child_pipefd[i][PIPE_OUT],&readfds); 974 | nfds = max(nfds,child_pipefd[i][PIPE_OUT]); 975 | } 976 | } 977 | 978 | r = pselect(nfds+1, &readfds, NULL, NULL, NULL, &emptymask); 979 | if ( r==-1 && errno!=EINTR ) error(errno,"waiting for child data"); 980 | 981 | if ( received_SIGCHLD ) { 982 | if ( (pid = wait(&status))<0 ) error(errno,"waiting on child"); 983 | if ( pid==child_pid ) break; 984 | } 985 | 986 | /* Check to see if data is available and pass it on */ 987 | for(i=1; i<=2; i++) { 988 | if ( child_pipefd[i][PIPE_OUT] != -1 && FD_ISSET(child_pipefd[i][PIPE_OUT],&readfds) ) { 989 | nread = read(child_pipefd[i][PIPE_OUT], buf, BUF_SIZE); 990 | if ( nread==-1 ) error(errno,"reading child fd %d",i); 991 | if ( nread==0 ) { 992 | /* EOF detected: close fd and indicate this with -1 */ 993 | if ( close(child_pipefd[i][PIPE_OUT])!=0 ) { 994 | error(errno,"closing pipe for fd %d",i); 995 | } 996 | child_pipefd[i][PIPE_OUT] = -1; 997 | continue; 998 | } 999 | if ( limit_streamsize && data_passed[i]+nread>=streamsize ) { 1000 | if ( data_passed[i] 2 | 3 | int main () { 4 | char in[10]; 5 | scanf("%s", in); 6 | printf("Hello %s", in); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /tests/judge-worker/cpp/run.stdin: -------------------------------------------------------------------------------- 1 | World -------------------------------------------------------------------------------- /tests/judge-worker/cpp/source.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int main () { 4 | char in[10]; 5 | cin>>in; 6 | cout<<"Hello "<) { 2 | val enterValue = readLine() 3 | println("Hello $enterValue") 4 | } 5 | -------------------------------------------------------------------------------- /tests/judge-worker/kotlin/run.stdin: -------------------------------------------------------------------------------- 1 | World 2 | -------------------------------------------------------------------------------- /tests/judge-worker/nodejs10/run.stdin: -------------------------------------------------------------------------------- 1 | World -------------------------------------------------------------------------------- /tests/judge-worker/nodejs10/script.js: -------------------------------------------------------------------------------- 1 | var readline = require('readline'); 2 | 3 | var rl = readline.createInterface({ 4 | input: process.stdin, 5 | output: process.stdout, 6 | terminal: false 7 | }); 8 | 9 | rl.on('line', function (line) { 10 | console.log("Hello " + line); 11 | }); -------------------------------------------------------------------------------- /tests/judge-worker/nodejs12/run.stdin: -------------------------------------------------------------------------------- 1 | World -------------------------------------------------------------------------------- /tests/judge-worker/nodejs12/script.js: -------------------------------------------------------------------------------- 1 | const readline = require('readline'); 2 | 3 | const rl = readline.createInterface({ 4 | input: process.stdin, 5 | output: process.stdout, 6 | terminal: false 7 | }); 8 | 9 | rl.on('line', function (line) { 10 | console.log("Hello " + line); 11 | }); -------------------------------------------------------------------------------- /tests/judge-worker/perl/run.stdin: -------------------------------------------------------------------------------- 1 | World 2 | -------------------------------------------------------------------------------- /tests/judge-worker/perl/script.pl: -------------------------------------------------------------------------------- 1 | $input = ; 2 | print "Hello ${input}"; 3 | -------------------------------------------------------------------------------- /tests/judge-worker/py2/run.stdin: -------------------------------------------------------------------------------- 1 | World -------------------------------------------------------------------------------- /tests/judge-worker/py2/script.py: -------------------------------------------------------------------------------- 1 | inp = raw_input() 2 | print("Hello " + inp) -------------------------------------------------------------------------------- /tests/judge-worker/py3/run.stdin: -------------------------------------------------------------------------------- 1 | World -------------------------------------------------------------------------------- /tests/judge-worker/py3/script.py: -------------------------------------------------------------------------------- 1 | inp = input() 2 | print("Hello " + inp) -------------------------------------------------------------------------------- /tests/judge-worker/ruby/run.stdin: -------------------------------------------------------------------------------- 1 | World -------------------------------------------------------------------------------- /tests/judge-worker/ruby/script.rb: -------------------------------------------------------------------------------- 1 | puts "Hello " + gets.to_s -------------------------------------------------------------------------------- /tests/judge-worker/rust/run.stdin: -------------------------------------------------------------------------------- 1 | World 2 | -------------------------------------------------------------------------------- /tests/judge-worker/rust/script.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | fn main() { 4 | let mut input = String::new(); 5 | 6 | io::stdin().read_line(&mut input) 7 | .ok() 8 | .expect("Couldn't read line"); 9 | 10 | println!("Hello {}", input); 11 | } 12 | -------------------------------------------------------------------------------- /tests/judge-worker/test_workers.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | pushd $(dirname "$0") 3 | DIR=$(pwd) 4 | RUNBOX="${DIR}/runbox" 5 | LANGUAGE=$1 6 | 7 | echo $RUNBOX 8 | # Create runbox 9 | mkdir -p $RUNBOX 10 | 11 | # Copy source to runbox 12 | cp $DIR/$LANGUAGE/* $RUNBOX/ 13 | 14 | # Test Compile 15 | docker run \ 16 | --cpus="1" \ 17 | --memory="500m" \ 18 | --ulimit nofile=64:64 \ 19 | --rm \ 20 | -v "$RUNBOX":/usr/src/runbox \ 21 | -w /usr/src/runbox codingblocks/judge-worker-"$LANGUAGE" \ 22 | /bin/judge.sh -t 5 23 | 24 | ls -lh ${RUNBOX} 25 | 26 | expected="Hello World" 27 | actual="$(cat ${RUNBOX}/run.stdout)" 28 | if [ "$expected" == "$actual" ] ;then 29 | : 30 | else 31 | echo "MISMATCH: Expected = $expected; Actual = $actual" 32 | echo "$(cat ${RUNBOX}/*.stderr)" 33 | rm -rf $RUNBOX 34 | exit 1 35 | fi 36 | 37 | # Delete runbox 38 | rm -rf $RUNBOX 39 | -------------------------------------------------------------------------------- /tests/project-worker/nodejs/project.yml: -------------------------------------------------------------------------------- 1 | project: 2 | allowed-folders: 3 | - src/ 4 | before-test: 5 | - yarn install 6 | - yarn build 7 | testcases: 8 | - yarn test -------------------------------------------------------------------------------- /tests/project-worker/nodejs/project/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # parcel-bundler cache (https://parceljs.org/) 61 | .cache 62 | 63 | # next.js build output 64 | .next 65 | 66 | # nuxt.js build output 67 | .nuxt 68 | 69 | # vuepress build output 70 | .vuepress/dist 71 | 72 | # Serverless directories 73 | .serverless/ 74 | 75 | # FuseBox cache 76 | .fusebox/ 77 | 78 | #DynamoDB Local files 79 | .dynamodb/ 80 | 81 | # MAC OS 82 | .DS_Store 83 | -------------------------------------------------------------------------------- /tests/project-worker/nodejs/project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node src/index.js", 8 | "build": "return 0", 9 | "test": "mocha --exit test/*.spec.js" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "express": "^4.17.1" 15 | }, 16 | "devDependencies": { 17 | "chai": "^4.2.0", 18 | "chai-http": "^4.3.0", 19 | "mocha": "^7.1.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/project-worker/nodejs/project/src/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | 3 | const app = express() 4 | 5 | app.get('/users', (req, res) => { 6 | // TODO: 7 | res.json([{ name: 'jatin' }]) 8 | }) 9 | 10 | app.listen(3000, () => console.log('App running')) 11 | 12 | module.exports = app 13 | 14 | -------------------------------------------------------------------------------- /tests/project-worker/nodejs/project/test/user.spec.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'test'; 2 | 3 | const chai = require('chai'); 4 | const chaiHttp = require('chai-http'); 5 | const server = require('../src/index.js'); 6 | const {expect} = chai 7 | 8 | chai.use(chaiHttp); 9 | 10 | describe('users', () => { 11 | it('should get all Users', async () => { 12 | const res = await chai 13 | .request(server) 14 | .get('/users') 15 | 16 | expect(res.status).to.be.equal(200) 17 | expect(res.body).to.be.a('array') 18 | expect(res.body.length).to.be.equal(1) 19 | }) 20 | }) 21 | 22 | -------------------------------------------------------------------------------- /tests/project-worker/nodejs/project/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/chai@4": 6 | version "4.2.11" 7 | resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.11.tgz#d3614d6c5f500142358e6ed24e1bf16657536c50" 8 | integrity sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw== 9 | 10 | "@types/cookiejar@*": 11 | version "2.1.1" 12 | resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" 13 | integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw== 14 | 15 | "@types/node@*": 16 | version "13.13.2" 17 | resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.2.tgz#160d82623610db590a64e8ca81784e11117e5a54" 18 | integrity sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A== 19 | 20 | "@types/superagent@^3.8.3": 21 | version "3.8.7" 22 | resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-3.8.7.tgz#1f1ed44634d5459b3a672eb7235a8e7cfd97704c" 23 | integrity sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA== 24 | dependencies: 25 | "@types/cookiejar" "*" 26 | "@types/node" "*" 27 | 28 | accepts@~1.3.7: 29 | version "1.3.7" 30 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 31 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== 32 | dependencies: 33 | mime-types "~2.1.24" 34 | negotiator "0.6.2" 35 | 36 | ansi-colors@3.2.3: 37 | version "3.2.3" 38 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" 39 | integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== 40 | 41 | ansi-regex@^3.0.0: 42 | version "3.0.0" 43 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 44 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 45 | 46 | ansi-regex@^4.1.0: 47 | version "4.1.0" 48 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 49 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== 50 | 51 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 52 | version "3.2.1" 53 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 54 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 55 | dependencies: 56 | color-convert "^1.9.0" 57 | 58 | anymatch@~3.1.1: 59 | version "3.1.1" 60 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" 61 | integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== 62 | dependencies: 63 | normalize-path "^3.0.0" 64 | picomatch "^2.0.4" 65 | 66 | argparse@^1.0.7: 67 | version "1.0.10" 68 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 69 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 70 | dependencies: 71 | sprintf-js "~1.0.2" 72 | 73 | array-flatten@1.1.1: 74 | version "1.1.1" 75 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 76 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 77 | 78 | assertion-error@^1.1.0: 79 | version "1.1.0" 80 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 81 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== 82 | 83 | asynckit@^0.4.0: 84 | version "0.4.0" 85 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 86 | integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= 87 | 88 | balanced-match@^1.0.0: 89 | version "1.0.0" 90 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 91 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 92 | 93 | binary-extensions@^2.0.0: 94 | version "2.0.0" 95 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" 96 | integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== 97 | 98 | body-parser@1.19.0: 99 | version "1.19.0" 100 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" 101 | integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== 102 | dependencies: 103 | bytes "3.1.0" 104 | content-type "~1.0.4" 105 | debug "2.6.9" 106 | depd "~1.1.2" 107 | http-errors "1.7.2" 108 | iconv-lite "0.4.24" 109 | on-finished "~2.3.0" 110 | qs "6.7.0" 111 | raw-body "2.4.0" 112 | type-is "~1.6.17" 113 | 114 | brace-expansion@^1.1.7: 115 | version "1.1.11" 116 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 117 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 118 | dependencies: 119 | balanced-match "^1.0.0" 120 | concat-map "0.0.1" 121 | 122 | braces@~3.0.2: 123 | version "3.0.2" 124 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 125 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 126 | dependencies: 127 | fill-range "^7.0.1" 128 | 129 | browser-stdout@1.3.1: 130 | version "1.3.1" 131 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 132 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 133 | 134 | bytes@3.1.0: 135 | version "3.1.0" 136 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" 137 | integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== 138 | 139 | camelcase@^5.0.0: 140 | version "5.3.1" 141 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 142 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 143 | 144 | chai-http@^4.3.0: 145 | version "4.3.0" 146 | resolved "https://registry.yarnpkg.com/chai-http/-/chai-http-4.3.0.tgz#3c37c675c1f4fe685185a307e345de7599337c1a" 147 | integrity sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg== 148 | dependencies: 149 | "@types/chai" "4" 150 | "@types/superagent" "^3.8.3" 151 | cookiejar "^2.1.1" 152 | is-ip "^2.0.0" 153 | methods "^1.1.2" 154 | qs "^6.5.1" 155 | superagent "^3.7.0" 156 | 157 | chai@^4.2.0: 158 | version "4.2.0" 159 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" 160 | integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== 161 | dependencies: 162 | assertion-error "^1.1.0" 163 | check-error "^1.0.2" 164 | deep-eql "^3.0.1" 165 | get-func-name "^2.0.0" 166 | pathval "^1.1.0" 167 | type-detect "^4.0.5" 168 | 169 | chalk@^2.4.2: 170 | version "2.4.2" 171 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 172 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 173 | dependencies: 174 | ansi-styles "^3.2.1" 175 | escape-string-regexp "^1.0.5" 176 | supports-color "^5.3.0" 177 | 178 | check-error@^1.0.2: 179 | version "1.0.2" 180 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 181 | integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= 182 | 183 | chokidar@3.3.0: 184 | version "3.3.0" 185 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" 186 | integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A== 187 | dependencies: 188 | anymatch "~3.1.1" 189 | braces "~3.0.2" 190 | glob-parent "~5.1.0" 191 | is-binary-path "~2.1.0" 192 | is-glob "~4.0.1" 193 | normalize-path "~3.0.0" 194 | readdirp "~3.2.0" 195 | optionalDependencies: 196 | fsevents "~2.1.1" 197 | 198 | cliui@^5.0.0: 199 | version "5.0.0" 200 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" 201 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== 202 | dependencies: 203 | string-width "^3.1.0" 204 | strip-ansi "^5.2.0" 205 | wrap-ansi "^5.1.0" 206 | 207 | color-convert@^1.9.0: 208 | version "1.9.3" 209 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 210 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 211 | dependencies: 212 | color-name "1.1.3" 213 | 214 | color-name@1.1.3: 215 | version "1.1.3" 216 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 217 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 218 | 219 | combined-stream@^1.0.6: 220 | version "1.0.8" 221 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 222 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 223 | dependencies: 224 | delayed-stream "~1.0.0" 225 | 226 | component-emitter@^1.2.0: 227 | version "1.3.0" 228 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" 229 | integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== 230 | 231 | concat-map@0.0.1: 232 | version "0.0.1" 233 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 234 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 235 | 236 | content-disposition@0.5.3: 237 | version "0.5.3" 238 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" 239 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== 240 | dependencies: 241 | safe-buffer "5.1.2" 242 | 243 | content-type@~1.0.4: 244 | version "1.0.4" 245 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 246 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 247 | 248 | cookie-signature@1.0.6: 249 | version "1.0.6" 250 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 251 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 252 | 253 | cookie@0.4.0: 254 | version "0.4.0" 255 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" 256 | integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== 257 | 258 | cookiejar@^2.1.0, cookiejar@^2.1.1: 259 | version "2.1.2" 260 | resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" 261 | integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== 262 | 263 | core-util-is@~1.0.0: 264 | version "1.0.2" 265 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 266 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 267 | 268 | debug@2.6.9: 269 | version "2.6.9" 270 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 271 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 272 | dependencies: 273 | ms "2.0.0" 274 | 275 | debug@3.2.6, debug@^3.1.0: 276 | version "3.2.6" 277 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 278 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 279 | dependencies: 280 | ms "^2.1.1" 281 | 282 | decamelize@^1.2.0: 283 | version "1.2.0" 284 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 285 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 286 | 287 | deep-eql@^3.0.1: 288 | version "3.0.1" 289 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" 290 | integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== 291 | dependencies: 292 | type-detect "^4.0.0" 293 | 294 | define-properties@^1.1.2, define-properties@^1.1.3: 295 | version "1.1.3" 296 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 297 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== 298 | dependencies: 299 | object-keys "^1.0.12" 300 | 301 | delayed-stream@~1.0.0: 302 | version "1.0.0" 303 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 304 | integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= 305 | 306 | depd@~1.1.2: 307 | version "1.1.2" 308 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 309 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 310 | 311 | destroy@~1.0.4: 312 | version "1.0.4" 313 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 314 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 315 | 316 | diff@3.5.0: 317 | version "3.5.0" 318 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 319 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== 320 | 321 | ee-first@1.1.1: 322 | version "1.1.1" 323 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 324 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 325 | 326 | emoji-regex@^7.0.1: 327 | version "7.0.3" 328 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 329 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 330 | 331 | encodeurl@~1.0.2: 332 | version "1.0.2" 333 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 334 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 335 | 336 | es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: 337 | version "1.17.5" 338 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" 339 | integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== 340 | dependencies: 341 | es-to-primitive "^1.2.1" 342 | function-bind "^1.1.1" 343 | has "^1.0.3" 344 | has-symbols "^1.0.1" 345 | is-callable "^1.1.5" 346 | is-regex "^1.0.5" 347 | object-inspect "^1.7.0" 348 | object-keys "^1.1.1" 349 | object.assign "^4.1.0" 350 | string.prototype.trimleft "^2.1.1" 351 | string.prototype.trimright "^2.1.1" 352 | 353 | es-to-primitive@^1.2.1: 354 | version "1.2.1" 355 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" 356 | integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== 357 | dependencies: 358 | is-callable "^1.1.4" 359 | is-date-object "^1.0.1" 360 | is-symbol "^1.0.2" 361 | 362 | escape-html@~1.0.3: 363 | version "1.0.3" 364 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 365 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 366 | 367 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: 368 | version "1.0.5" 369 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 370 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 371 | 372 | esprima@^4.0.0: 373 | version "4.0.1" 374 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 375 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 376 | 377 | etag@~1.8.1: 378 | version "1.8.1" 379 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 380 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 381 | 382 | express@^4.17.1: 383 | version "4.17.1" 384 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" 385 | integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== 386 | dependencies: 387 | accepts "~1.3.7" 388 | array-flatten "1.1.1" 389 | body-parser "1.19.0" 390 | content-disposition "0.5.3" 391 | content-type "~1.0.4" 392 | cookie "0.4.0" 393 | cookie-signature "1.0.6" 394 | debug "2.6.9" 395 | depd "~1.1.2" 396 | encodeurl "~1.0.2" 397 | escape-html "~1.0.3" 398 | etag "~1.8.1" 399 | finalhandler "~1.1.2" 400 | fresh "0.5.2" 401 | merge-descriptors "1.0.1" 402 | methods "~1.1.2" 403 | on-finished "~2.3.0" 404 | parseurl "~1.3.3" 405 | path-to-regexp "0.1.7" 406 | proxy-addr "~2.0.5" 407 | qs "6.7.0" 408 | range-parser "~1.2.1" 409 | safe-buffer "5.1.2" 410 | send "0.17.1" 411 | serve-static "1.14.1" 412 | setprototypeof "1.1.1" 413 | statuses "~1.5.0" 414 | type-is "~1.6.18" 415 | utils-merge "1.0.1" 416 | vary "~1.1.2" 417 | 418 | extend@^3.0.0: 419 | version "3.0.2" 420 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 421 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== 422 | 423 | fill-range@^7.0.1: 424 | version "7.0.1" 425 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 426 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 427 | dependencies: 428 | to-regex-range "^5.0.1" 429 | 430 | finalhandler@~1.1.2: 431 | version "1.1.2" 432 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" 433 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== 434 | dependencies: 435 | debug "2.6.9" 436 | encodeurl "~1.0.2" 437 | escape-html "~1.0.3" 438 | on-finished "~2.3.0" 439 | parseurl "~1.3.3" 440 | statuses "~1.5.0" 441 | unpipe "~1.0.0" 442 | 443 | find-up@3.0.0, find-up@^3.0.0: 444 | version "3.0.0" 445 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 446 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 447 | dependencies: 448 | locate-path "^3.0.0" 449 | 450 | flat@^4.1.0: 451 | version "4.1.0" 452 | resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" 453 | integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== 454 | dependencies: 455 | is-buffer "~2.0.3" 456 | 457 | form-data@^2.3.1: 458 | version "2.5.1" 459 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" 460 | integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== 461 | dependencies: 462 | asynckit "^0.4.0" 463 | combined-stream "^1.0.6" 464 | mime-types "^2.1.12" 465 | 466 | formidable@^1.2.0: 467 | version "1.2.2" 468 | resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" 469 | integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== 470 | 471 | forwarded@~0.1.2: 472 | version "0.1.2" 473 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 474 | integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= 475 | 476 | fresh@0.5.2: 477 | version "0.5.2" 478 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 479 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 480 | 481 | fs.realpath@^1.0.0: 482 | version "1.0.0" 483 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 484 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 485 | 486 | fsevents@~2.1.1: 487 | version "2.1.3" 488 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" 489 | integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== 490 | 491 | function-bind@^1.1.1: 492 | version "1.1.1" 493 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 494 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 495 | 496 | get-caller-file@^2.0.1: 497 | version "2.0.5" 498 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 499 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 500 | 501 | get-func-name@^2.0.0: 502 | version "2.0.0" 503 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 504 | integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= 505 | 506 | glob-parent@~5.1.0: 507 | version "5.1.1" 508 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" 509 | integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== 510 | dependencies: 511 | is-glob "^4.0.1" 512 | 513 | glob@7.1.3: 514 | version "7.1.3" 515 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" 516 | integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== 517 | dependencies: 518 | fs.realpath "^1.0.0" 519 | inflight "^1.0.4" 520 | inherits "2" 521 | minimatch "^3.0.4" 522 | once "^1.3.0" 523 | path-is-absolute "^1.0.0" 524 | 525 | growl@1.10.5: 526 | version "1.10.5" 527 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 528 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 529 | 530 | has-flag@^3.0.0: 531 | version "3.0.0" 532 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 533 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 534 | 535 | has-symbols@^1.0.0, has-symbols@^1.0.1: 536 | version "1.0.1" 537 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" 538 | integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== 539 | 540 | has@^1.0.3: 541 | version "1.0.3" 542 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 543 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 544 | dependencies: 545 | function-bind "^1.1.1" 546 | 547 | he@1.2.0: 548 | version "1.2.0" 549 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 550 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 551 | 552 | http-errors@1.7.2: 553 | version "1.7.2" 554 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" 555 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== 556 | dependencies: 557 | depd "~1.1.2" 558 | inherits "2.0.3" 559 | setprototypeof "1.1.1" 560 | statuses ">= 1.5.0 < 2" 561 | toidentifier "1.0.0" 562 | 563 | http-errors@~1.7.2: 564 | version "1.7.3" 565 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" 566 | integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== 567 | dependencies: 568 | depd "~1.1.2" 569 | inherits "2.0.4" 570 | setprototypeof "1.1.1" 571 | statuses ">= 1.5.0 < 2" 572 | toidentifier "1.0.0" 573 | 574 | iconv-lite@0.4.24: 575 | version "0.4.24" 576 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 577 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 578 | dependencies: 579 | safer-buffer ">= 2.1.2 < 3" 580 | 581 | inflight@^1.0.4: 582 | version "1.0.6" 583 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 584 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 585 | dependencies: 586 | once "^1.3.0" 587 | wrappy "1" 588 | 589 | inherits@2, inherits@2.0.4, inherits@~2.0.3: 590 | version "2.0.4" 591 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 592 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 593 | 594 | inherits@2.0.3: 595 | version "2.0.3" 596 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 597 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 598 | 599 | ip-regex@^2.0.0: 600 | version "2.1.0" 601 | resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" 602 | integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= 603 | 604 | ipaddr.js@1.9.1: 605 | version "1.9.1" 606 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" 607 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 608 | 609 | is-binary-path@~2.1.0: 610 | version "2.1.0" 611 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 612 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 613 | dependencies: 614 | binary-extensions "^2.0.0" 615 | 616 | is-buffer@~2.0.3: 617 | version "2.0.4" 618 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" 619 | integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== 620 | 621 | is-callable@^1.1.4, is-callable@^1.1.5: 622 | version "1.1.5" 623 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" 624 | integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== 625 | 626 | is-date-object@^1.0.1: 627 | version "1.0.2" 628 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" 629 | integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== 630 | 631 | is-extglob@^2.1.1: 632 | version "2.1.1" 633 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 634 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 635 | 636 | is-fullwidth-code-point@^2.0.0: 637 | version "2.0.0" 638 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 639 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 640 | 641 | is-glob@^4.0.1, is-glob@~4.0.1: 642 | version "4.0.1" 643 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 644 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== 645 | dependencies: 646 | is-extglob "^2.1.1" 647 | 648 | is-ip@^2.0.0: 649 | version "2.0.0" 650 | resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-2.0.0.tgz#68eea07e8a0a0a94c2d080dd674c731ab2a461ab" 651 | integrity sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas= 652 | dependencies: 653 | ip-regex "^2.0.0" 654 | 655 | is-number@^7.0.0: 656 | version "7.0.0" 657 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 658 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 659 | 660 | is-regex@^1.0.5: 661 | version "1.0.5" 662 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" 663 | integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== 664 | dependencies: 665 | has "^1.0.3" 666 | 667 | is-symbol@^1.0.2: 668 | version "1.0.3" 669 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" 670 | integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== 671 | dependencies: 672 | has-symbols "^1.0.1" 673 | 674 | isarray@~1.0.0: 675 | version "1.0.0" 676 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 677 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 678 | 679 | isexe@^2.0.0: 680 | version "2.0.0" 681 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 682 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 683 | 684 | js-yaml@3.13.1: 685 | version "3.13.1" 686 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 687 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== 688 | dependencies: 689 | argparse "^1.0.7" 690 | esprima "^4.0.0" 691 | 692 | locate-path@^3.0.0: 693 | version "3.0.0" 694 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 695 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== 696 | dependencies: 697 | p-locate "^3.0.0" 698 | path-exists "^3.0.0" 699 | 700 | lodash@^4.17.15: 701 | version "4.17.15" 702 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 703 | integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== 704 | 705 | log-symbols@3.0.0: 706 | version "3.0.0" 707 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" 708 | integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== 709 | dependencies: 710 | chalk "^2.4.2" 711 | 712 | media-typer@0.3.0: 713 | version "0.3.0" 714 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 715 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 716 | 717 | merge-descriptors@1.0.1: 718 | version "1.0.1" 719 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 720 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 721 | 722 | methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: 723 | version "1.1.2" 724 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 725 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 726 | 727 | mime-db@1.43.0: 728 | version "1.43.0" 729 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" 730 | integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== 731 | 732 | mime-types@^2.1.12, mime-types@~2.1.24: 733 | version "2.1.26" 734 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" 735 | integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== 736 | dependencies: 737 | mime-db "1.43.0" 738 | 739 | mime@1.6.0, mime@^1.4.1: 740 | version "1.6.0" 741 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 742 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 743 | 744 | minimatch@3.0.4, minimatch@^3.0.4: 745 | version "3.0.4" 746 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 747 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 748 | dependencies: 749 | brace-expansion "^1.1.7" 750 | 751 | minimist@^1.2.5: 752 | version "1.2.5" 753 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 754 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 755 | 756 | mkdirp@0.5.3: 757 | version "0.5.3" 758 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.3.tgz#5a514b7179259287952881e94410ec5465659f8c" 759 | integrity sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg== 760 | dependencies: 761 | minimist "^1.2.5" 762 | 763 | mocha@^7.1.1: 764 | version "7.1.1" 765 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.1.1.tgz#89fbb30d09429845b1bb893a830bf5771049a441" 766 | integrity sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA== 767 | dependencies: 768 | ansi-colors "3.2.3" 769 | browser-stdout "1.3.1" 770 | chokidar "3.3.0" 771 | debug "3.2.6" 772 | diff "3.5.0" 773 | escape-string-regexp "1.0.5" 774 | find-up "3.0.0" 775 | glob "7.1.3" 776 | growl "1.10.5" 777 | he "1.2.0" 778 | js-yaml "3.13.1" 779 | log-symbols "3.0.0" 780 | minimatch "3.0.4" 781 | mkdirp "0.5.3" 782 | ms "2.1.1" 783 | node-environment-flags "1.0.6" 784 | object.assign "4.1.0" 785 | strip-json-comments "2.0.1" 786 | supports-color "6.0.0" 787 | which "1.3.1" 788 | wide-align "1.1.3" 789 | yargs "13.3.2" 790 | yargs-parser "13.1.2" 791 | yargs-unparser "1.6.0" 792 | 793 | ms@2.0.0: 794 | version "2.0.0" 795 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 796 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 797 | 798 | ms@2.1.1: 799 | version "2.1.1" 800 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 801 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 802 | 803 | ms@^2.1.1: 804 | version "2.1.2" 805 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 806 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 807 | 808 | negotiator@0.6.2: 809 | version "0.6.2" 810 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 811 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== 812 | 813 | node-environment-flags@1.0.6: 814 | version "1.0.6" 815 | resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" 816 | integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw== 817 | dependencies: 818 | object.getownpropertydescriptors "^2.0.3" 819 | semver "^5.7.0" 820 | 821 | normalize-path@^3.0.0, normalize-path@~3.0.0: 822 | version "3.0.0" 823 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 824 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 825 | 826 | object-inspect@^1.7.0: 827 | version "1.7.0" 828 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" 829 | integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== 830 | 831 | object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: 832 | version "1.1.1" 833 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 834 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 835 | 836 | object.assign@4.1.0, object.assign@^4.1.0: 837 | version "4.1.0" 838 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" 839 | integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== 840 | dependencies: 841 | define-properties "^1.1.2" 842 | function-bind "^1.1.1" 843 | has-symbols "^1.0.0" 844 | object-keys "^1.0.11" 845 | 846 | object.getownpropertydescriptors@^2.0.3: 847 | version "2.1.0" 848 | resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" 849 | integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== 850 | dependencies: 851 | define-properties "^1.1.3" 852 | es-abstract "^1.17.0-next.1" 853 | 854 | on-finished@~2.3.0: 855 | version "2.3.0" 856 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 857 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 858 | dependencies: 859 | ee-first "1.1.1" 860 | 861 | once@^1.3.0: 862 | version "1.4.0" 863 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 864 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 865 | dependencies: 866 | wrappy "1" 867 | 868 | p-limit@^2.0.0: 869 | version "2.3.0" 870 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 871 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 872 | dependencies: 873 | p-try "^2.0.0" 874 | 875 | p-locate@^3.0.0: 876 | version "3.0.0" 877 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 878 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== 879 | dependencies: 880 | p-limit "^2.0.0" 881 | 882 | p-try@^2.0.0: 883 | version "2.2.0" 884 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 885 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 886 | 887 | parseurl@~1.3.3: 888 | version "1.3.3" 889 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 890 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 891 | 892 | path-exists@^3.0.0: 893 | version "3.0.0" 894 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 895 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 896 | 897 | path-is-absolute@^1.0.0: 898 | version "1.0.1" 899 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 900 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 901 | 902 | path-to-regexp@0.1.7: 903 | version "0.1.7" 904 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 905 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 906 | 907 | pathval@^1.1.0: 908 | version "1.1.0" 909 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" 910 | integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= 911 | 912 | picomatch@^2.0.4: 913 | version "2.2.2" 914 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" 915 | integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== 916 | 917 | process-nextick-args@~2.0.0: 918 | version "2.0.1" 919 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 920 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 921 | 922 | proxy-addr@~2.0.5: 923 | version "2.0.6" 924 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" 925 | integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== 926 | dependencies: 927 | forwarded "~0.1.2" 928 | ipaddr.js "1.9.1" 929 | 930 | qs@6.7.0: 931 | version "6.7.0" 932 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" 933 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== 934 | 935 | qs@^6.5.1: 936 | version "6.9.3" 937 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e" 938 | integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw== 939 | 940 | range-parser@~1.2.1: 941 | version "1.2.1" 942 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 943 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 944 | 945 | raw-body@2.4.0: 946 | version "2.4.0" 947 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" 948 | integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== 949 | dependencies: 950 | bytes "3.1.0" 951 | http-errors "1.7.2" 952 | iconv-lite "0.4.24" 953 | unpipe "1.0.0" 954 | 955 | readable-stream@^2.3.5: 956 | version "2.3.7" 957 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 958 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 959 | dependencies: 960 | core-util-is "~1.0.0" 961 | inherits "~2.0.3" 962 | isarray "~1.0.0" 963 | process-nextick-args "~2.0.0" 964 | safe-buffer "~5.1.1" 965 | string_decoder "~1.1.1" 966 | util-deprecate "~1.0.1" 967 | 968 | readdirp@~3.2.0: 969 | version "3.2.0" 970 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" 971 | integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== 972 | dependencies: 973 | picomatch "^2.0.4" 974 | 975 | require-directory@^2.1.1: 976 | version "2.1.1" 977 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 978 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 979 | 980 | require-main-filename@^2.0.0: 981 | version "2.0.0" 982 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" 983 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== 984 | 985 | safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 986 | version "5.1.2" 987 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 988 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 989 | 990 | "safer-buffer@>= 2.1.2 < 3": 991 | version "2.1.2" 992 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 993 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 994 | 995 | semver@^5.7.0: 996 | version "5.7.1" 997 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 998 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 999 | 1000 | send@0.17.1: 1001 | version "0.17.1" 1002 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" 1003 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== 1004 | dependencies: 1005 | debug "2.6.9" 1006 | depd "~1.1.2" 1007 | destroy "~1.0.4" 1008 | encodeurl "~1.0.2" 1009 | escape-html "~1.0.3" 1010 | etag "~1.8.1" 1011 | fresh "0.5.2" 1012 | http-errors "~1.7.2" 1013 | mime "1.6.0" 1014 | ms "2.1.1" 1015 | on-finished "~2.3.0" 1016 | range-parser "~1.2.1" 1017 | statuses "~1.5.0" 1018 | 1019 | serve-static@1.14.1: 1020 | version "1.14.1" 1021 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" 1022 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== 1023 | dependencies: 1024 | encodeurl "~1.0.2" 1025 | escape-html "~1.0.3" 1026 | parseurl "~1.3.3" 1027 | send "0.17.1" 1028 | 1029 | set-blocking@^2.0.0: 1030 | version "2.0.0" 1031 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1032 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 1033 | 1034 | setprototypeof@1.1.1: 1035 | version "1.1.1" 1036 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" 1037 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== 1038 | 1039 | sprintf-js@~1.0.2: 1040 | version "1.0.3" 1041 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1042 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 1043 | 1044 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0: 1045 | version "1.5.0" 1046 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 1047 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 1048 | 1049 | "string-width@^1.0.2 || 2": 1050 | version "2.1.1" 1051 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1052 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 1053 | dependencies: 1054 | is-fullwidth-code-point "^2.0.0" 1055 | strip-ansi "^4.0.0" 1056 | 1057 | string-width@^3.0.0, string-width@^3.1.0: 1058 | version "3.1.0" 1059 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 1060 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 1061 | dependencies: 1062 | emoji-regex "^7.0.1" 1063 | is-fullwidth-code-point "^2.0.0" 1064 | strip-ansi "^5.1.0" 1065 | 1066 | string.prototype.trimend@^1.0.0: 1067 | version "1.0.1" 1068 | resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" 1069 | integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== 1070 | dependencies: 1071 | define-properties "^1.1.3" 1072 | es-abstract "^1.17.5" 1073 | 1074 | string.prototype.trimleft@^2.1.1: 1075 | version "2.1.2" 1076 | resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" 1077 | integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== 1078 | dependencies: 1079 | define-properties "^1.1.3" 1080 | es-abstract "^1.17.5" 1081 | string.prototype.trimstart "^1.0.0" 1082 | 1083 | string.prototype.trimright@^2.1.1: 1084 | version "2.1.2" 1085 | resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" 1086 | integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== 1087 | dependencies: 1088 | define-properties "^1.1.3" 1089 | es-abstract "^1.17.5" 1090 | string.prototype.trimend "^1.0.0" 1091 | 1092 | string.prototype.trimstart@^1.0.0: 1093 | version "1.0.1" 1094 | resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" 1095 | integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== 1096 | dependencies: 1097 | define-properties "^1.1.3" 1098 | es-abstract "^1.17.5" 1099 | 1100 | string_decoder@~1.1.1: 1101 | version "1.1.1" 1102 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1103 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 1104 | dependencies: 1105 | safe-buffer "~5.1.0" 1106 | 1107 | strip-ansi@^4.0.0: 1108 | version "4.0.0" 1109 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1110 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 1111 | dependencies: 1112 | ansi-regex "^3.0.0" 1113 | 1114 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: 1115 | version "5.2.0" 1116 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 1117 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 1118 | dependencies: 1119 | ansi-regex "^4.1.0" 1120 | 1121 | strip-json-comments@2.0.1: 1122 | version "2.0.1" 1123 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1124 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 1125 | 1126 | superagent@^3.7.0: 1127 | version "3.8.3" 1128 | resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" 1129 | integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== 1130 | dependencies: 1131 | component-emitter "^1.2.0" 1132 | cookiejar "^2.1.0" 1133 | debug "^3.1.0" 1134 | extend "^3.0.0" 1135 | form-data "^2.3.1" 1136 | formidable "^1.2.0" 1137 | methods "^1.1.1" 1138 | mime "^1.4.1" 1139 | qs "^6.5.1" 1140 | readable-stream "^2.3.5" 1141 | 1142 | supports-color@6.0.0: 1143 | version "6.0.0" 1144 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" 1145 | integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== 1146 | dependencies: 1147 | has-flag "^3.0.0" 1148 | 1149 | supports-color@^5.3.0: 1150 | version "5.5.0" 1151 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1152 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1153 | dependencies: 1154 | has-flag "^3.0.0" 1155 | 1156 | to-regex-range@^5.0.1: 1157 | version "5.0.1" 1158 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1159 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1160 | dependencies: 1161 | is-number "^7.0.0" 1162 | 1163 | toidentifier@1.0.0: 1164 | version "1.0.0" 1165 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 1166 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== 1167 | 1168 | type-detect@^4.0.0, type-detect@^4.0.5: 1169 | version "4.0.8" 1170 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 1171 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 1172 | 1173 | type-is@~1.6.17, type-is@~1.6.18: 1174 | version "1.6.18" 1175 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 1176 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 1177 | dependencies: 1178 | media-typer "0.3.0" 1179 | mime-types "~2.1.24" 1180 | 1181 | unpipe@1.0.0, unpipe@~1.0.0: 1182 | version "1.0.0" 1183 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1184 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 1185 | 1186 | util-deprecate@~1.0.1: 1187 | version "1.0.2" 1188 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1189 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1190 | 1191 | utils-merge@1.0.1: 1192 | version "1.0.1" 1193 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 1194 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 1195 | 1196 | vary@~1.1.2: 1197 | version "1.1.2" 1198 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 1199 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 1200 | 1201 | which-module@^2.0.0: 1202 | version "2.0.0" 1203 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 1204 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= 1205 | 1206 | which@1.3.1: 1207 | version "1.3.1" 1208 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1209 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 1210 | dependencies: 1211 | isexe "^2.0.0" 1212 | 1213 | wide-align@1.1.3: 1214 | version "1.1.3" 1215 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 1216 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 1217 | dependencies: 1218 | string-width "^1.0.2 || 2" 1219 | 1220 | wrap-ansi@^5.1.0: 1221 | version "5.1.0" 1222 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" 1223 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== 1224 | dependencies: 1225 | ansi-styles "^3.2.0" 1226 | string-width "^3.0.0" 1227 | strip-ansi "^5.0.0" 1228 | 1229 | wrappy@1: 1230 | version "1.0.2" 1231 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1232 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1233 | 1234 | y18n@^4.0.0: 1235 | version "4.0.0" 1236 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" 1237 | integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== 1238 | 1239 | yargs-parser@13.1.2, yargs-parser@^13.1.2: 1240 | version "13.1.2" 1241 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" 1242 | integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== 1243 | dependencies: 1244 | camelcase "^5.0.0" 1245 | decamelize "^1.2.0" 1246 | 1247 | yargs-unparser@1.6.0: 1248 | version "1.6.0" 1249 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" 1250 | integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== 1251 | dependencies: 1252 | flat "^4.1.0" 1253 | lodash "^4.17.15" 1254 | yargs "^13.3.0" 1255 | 1256 | yargs@13.3.2, yargs@^13.3.0: 1257 | version "13.3.2" 1258 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" 1259 | integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== 1260 | dependencies: 1261 | cliui "^5.0.0" 1262 | find-up "^3.0.0" 1263 | get-caller-file "^2.0.1" 1264 | require-directory "^2.1.1" 1265 | require-main-filename "^2.0.0" 1266 | set-blocking "^2.0.0" 1267 | string-width "^3.0.0" 1268 | which-module "^2.0.0" 1269 | y18n "^4.0.0" 1270 | yargs-parser "^13.1.2" 1271 | -------------------------------------------------------------------------------- /tests/project-worker/python/project.yml: -------------------------------------------------------------------------------- 1 | project: 2 | allowed-folders: 3 | - src/ 4 | before-test: 5 | - pip install -r requirements.txt 6 | testcases: 7 | - python manage.py test tests/* -------------------------------------------------------------------------------- /tests/project-worker/python/project/main/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-blocks/judge-workers/a937e494c3f80864dae0bd1253318a23b503a375/tests/project-worker/python/project/main/__init__.py -------------------------------------------------------------------------------- /tests/project-worker/python/project/main/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/main/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MainConfig(AppConfig): 5 | name = 'main' 6 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/main/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.8 on 2020-07-08 13:24 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Animal', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('name', models.CharField(max_length=1024)), 19 | ('sound', models.CharField(max_length=1024)), 20 | ], 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/main/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-blocks/judge-workers/a937e494c3f80864dae0bd1253318a23b503a375/tests/project-worker/python/project/main/migrations/__init__.py -------------------------------------------------------------------------------- /tests/project-worker/python/project/main/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | class Animal(models.Model): 5 | name = models.CharField(max_length = 1024) 6 | sound = models.CharField(max_length = 1024) 7 | 8 | def speak(self): 9 | return f'The {self.name} says \"{self.sound}\"' 10 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/main/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/main/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample.settings') 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/requirements.txt: -------------------------------------------------------------------------------- 1 | django -------------------------------------------------------------------------------- /tests/project-worker/python/project/sample/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coding-blocks/judge-workers/a937e494c3f80864dae0bd1253318a23b503a375/tests/project-worker/python/project/sample/__init__.py -------------------------------------------------------------------------------- /tests/project-worker/python/project/sample/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for sample project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/sample/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for sample project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.0.8. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.0/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'j_#@8u(ux_slp$7yp&b(sxexkj2c$65u83q5c-xv6jmyeyi4*b' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'main', 35 | 36 | 'django.contrib.admin', 37 | 'django.contrib.auth', 38 | 'django.contrib.contenttypes', 39 | 'django.contrib.sessions', 40 | 'django.contrib.messages', 41 | 'django.contrib.staticfiles', 42 | ] 43 | 44 | MIDDLEWARE = [ 45 | 'django.middleware.security.SecurityMiddleware', 46 | 'django.contrib.sessions.middleware.SessionMiddleware', 47 | 'django.middleware.common.CommonMiddleware', 48 | 'django.middleware.csrf.CsrfViewMiddleware', 49 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 50 | 'django.contrib.messages.middleware.MessageMiddleware', 51 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 52 | ] 53 | 54 | ROOT_URLCONF = 'sample.urls' 55 | 56 | TEMPLATES = [ 57 | { 58 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 59 | 'DIRS': [], 60 | 'APP_DIRS': True, 61 | 'OPTIONS': { 62 | 'context_processors': [ 63 | 'django.template.context_processors.debug', 64 | 'django.template.context_processors.request', 65 | 'django.contrib.auth.context_processors.auth', 66 | 'django.contrib.messages.context_processors.messages', 67 | ], 68 | }, 69 | }, 70 | ] 71 | 72 | WSGI_APPLICATION = 'sample.wsgi.application' 73 | 74 | 75 | # Database 76 | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases 77 | 78 | DATABASES = { 79 | 'default': { 80 | 'ENGINE': 'django.db.backends.sqlite3', 81 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 82 | } 83 | } 84 | 85 | 86 | # Password validation 87 | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators 88 | 89 | AUTH_PASSWORD_VALIDATORS = [ 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 92 | }, 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 101 | }, 102 | ] 103 | 104 | 105 | # Internationalization 106 | # https://docs.djangoproject.com/en/3.0/topics/i18n/ 107 | 108 | LANGUAGE_CODE = 'en-us' 109 | 110 | TIME_ZONE = 'UTC' 111 | 112 | USE_I18N = True 113 | 114 | USE_L10N = True 115 | 116 | USE_TZ = True 117 | 118 | 119 | # Static files (CSS, JavaScript, Images) 120 | # https://docs.djangoproject.com/en/3.0/howto/static-files/ 121 | 122 | STATIC_URL = '/static/' 123 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/sample/urls.py: -------------------------------------------------------------------------------- 1 | """sample URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | ] 22 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/sample/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for sample project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sample.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /tests/project-worker/python/project/tests/main/test_animal.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from main.models import Animal 3 | 4 | class AnimalTestCase(TestCase): 5 | def setUp(self): 6 | Animal.objects.create(name="lion", sound="roar") 7 | Animal.objects.create(name="cat", sound="meow") 8 | 9 | def test_animals_can_speak(self): 10 | """Animals that can speak are correctly identified""" 11 | lion = Animal.objects.get(name="lion") 12 | cat = Animal.objects.get(name="cat") 13 | self.assertEqual(lion.speak(), 'The lion says "roar"') 14 | self.assertEqual(cat.speak(), 'The cat says "meow"') -------------------------------------------------------------------------------- /tests/project-worker/test_workers.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | pushd $(dirname "$0") 3 | DIR=$(pwd) 4 | RUNBOX="${DIR}/runbox" 5 | LANGUAGE=$1 6 | 7 | echo $RUNBOX 8 | # Create runbox 9 | mkdir -p $RUNBOX 10 | 11 | # Copy source to runbox 12 | cp -r $DIR/$LANGUAGE/* $RUNBOX/ 13 | 14 | # Test Compile 15 | docker run \ 16 | --cpus="1" \ 17 | --memory="500m" \ 18 | --rm \ 19 | -v "$RUNBOX":/usr/src/runbox \ 20 | -w /usr/src/runbox codingblocks/project-worker-"$LANGUAGE" \ 21 | /bin/judge.py 22 | 23 | ls -lh ${RUNBOX} 24 | 25 | cat ${RUNBOX}/result.code 26 | cat ${RUNBOX}/result.stderr 27 | 28 | # Delete runbox 29 | rm -rf $RUNBOX 30 | --------------------------------------------------------------------------------