diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml new file mode 100644 index 0000000..c006bf4 --- /dev/null +++ b/.buildkite/pipeline.yml @@ -0,0 +1,10 @@ +steps: + - commands: + - docker build --build-arg BUILD_VERSION=$BUILDKITE_COMMIT --build-arg AWS_ACCESS_KEY_ID=AKIAIUEJ6IB7XWPIBUXA --build-arg AWS_SECRET_ACCESS_KEY -t fly:$BUILDKITE_COMMIT . + - docker run --name fly_$BUILDKITE_COMMIT fly:$BUILDKITE_COMMIT /fly --help + - docker cp fly_$BUILDKITE_COMMIT:/fly . && docker cp fly_$BUILDKITE_COMMIT:/fly-dist . + - docker rm fly_$BUILDKITE_COMMIT + - tar -czf fly-linux-x64-static.tar.gz fly fly-dist + - aws s3 cp fly-linux-x64-static.tar.gz s3://fly-proxy/$BUILDKITE_BRANCH/ --acl public-read + artifact_paths: + - ./*.tar.gz \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..cbe36ca --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +target +.envrc +libfly/v8 +*.db +*.bin +.dockerignore +Dockerfile \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..aef67cc --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +msg_generated.ts linguist-generated=true +msg_generated.rs linguist-generated=true \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index e86db1b..b7baf53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: rust rust: -- 1.31.1 +- stable matrix: include: - os: linux @@ -18,7 +18,7 @@ services: env: global: - AWS_ACCESS_KEY_ID=AKIAIUEJ6IB7XWPIBUXA - - SCCACHE_VERSION=0.2.7 + - SCCACHE_VERSION=0.2.8 - SCCACHE_BUCKET=fly-proxy-sccache - RUSTUP_HOME=$HOME/.rustup/ @@ -75,7 +75,8 @@ before_script: createuser -s postgres; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew services start redis; fi script: -- RUST_BACKTRACE=1 cargo test +- RUST_BACKTRACE=1 cargo test --features openssl_vendored +- RUST_BACKTRACE=1 cargo run --features openssl_vendored --bin fly test "v8env/tests/**/*.spec.*" - "./scripts/build-release.sh" - sccache --stop-server before_cache: diff --git a/Cargo.lock b/Cargo.lock index c75b73d..9c53d24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,11 @@ +[[package]] +name = "MacTypes-sys" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "adler32" version = "1.0.3" @@ -8,7 +16,7 @@ name = "aho-corasick" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -26,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arc-swap" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -45,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -61,30 +69,36 @@ name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "backtrace" -version = "0.3.9" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.24" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -115,7 +129,7 @@ dependencies = [ [[package]] name = "base64" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -131,7 +145,7 @@ name = "blake2-rfc" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -146,21 +160,21 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "block-padding" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -170,7 +184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byte-tools" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -189,7 +203,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.25" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -207,8 +221,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -240,28 +254,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "combine" -version = "3.6.3" +version = "3.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "config" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-ini 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -276,7 +290,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -284,7 +298,7 @@ name = "core-foundation-sys" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -302,6 +316,35 @@ dependencies = [ "libfly 0.1.0", ] +[[package]] +name = "crossbeam" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "crossbeam" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-channel" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.2.0" @@ -313,11 +356,11 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -325,7 +368,7 @@ name = "crossbeam-epoch" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -336,12 +379,12 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -357,10 +400,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.6.1" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -374,25 +418,25 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "data-encoding-macro" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "data-encoding-macro-internal 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "data-encoding-macro-internal 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "data-encoding-macro-internal" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -403,9 +447,9 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -438,7 +482,7 @@ name = "dirs" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -447,17 +491,17 @@ dependencies = [ name = "distributed-fly" version = "0.1.0" dependencies = [ - "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "config 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "fly 0.1.0", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.19 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", - "prometheus 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", + "prometheus 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2_redis 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rmp-serde 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -465,12 +509,18 @@ dependencies = [ "rusoto_core 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)", "rusoto_credential 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "rusoto_kms 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sentry 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "sentry 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-stdlog 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-openssl 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -486,7 +536,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "encoding_rs" -version = "0.8.13" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -505,7 +555,7 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -517,7 +567,7 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -526,26 +576,26 @@ name = "error-chain" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -556,7 +606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "fallible-iterator" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -564,7 +614,7 @@ name = "flatbuffers" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -579,48 +629,54 @@ dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "config 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "flatbuffers 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "floating-duration 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.19 (registry+https://github.com/rust-lang/crates.io-index)", + "globwalk 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)", + "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", "ksuid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy-static-include 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy-static-include 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "libfly 0.1.0", "libwebp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "postgres 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "postgres-openssl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "prometheus 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "prometheus 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2_postgres 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2_redis 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "r2d2_sqlite 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2_sqlite 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "redis 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rusqlite 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rusqlite 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-stdlog 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-term 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "sourcemap 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "trust-dns 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trust-dns-resolver 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trust-dns-server 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trust-dns 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "trust-dns-resolver 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", + "trust-dns-server 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -641,6 +697,11 @@ name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fuchsia-cprng" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -666,7 +727,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -695,25 +756,41 @@ dependencies = [ ] [[package]] -name = "glob" -version = "0.2.11" +name = "globset" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "globwalk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "h2" -version = "0.1.13" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -740,13 +817,13 @@ name = "hostname" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "http" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -774,27 +851,27 @@ dependencies = [ [[package]] name = "hyper" -version = "0.12.19" +version = "0.12.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -805,9 +882,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.19 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -817,7 +894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -825,9 +902,26 @@ name = "if_chain" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ignore" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "im" -version = "12.2.0" +version = "12.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -836,7 +930,7 @@ dependencies = [ [[package]] name = "image" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -846,7 +940,8 @@ dependencies = [ "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "safe-transmute 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tiff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -869,7 +964,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -885,6 +980,17 @@ dependencies = [ "winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "isatty" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.3.4" @@ -919,14 +1025,14 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "resize-slice 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy-static-include" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -944,12 +1050,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazycell" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.44" +version = "0.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -966,16 +1072,16 @@ dependencies = [ name = "libfly" version = "0.1.0" dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libsqlite3-sys" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -985,7 +1091,7 @@ name = "libwebp-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1016,6 +1122,14 @@ dependencies = [ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.6" @@ -1052,17 +1166,16 @@ name = "memchr" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1072,7 +1185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mime" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1083,9 +1196,9 @@ name = "mime_guess" version = "2.0.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "mime 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1098,12 +1211,12 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1113,7 +1226,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1134,14 +1247,14 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1151,7 +1264,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1167,21 +1280,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "nom" -version = "4.1.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-derive" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1225,28 +1338,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "opaque-debug" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.10.15" +version = "0.10.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1259,16 +1372,16 @@ name = "openssl-src" version = "111.1.0+1.1.1a" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.39" +version = "0.9.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-src 111.1.0+1.1.1a (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1284,22 +1397,22 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.6.4" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1310,33 +1423,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "phf" -version = "0.7.23" +version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_shared 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_codegen" -version = "0.7.23" +version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_generator 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_generator" -version = "0.7.23" +version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_shared 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_shared" -version = "0.7.23" +version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1350,7 +1463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "png" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1365,7 +1478,7 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "fallible-iterator 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-iterator 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "postgres-protocol 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "postgres-shared 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1377,7 +1490,7 @@ name = "postgres-openssl" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "postgres 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1389,12 +1502,12 @@ dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "fallible-iterator 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-iterator 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "md5 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "stringprep 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1404,11 +1517,11 @@ name = "postgres-shared" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fallible-iterator 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-iterator 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", "postgres-protocol 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1426,7 +1539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.24" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1434,25 +1547,20 @@ dependencies = [ [[package]] name = "prometheus" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "protobuf" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quick-error" -version = "0.2.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1467,10 +1575,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.6.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1504,11 +1612,11 @@ dependencies = [ [[package]] name = "r2d2_sqlite" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "r2d2 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rusqlite 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rusqlite 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1522,74 +1630,75 @@ dependencies = [ [[package]] name = "rand" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.6.1" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1597,7 +1706,7 @@ name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1605,7 +1714,30 @@ name = "rand_isaac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1613,16 +1745,16 @@ name = "rand_pcg" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_xorshift" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1642,8 +1774,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1652,19 +1792,19 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "combine 3.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "combine 3.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.43" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1672,7 +1812,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1681,9 +1821,9 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1692,7 +1832,7 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1700,12 +1840,12 @@ dependencies = [ [[package]] name = "regex" -version = "1.0.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1720,7 +1860,7 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1736,28 +1876,31 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.9.5" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.19 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1770,7 +1913,7 @@ dependencies = [ [[package]] name = "resolv-conf" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1779,12 +1922,13 @@ dependencies = [ [[package]] name = "ring" -version = "0.13.5" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1804,7 +1948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "rmp 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1814,7 +1958,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "rmp 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1827,18 +1971,18 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.19 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "md5 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rusoto_credential 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1851,12 +1995,12 @@ dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.19 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1866,31 +2010,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "rusoto_core 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rusqlite" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libsqlite3-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libsqlite3-sys 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rust-ini" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-demangle" -version = "0.1.9" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1903,15 +2047,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", + "sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1919,6 +2063,11 @@ name = "ryu" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "safe-transmute" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "safemem" version = "0.2.0" @@ -1929,6 +2078,14 @@ name = "safemem" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "same-file" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "schannel" version = "0.1.14" @@ -1958,31 +2115,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "sct" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "security-framework" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "security-framework-sys" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "MacTypes-sys 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2000,42 +2158,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "sentry" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "httpdate 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "im 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "im 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sentry-types 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sentry-types 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "uname 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sentry-types" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "debugid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2050,7 +2208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.80" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2061,7 +2219,7 @@ dependencies = [ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2070,7 +2228,7 @@ name = "serde_bytes" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2093,12 +2251,12 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.82" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2114,12 +2272,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2137,19 +2295,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sha-1" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2173,19 +2331,19 @@ name = "sha2" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "signal-hook" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arc-swap 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2195,12 +2353,71 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "slab" -version = "0.4.1" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "slog" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "slog-async" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "slog-json" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "slog-scope" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "slog-stdlog" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "slog-term" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "smallvec" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2212,8 +2429,8 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2238,6 +2455,11 @@ name = "spin" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "spin" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "stable_deref_trait" version = "1.1.1" @@ -2245,7 +2467,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "string" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2254,7 +2476,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2274,11 +2496,11 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.22" +version = "0.15.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2295,25 +2517,39 @@ name = "synstructure" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "tempfile" version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "term" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termcolor" version = "1.0.4" @@ -2327,8 +2563,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2355,40 +2591,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2398,7 +2635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2407,30 +2644,31 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-executor" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-io" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2444,35 +2682,36 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-reactor" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-rustls" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "rustls 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2481,52 +2720,63 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-sync" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-tcp" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-threadpool" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-timer" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2539,126 +2789,126 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-uds" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trust-dns" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "data-encoding-macro 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "data-encoding-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "radix_trie 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "trust-dns-proto 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trust-dns-proto" -version = "0.5.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trust-dns-resolver" -version = "0.10.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "ipconfig 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "resolv-conf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "trust-dns-proto 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "trust-dns-server" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rusqlite 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-rustls 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rusqlite 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "trust-dns 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "trust-dns 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "trust-dns-proto 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2681,7 +2931,7 @@ name = "uname" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2710,8 +2960,11 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "unicode-width" @@ -2761,7 +3014,7 @@ name = "url_serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2772,11 +3025,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "uuid" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2799,6 +3052,16 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "walkdir" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "want" version = "0.0.6" @@ -2811,10 +3074,10 @@ dependencies = [ [[package]] name = "webpki" -version = "0.18.1" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2849,7 +3112,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2866,7 +3129,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2911,53 +3174,58 @@ dependencies = [ ] [metadata] +"checksum MacTypes-sys 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eaf9f0d0b1cc33a4d2aee14fb4b2eac03462ef4db29c8ac4057327d8a71ad86f" "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" -"checksum arc-swap 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5c5ed110e2537bdd3f5b9091707a8a5556a72ac49bbd7302ae0b28fdccb3246c" +"checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6" "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc" +"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5fc969a8ce2c9c0c4b0429bb8431544f6658283c8326ba5ff8c762b75369335" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" -"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" -"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2" +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "979d348dc50dfcd050a87df408ec61f01a0a27ee9b4ebdc6085baba8275b2c7f" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" -"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" -"checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3" +"checksum block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "509de513cca6d92b6aacf9c61acfe7eaa160837323a81068d690cc1f8e5740da" +"checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" -"checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" -"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" +"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" -"checksum combine 3.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "db733c5d0f4f52e78d4417959cadf0eecc7476e7f9ece05677912571a4af34e2" -"checksum config 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13490293b8a84cc82cd531da41adeae82cd9eaa40e926ac18865aa361f9c9f60" +"checksum combine 3.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3d64b57f9d8186d72311c241e580409b31e5d340c67fd2d9c74f05eda6d3aa54" +"checksum config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e82d07fac0a5eeaa9d959b5194d01bb66e414665f547416958d2b430f8f4852" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" "checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" "checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" +"checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" +"checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" +"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe1b6f945f824c7a25afe44f62e25d714c0cc523f8e99d8db5cd1026e1269d3" +"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2449aaa4ec7ef96e5fb24db16024b935df718e9ae1cec0a1e68feeca2efca7b8" +"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c55913cc2799171a550e307918c0a360e8c16004820291bf3b638969b4a01816" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum crypto-mac 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0999b4ff4d3446d4ddb19a63e9e00c1876e75cd7000d20e57a693b4b3f08d958" -"checksum data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67df0571a74bf0d97fb8b2ed22abdd9a48475c96bd327db968b7d9cace99655e" -"checksum data-encoding-macro 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9864bace8597a3e0cc02c120f678e5def886b428ad584ddb6f784984af21de7d" -"checksum data-encoding-macro-internal 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f40eac430a0f672126b89e606465ff50f1ea468daa42b1547732a78971346d5e" +"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" +"checksum data-encoding-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b87bf377fc964606c3679c1de6822a9a9d8b69aae2651ca4af28cb2d1550b37" +"checksum data-encoding-macro-internal 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "22b318a8d6d56c45df45c61fcc7d2dbf98ea014d4987e7c74ef1f86c9b87e503" "checksum debugid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb088ba9178f59386641547f9c22fd1d658e2d130f02359bb562759f8f992fc" "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" @@ -2965,20 +3233,21 @@ dependencies = [ "checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a" "checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" -"checksum encoding_rs 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1a8fa54e6689eb2549c4efed8d00d7f3b2b994a064555b0e8df4ae3764bcc4be" +"checksum encoding_rs 0.8.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fd251508d65030820f3a4317af2248180db337fdb25d89967956242580277813" "checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" "checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" "checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e" "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" -"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7" -"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fallible-iterator 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea79295a7a3e0d77f19e763cf1fe7189cd95fc2b36735ea0ea6b711a7380f509" +"checksum fallible-iterator 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eb7217124812dc5672b7476d0c2d20cfe9f7c0f1ba0904b674a9762a0212f72e" "checksum flatbuffers 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea0c34f669be9911826facafe996adfda978aeee67285a13556869e2d8b8331f" "checksum floating-duration 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2c60b71d9dbcd810a3be879dc9aafac6cec5c50dc2346e245f61f54a61fdf22" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +"checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" @@ -2986,52 +3255,56 @@ dependencies = [ "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4bca55ac1f213920ce3527ccd62386f1f15fa3f1714aeee1cf93f2c416903f" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum h2 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd33bafe2e6370e6c8eb0cf1b8c5f93390b90acde7e9b03723f166b28b648ed" +"checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865" +"checksum globwalk 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4be0267260c9bb4e278dfb2291de9518a595cb625cf6f5f385c4b7d8d1aa7112" +"checksum h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb2b25a33e231484694267af28fec74ac63b5ccf51ee2065a5e313b834d836e" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44f3bdb08579d99d7dc761c0e266f13b5f2ab8c8c703b9fc9ef333cd8f48f55e" "checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" -"checksum http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "02096a6d2c55e63f7fcb800690e4f889a25f6ec342e3adb4594e293b625215ab" +"checksum http 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1a10e5b573b9a0146545010f50772b9e8b1dd0a256564cc4307694c68832a2f5" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum httpdate 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum hyper 0.12.19 (registry+https://github.com/rust-lang/crates.io-index)" = "f1ebec079129e43af5e234ef36ee3d7e6085687d145b7ea653b262d16c6b65f1" +"checksum hyper 0.12.23 (registry+https://github.com/rust-lang/crates.io-index)" = "860faf61a9957c9cb0e23e69f1c8290e92f6eb660fcdd1f2d6777043a2ae1a46" "checksum hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32cd73f14ad370d3b4d4b7dce08f69b81536c82e39fcc89731930fe5788cd661" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec" -"checksum im 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9c7f9bb8aee47fc16d535a705f7867a9fc83bb822e5e1043bb98e77ffeed3c" -"checksum image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44665b4395d1844c96e7dc8ed5754782a1cdfd9ef458a80bbe45702681450504" +"checksum ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ad03ca67dc12474ecd91fdb94d758cbd20cb4e7a78ebe831df26a9b7511e1162" +"checksum im 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0627d417829c1d763d602687634869f254fc79f7e22dea6c824dab993db857e4" +"checksum image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "52fb0666a1273dac46f9725aa4859bcd5595fc3554cf3495051b4de8db745e7d" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum inflate 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "84c683bde2d8413b8f1be3e459c30e4817672b6e7a31d9212b0323154e76eba7" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum ipconfig 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "08f7eadeaf4b52700de180d147c4805f199854600b36faa963d91114827b2ffc" +"checksum isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e31a8281fc93ec9693494da65fbf28c0c2aa60a2eaec25dc58e2f31952e95edc" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum ksuid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "42729258604bc3c02a3502ca8cb070d044fef73d75c657bec0fe5d51bfac8d24" -"checksum lazy-static-include 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9be5ac0d6c5bc72d810006a40475b4ebd1e551a825ee26db94b3d7da2702a3ed" +"checksum lazy-static-include 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "43087a116fcad74e41cb5934cbed3c219892f2f5ded8ce10acb3d87136239fe7" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -"checksum lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddba4c30a78328befecec92fc94970e53b3ae385827d28620f0f5bb2493081e0" -"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311" +"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" +"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "bff3ac7d6f23730d3b533c35ed75eef638167634476a499feef16c428d74b57b" -"checksum libsqlite3-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "742b695cbfb89e549dca6960a55e6802f67d352e33e97859ee46dee835211b0f" +"checksum libsqlite3-sys 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3567bc1a0c84e2c0d71eeb4a1f08451babf7843babd733158777d9c686dad9f3" "checksum libwebp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e70c064738b35a28fd6f991d27c0d9680353641d167ae3702a8228dd8272ef6" "checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum md5 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "79c56d6a0b07f9e19282511c83fc5b086364cbae4ba8c7d5f190c3d9b0425a48" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" -"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16" +"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum mime 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0a907b83e7b9e987032439a387e187119cddafc92d5c2aaeb1d92580a793f630" +"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425" "checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" @@ -3040,156 +3313,170 @@ dependencies = [ "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nibble_vec 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8d77f3db4bce033f4d04db08079b2ef1c3d02b44e86f25d08886fafa7756ffa" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a" -"checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d" +"checksum nom 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b30adc557058ce00c9d0d7cb3c6e0b5bc6f36e2e2eabe74b0ba726d194abd588" +"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51ecbcb821e1bd256d456fe858aaa7f380b63863eab2eb86eee1bd9f33dd6682" -"checksum openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "5e1309181cdcbdb51bc3b6bedb33dfac2a83b3d585033d3f6d9e22e8c1928613" +"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" +"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" +"checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-src 111.1.0+1.1.1a (registry+https://github.com/rust-lang/crates.io-index)" = "26bb632127731bf4ac49bf86a5dde12d2ca0918c2234fc39d79d4da2ccbc6da7" -"checksum openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)" = "278c1ad40a89aa1e741a1eed089a2f60b18fab8089c3139b542140fc7d674106" +"checksum openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)" = "1bb974e77de925ef426b6bc82fce15fd45bdcbeb5728bffcfc7cdeeb7ce1c2d6" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" -"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" +"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum phf 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "cec29da322b242f4c3098852c77a0ca261c9c01b806cae85a5572a1eb94db9a6" -"checksum phf_codegen 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "7d187f00cd98d5afbcd8898f6cf181743a449162aeb329dcd2f3849009e605ad" -"checksum phf_generator 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "03dc191feb9b08b0dc1330d6549b795b9d81aec19efe6b4a45aec8d4caee0c4b" -"checksum phf_shared 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "b539898d22d4273ded07f64a05737649dc69095d92cb87c7097ec68e3f150b93" +"checksum phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" +"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" +"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" +"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" -"checksum png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f54b9600d584d3b8a739e1662a595fab051329eff43f20e7d8cc22872962145b" +"checksum png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9adebf7fb91ccf5eac9da1a8e00e83cb8ae882c3e8d8e4ad59da73cb8c82a2c9" "checksum postgres 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "115dde90ef51af573580c035857badbece2aa5cde3de1dfb3c932969ca92a6c5" "checksum postgres-openssl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "721a16be77e943e19a763d8e81788684174ecd8fa80b5a5fd8f9af79a36f9479" "checksum postgres-protocol 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2487e66455bf88a1b247bf08a3ce7fe5197ac6d67228d920b0ee6a0e97fd7312" "checksum postgres-shared 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ffac35b3e0029b404c24a3b82149b4e904f293e8ca4a327eefa24d3ca50df36f" "checksum proc-macro-hack 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c725b36c99df7af7bf9324e9c999b9e37d92c8f8caf106d82e1d7953218d2d8" "checksum proc-macro-hack-impl 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b753ad9ed99dd8efeaa7d2fb8453c8f6bc3e54b97966d35f1bc77ca6865254a" -"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" -"checksum prometheus 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "760293453bee1de0a12987422d7c4885f7ee933e4417bb828ed23f7d05c3c390" -"checksum protobuf 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbd08d128db199b1c6bb662e343d7d1a8f6d0060b411675766d88e5146a4bb38" -"checksum quick-error 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ac990ab4e038dd8481a5e3fd00641067fcfc674ad663f3222752ed5284e05d4" +"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum prometheus 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48e3f33ff50a88c73ad8458fa6c22931aa7a6e19bb4a95d62816618c153b3f02" +"checksum protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82d117bc7565ce6be0150159251c9b1eeec7b129f5a2aa86e10acb5970de1cb" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" +"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum r2d2 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5d746fc8a0dab19ccea7ff73ad535854e90ddb3b4b8cdce953dd5cd0b2e7bd22" "checksum r2d2_postgres 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "78c7fe9c0c3d2c298cf262bc3ce4b89cdf0eab620fd9fe759f65b34a1a00fb93" "checksum r2d2_redis 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98318a90bb5f4990e084cd54e875aedb794f73dcef8668287cc74e875955b9db" -"checksum r2d2_sqlite 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce466d46abbb1b52280818d3fdb300f456f7cc90a899e1ab4f6890aa3aeae909" +"checksum r2d2_sqlite 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7cba990b29ae565b1a765ef45f6b84a89a77736b91582e0243c12f613653857" "checksum radix_trie 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ebcf72e767017c1aa4b63d4dd0b0b836a243b648fd81d41c6bf6e850ef7a95c7" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" -"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" -"checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" -"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" +"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" +"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" -"checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redis 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c747d743d48233f9bc3ed3fb00cb84c1d98d8c7f54ed2d4cca9adf461a7ef3" -"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d" +"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26" "checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" -"checksum regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ee84f70c8c08744ea9641a731c7fadb475bf2ecc52d7f627feb833e0b3990467" +"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" -"checksum regex-syntax 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fbc557aac2b708fe84121caf261346cc2eed71978024337e42eb46b8a252ac6e" +"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum reqwest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ab52e462d1e15891441aeefadff68bdea005174328ce3da0a314f2ad313ec837" +"checksum reqwest 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "09d6e187a58d923ee132fcda141c94e716bcfe301c2ea2bef5c81536e0085376" "checksum resize-slice 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a3cb2f74a9891e76958b9e0ccd269a25b466c3ae3bb3efd71db157248308c4a" -"checksum resolv-conf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c62bd95a41841efdf7fca2ae9951e64a8d8eae7e5da196d8ce489a2241491a92" -"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" +"checksum resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b263b4aa1b5de9ffc0054a2386f96992058bb6870aab516f8cdeb8a667d56dcb" +"checksum ring 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a47f25c9d9eb3279cbf39913d58e1260ab4adc4b0841da3f6d72cd5cc31feb34" "checksum rmp 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a3d45d7afc9b132b34a2479648863aa95c5c88e98b32285326a6ebadc80ec5c9" "checksum rmp-serde 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "011e1d58446e9fa3af7cdc1fb91295b10621d3ac4cb3a85cc86385ee9ca50cd3" "checksum rmpv 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29af0205707de955a396a1d3c657677c65f791ebabb63c0596c0b2fec0bf6325" "checksum rusoto_core 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9be4aac9e74cc9bc3401a77fe2bfe72bb603c2e4fcf7bf68ada89c2b0fd7049d" "checksum rusoto_credential 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a331ddbb4cbc2f99464092cb3dcded64af9ea1e009f4ef719c9fa1130731992" "checksum rusoto_kms 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6929a4ed3ea49db48c499b1f0fab34a8bb14915bbc60ce963adabc76c29781d1" -"checksum rusqlite 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39bae767eb27866f5c0be918635ae54af705bc09db11be2c43a3c6b361cf3462" -"checksum rust-ini 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ac66e816614e124a692b6ac1b8437237a518c9155a3aacab83a373982630c715" -"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" +"checksum rusqlite 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6381ddfe91dbb659b4b132168da15985bc84162378cf4fcdc4eb99c857d063e2" +"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" +"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b7891791343c75b73ed9a18cadcafd8c8563d11a88ebe2d87f5b8a3182654d9" +"checksum rustls 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "38af00e78b66109e7184a0ee16940f41583161b7ec0518af258e4bcaed15db25" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" +"checksum safe-transmute 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9604873ffe1980bc1f179103704a65c8aca141c248d9e52b7af95ff10578166e" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" +"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" "checksum scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a2ff3fc5223829be817806c6441279c676e454cc7da608faf03b0ccc09d3889" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" -"checksum security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "697d3f3c23a618272ead9e1fb259c1411102b31c6af8b93f1d64cca9c3b0e8e0" -"checksum security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab01dfbe5756785b5b4d46e0289e5a18071dfa9a7c2b24213ea00b9ef9b665bf" +"checksum sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f5adf8fbd58e1b1b52699dc8bed2630faecb6d8c7bee77d009d6bbe4af569b9" +"checksum security-framework 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfab8dda0e7a327c696d893df9ffa19cadc4bd195797997f5223cf5831beaf05" +"checksum security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3d6696852716b589dff9e886ff83778bb635150168e83afa8ac6b8a78cb82abc" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum sentry 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b565ae999bf4a6399a95315b110560432a8958a207474749b91ea2a078a2bece" -"checksum sentry-types 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1108bf605cb7f136bea4d30d24c9e255ab16ea610a74e004c02d673a2247f6cf" +"checksum sentry 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b85d01c9f486937cf0972435475de7a8ad84e2f85201c7a1891ae70301d5f07" +"checksum sentry-types 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d4120ca636ad2934528f5fbceeb22a80f0c9160b0400136cb05fbaa37d5c484" "checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" "checksum serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" -"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef" +"checksum serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "534b8b91a95e0f71bca3ed5824752d558da048d4248c91af873b63bd60519752" "checksum serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153" "checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3" "checksum serde_codegen_internals 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bc888bd283bd2420b16ad0d860e35ad8acb21941180a83a189bb2046f9d00400" "checksum serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "978fd866f4d4872084a81ccc35e275158351d3b9fe620074e7d7504b816b74ba" -"checksum serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "96a7f9496ac65a2db5929afa087b54f8fc5008dcfbe48a8874ed20049b0d6154" +"checksum serde_derive 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)" = "a915306b0f1ac5607797697148c223bedeaa36bcc2e28a01441cd638cc6567b4" "checksum serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ad8bcf487be7d2e15d3d543f04312de991d631cfe1b43ea0ade69e6a8a5b16a1" -"checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811" +"checksum serde_json 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "4b90a9fbe1211e57d3e1c15670f1cb00802988fb23a1a4aad7a2b63544f1920e" "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" "checksum serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d48f9f99cd749a2de71d29da5f948de7f2764cc5a9d7f3c97e3514d4ee6eabf2" -"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" +"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum signal-hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8941ae94fa73d0f73b422774b3a40a7195cecd88d1c090f4b37ade7dc795ab66" +"checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" -"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" -"checksum smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "622df2d454c29a4d89b30dc3b27b42d7d90d6b9e587dbf8f67652eb7514da484" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +"checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" +"checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" +"checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" +"checksum slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "60c04b4726fa04595ccf2c2dad7bcd15474242c4c5e109a8a376e8a2c9b1539a" +"checksum slog-stdlog 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ac42f8254ae996cc7d640f9410d3b048dcdf8887a10df4d5d4c44966de24c4a8" +"checksum slog-term 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5951a808c40f419922ee014c15b6ae1cd34d963538b57d8a4778b9ca3fff1e0b" +"checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15" "checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" "checksum sourcemap 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "febeea08fbed8ee59d9a784035669cb96123279459a28866e6dd76a7834ba32b" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" +"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum string 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98998cced76115b1da46f63388b909d118a37ae0be0f82ad35773d4a4bc9d18d" +"checksum string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b639411d0b9c738748b5397d5ceba08e648f4f1992231aa859af1a017f31f60b" "checksum stringprep 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" +"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2" +"checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum tiff 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a2cc6c4fd13cb1cfd20abdb196e794ceccb29371855b7e7f575945f920a5b3c2" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "a7817d4c98cc5be21360b3b37d6036fe9b7aefa5b7a201b7b16ff33423822f7d" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "e0500b88064f08bebddd0c0bed39e19f5c567a5f30975bee52b0c0d3e2eeb38c" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" "checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" -"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde" -"checksum tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "60ae25f6b17d25116d2cba342083abe5255d3c2c79cb21ea11aa049c53bf7c75" -"checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21" +"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" +"checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d" +"checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f" "checksum tokio-openssl 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771d6246b170ae108d67d9963c23f31a579016c016d73bd4bd7d6ef0252afda7" -"checksum tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "502b625acb4ee13cbb3b90b8ca80e0addd263ddacf6931666ef751e610b07fb5" -"checksum tokio-rustls 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c98c5346e4231382951111f42f4651094854462297370a08f0fba57a3b92576" +"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f" +"checksum tokio-rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7223fa02f4b2d9f3736f13cc3dea3723aaec57ca4b3dded922126ebbb2cb8ce9" "checksum tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd6dc5276ea05ce379a16de90083ec80836440d5ef8a6a39545a3207373b8296" -"checksum tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad235e9dadd126b2d47f6736f65aa1fdcd6420e66ca63f44177bc78df89f912" -"checksum tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "56c5556262383032878afad66943926a1d1f0967f17e94bd7764ceceb3b70e7f" -"checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" +"checksum tokio-sync 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d65a58e2215c13179e6eeb2cf00511e0aee455cad40a9bfaef15a2fd8aab1c7" +"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" +"checksum tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c3fd86cb15547d02daa2b21aadaf4e37dee3368df38a526178a5afa3c034d2fb" +"checksum tokio-timer 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "21c04a314a1f69f73c0227beba6250e06cdc1e9a62e7eff912bf54a59b6d1b94" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" -"checksum tokio-uds 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "99ce87382f6c1a24b513a72c048b2c8efe66cb5161c9061d00bee510f08dc168" -"checksum toml 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "19782e145d5abefb03758958f06ea35f7b1d8421b534140e0238fd3d0bfd66e3" -"checksum trust-dns 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9b3df6034a7e2836b5300e6a1dd5648a4e8fdd62729331ed05027ea16de8e4" -"checksum trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0838272e89f1c693b4df38dc353412e389cf548ceed6f9fd1af5a8d6e0e7cf74" -"checksum trust-dns-resolver 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e913a5df94658858e548cc95a3212797ee524e487ede091c32f27ca26e11620" -"checksum trust-dns-server 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92ee7757f2490879634b3fcc9fb837aeb57f610ed7e1e1409b30670d815c788a" +"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +"checksum trust-dns 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "65096825b064877da37eeeb9a83390bd23433eabfc503a6476dc5b1949034aa7" +"checksum trust-dns-proto 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09144f0992b0870fa8d2972cc069cbf1e3c0fda64d1f3d45c4d68d0e0b52ad4e" +"checksum trust-dns-resolver 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a9f877f7a1ad821ab350505e1f1b146a4960402991787191d6d8cab2ce2de2c" +"checksum trust-dns-server 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9df6e61b1fac710748860b25650515bb36389e8fca3ba8cb58785550572813f" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" @@ -3197,7 +3484,7 @@ dependencies = [ "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" +"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" @@ -3207,19 +3494,20 @@ dependencies = [ "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" -"checksum uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dab5c5526c5caa3d106653401a267fed923e7046f35895ffcb5ca42db64942e6" +"checksum uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0238db0c5b605dd1cf51de0f21766f97fba2645897024461d6a00c036819a768" "checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" -"checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" +"checksum webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f7e1cd7900a3a6b65a3e8780c51a3e6b59c0e2c55c6dc69578c288d69f7d082" "checksum widestring 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7157704c2e12e3d2189c507b7482c52820a16dfa4465ba91add92f266667cadb" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" diff --git a/Cargo.toml b/Cargo.toml index f48fa77..026cbfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,56 +5,68 @@ authors = ["Jerome Gravel-Niquet "] edition = "2018" publish = false +[profile.release] +debug = true + [dependencies] -bytes = "0.4" -chrono = "0.4" -clap = "2.32" -config = "0.9" -env_logger = "*" -flatbuffers = "0.5" -floating-duration = "0.1" +bytes = "0.4.11" +chrono = "0.4.6" +clap = "2.32.0" +config = "0.9.2" +flatbuffers = "0.5.0" +floating-duration = "0.1.2" futures = "0.1.25" -glob = "0.2" -http = "*" -hyper = "0.12" -hyper-tls = "0.3" -image = "0.20" -ksuid = "0.2" -lazy_static = "1.1" -lazy-static-include = "1.2" -libc = "*" +globwalk = "0.6" +http = "0.1.15" +hyper = "0.12.23" +hyper-tls = "0.3.1" +image = "0.21.0" +ksuid = "0.2.0" +lazy_static = "1.2.0" +lazy-static-include = "1.2.2" +libc = "0.2.48" libfly = { path = "libfly" } -libwebp-sys = "0.2" -log = "*" -openssl = {version="0.10", features=["vendored"]} -postgres = {version="0.15", features=["with-serde_json"]} -postgres-openssl = "0.1" -prometheus = "0.4" -r2d2 = "0.8" -r2d2_postgres = "0.14" -r2d2_redis = "0.8" -r2d2_sqlite = "0.7" -rand = "0.5" -redis = "0.9" -rusqlite = {version="0.15", features=["bundled", "blob", "chrono"]} -serde = "1" -serde_derive = "1" -serde_json = "1.0" -sha-1 = "0.7" -sha2 = "0.7" -sourcemap = "2.2" -tokio = "0.1" -tokio-signal = "0.2" -tokio-udp = "0.1" -trust-dns = "0.15" -trust-dns-proto = "*" -trust-dns-resolver = "0.10" -trust-dns-server = "0.15" -url = "1.7" +libwebp-sys = "0.2.0" +log = "0.4.6" +postgres = { version = "0.15.2", features = ["with-serde_json"] } +postgres-openssl = "0.1.0" +prometheus = "0.5.0" +r2d2 = "0.8.3" +r2d2_postgres = "0.14.0" +r2d2_redis = "0.8.0" +r2d2_sqlite = "0.8.0" +rand = "0.6.5" +redis = "0.9.1" +rusqlite = { version = "0.16.0", features = ["bundled", "blob", "chrono"] } +serde = { version = "1.0.85", default-features = false } +serde_derive = "1.0.85" +serde_json = "1.0.37" +sha-1 = "0.8.1" +sha2 = "0.8.0" +slog = { version = "2.4.1", features = ["max_level_debug", "release_max_level_info"] } +slog-async = "2.3.0" +slog-json = "2.3.0" +slog-scope = "4.1.1" +slog-stdlog = "3.0.2" +slog-term = "2.4.0" +sourcemap = "2.2.1" +tempfile = "3.0.5" +tokio = "0.1.15" +tokio-udp = "0.1.3" +tokio-signal = "*" +trust-dns = "0.15.1" +trust-dns-resolver = "0.10.3" +trust-dns-server = "0.15.1" +url = "1.7.2" +openssl = "0.10.16" +uuid = { version = "0.7", features = ["v4"] } [workspace] members = [ "libfly", "distributed-fly", "create_snapshot" -] \ No newline at end of file +] + +[features] +openssl_vendored = ["openssl/vendored"] \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 976b055..7203629 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,57 +1,193 @@ -FROM node:10-stretch as v8env +FROM alpine:3.8 AS sccache + +WORKDIR /tmp +RUN wget --no-check-certificate -qO- https://github.com/mozilla/sccache/releases/download/0.2.8/sccache-0.2.8-x86_64-unknown-linux-musl.tar.gz | tar xvz \ + && mv sccache-0.2.8-x86_64-unknown-linux-musl/sccache . + +FROM alpine:3.8 as libv8 + +LABEL repository.hub="alexmasterov/alpine-libv8:7.2" \ + repository.url="https://github.com/AlexMasterov/dockerfiles" \ + maintainer="Alex Masterov " + +ARG V8_VERSION=7.2.505 +ARG V8_DIR=/usr/local/v8 + +ARG BUILD_COMMIT=5a371bcc0efe2cc84f384f14bdf5eaf5fe3e271a +ARG BUILDTOOLS_COMMIT=13a00f110ef910a25763346d6538b60f12845656 +ARG ICU_COMMIT=407b39301e71006b68bd38e770f35d32398a7b14 +ARG GTEST_COMMIT=2e68926a9d4929e9289373cd49e40ddcb9a628f7 +ARG TRACE_EVENT_COMMIT=211b3ed9d0481b4caddbee1322321b86a483ca1f +ARG CLANG_COMMIT=3041f30dd6b3fa4fb8ca7db6439bed372f4accc0 +ARG JINJA2_COMMIT=b41863e42637544c2941b574c7877d3e1f663e25 +ARG MARKUPSAFE_COMMIT=8f45f5cfa0009d2a70589bcda0349b8cb2b72783 +ARG CATAPULT_COMMIT=ed6fe0f638403e1afd377e38975e4fd430f53432 + +ARG GN_SOURCE=https://www.dropbox.com/s/3ublwqh4h9dit9t/alpine-gn-80e00be.tar.gz +ARG V8_SOURCE=https://chromium.googlesource.com/v8/v8/+archive/${V8_VERSION}.tar.gz + +ENV V8_VERSION=${V8_VERSION} \ + V8_DIR=${V8_DIR} + +RUN set -x \ + && apk add --update --virtual .v8-build-dependencies \ + at-spi2-core-dev \ + curl \ + g++ \ + gcc \ + glib-dev \ + icu-dev \ + linux-headers \ + make \ + ninja \ + python \ + tar \ + xz \ + && : "---------- V8 ----------" \ + && mkdir -p /tmp/v8 \ + && curl -fSL --connect-timeout 30 ${V8_SOURCE} | tar xmz -C /tmp/v8 \ + && : "---------- Dependencies ----------" \ + && DEPS=" \ + chromium/buildtools.git@${BUILDTOOLS_COMMIT}:buildtools; \ + chromium/src/build.git@${BUILD_COMMIT}:build; \ + chromium/src/base/trace_event/common.git@${TRACE_EVENT_COMMIT}:base/trace_event/common; \ + chromium/src/tools/clang.git@${CLANG_COMMIT}:tools/clang; \ + chromium/src/third_party/jinja2.git@${JINJA2_COMMIT}:third_party/jinja2; \ + chromium/src/third_party/markupsafe.git@${MARKUPSAFE_COMMIT}:third_party/markupsafe; \ + chromium/deps/icu.git@${ICU_COMMIT}:third_party/icu; \ + external/github.com/google/googletest.git@${GTEST_COMMIT}:third_party/googletest/src; \ + catapult.git@${CATAPULT_COMMIT}:third_party/catapult \ + " \ + && while [ "${DEPS}" ]; do \ + dep="${DEPS%%;*}" \ + link="${dep%%:*}" \ + url="${link%%@*}" url="${url#"${url%%[![:space:]]*}"}" \ + hash="${link#*@}" \ + dir="${dep#*:}"; \ + [ -n "${dep}" ] \ + && dep_url="https://chromium.googlesource.com/${url}/+archive/${hash}.tar.gz" \ + && dep_dir="/tmp/v8/${dir}" \ + && mkdir -p ${dep_dir} \ + && curl -fSL --connect-timeout 30 ${dep_url} | tar xmz -C ${dep_dir} \ + & [ "${DEPS}" = "${dep}" ] && DEPS='' || DEPS="${DEPS#*;}"; \ + done; \ + wait \ + && : "---------- Downloads the current stable Linux sysroot ----------" \ + && /tmp/v8/build/linux/sysroot_scripts/install-sysroot.py --arch=amd64 \ + && : "---------- Proper GN ----------" \ + && apk add --virtual .gn-runtime-dependencies \ + libevent \ + libexecinfo \ + libstdc++ \ + && curl -fSL --connect-timeout 30 ${GN_SOURCE} | tar xmz -C /tmp/v8/buildtools/linux64/ + +ARG AWS_ACCESS_KEY_ID +ARG AWS_SECRET_ACCESS_KEY + +COPY --from=sccache /tmp/sccache /usr/bin/sccache + +ENV SCCACHE_BUCKET=fly-proxy-sccache \ + AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \ + AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY + +RUN : "---------- Build instructions ----------" \ + && sccache --start-server \ + && cd /tmp/v8 \ + && ./tools/dev/v8gen.py \ + x64.release -- \ + cc_wrapper=\"sccache\" \ + binutils_path=\"/usr/bin\" \ + target_os=\"linux\" \ + target_cpu=\"x64\" \ + v8_target_cpu=\"x64\" \ + v8_use_external_startup_data=false \ + v8_use_snapshot = true \ + v8_enable_future=true \ + is_official_build=true \ + is_cfi=false \ + is_clang=false \ + use_custom_libcxx=false \ + use_sysroot=false \ + use_gold=false \ + use_allocator_shim=false \ + treat_warnings_as_errors=false \ + symbol_level=0 \ + v8_monolithic = true \ + use_jumbo_build = true \ + && : "---------- Build ----------" \ + && ninja d8 -C out.gn/x64.release/ -j $(getconf _NPROCESSORS_ONLN) v8_monolith \ + && sccache --stop-server + +RUN : "---------- Extract shared libraries ----------" \ + && mkdir -p ${V8_DIR}/include ${V8_DIR}/lib \ + && cp -R /tmp/v8/include/* ${V8_DIR}/include/ \ + && (cd /tmp/v8/out.gn/x64.release; \ + cp obj/lib*.a icudtl.dat ${V8_DIR}/lib/) + +RUN : "---------- Removing build dependencies, clean temporary files ----------" \ + && apk del .v8-build-dependencies .gn-runtime-dependencies \ + && rm -rf /var/cache/apk/* /var/tmp/* /tmp/* -COPY --from=neomantra/flatbuffers:20180924 /usr/local/bin/flatc /usr/local/bin/flatc +FROM node:10-stretch as v8env WORKDIR /v8env COPY v8env/package.json package.json RUN yarn install ADD v8env/ . +ADD scripts/build-version.sh ../scripts/build-version.sh -ADD msg.fbs . -RUN flatc --ts -o src --no-fb-import --gen-mutable msg.fbs +ARG BUILD_VERSION +ENV BUILD_VERSION=$BUILD_VERSION RUN ./node_modules/.bin/rollup -c RUN ls -lah dist -FROM flyio/v8:7.1 as v8 - -FROM liuchong/rustup:1.29.1 as builder - -RUN apt-get update -qq \ - && apt-get install -y --no-install-recommends \ - ca-certificates build-essential pkg-config git curl python libxml2 libxml2-dev \ - clang-3.8 libc++-dev libc++abi-dev llvm \ - && rm -rf /var/lib/apt/lists/* +FROM alpine:edge as builder WORKDIR /usr/src/myapp -COPY --from=neomantra/flatbuffers:20180924 /usr/local/bin/flatc /usr/local/bin/flatc +RUN apk --no-cache add rust cargo g++ openssl openssl-dev COPY libfly libfly -COPY --from=v8 /v8/lib libfly/third_party/v8/out.gn/lib/obj -COPY . . +COPY --from=libv8 /usr/local/v8/lib libfly/v8/out.gn/lib/obj +COPY --from=libv8 /usr/local/v8/include libfly/v8/include +COPY --from=v8env v8env/ v8env/ -RUN ls -l third_party/flatbuffers +ADD . ./ -RUN touch v8env.bin && mkdir -p v8env/dist && touch v8env/dist/v8env.js.map -RUN cargo build --release --bin create_snapshot +ARG AWS_ACCESS_KEY_ID +ARG AWS_SECRET_ACCESS_KEY -RUN ls -lah target/release +COPY --from=sccache /tmp/sccache /usr/bin/sccache -COPY --from=v8env v8env/ v8env/ +ENV RUSTFLAGS="-C target-feature=+crt-static"\ + OPENSSL_STATIC=yes\ + OPENSSL_LIB_DIR=/usr/lib\ + OPENSSL_INCLUDE_DIR=/usr/include/openssl \ + SCCACHE_BUCKET=fly-proxy-sccache \ + RUSTC_WRAPPER=/usr/bin/sccache \ + AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \ + AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY + +RUN sccache --start-server \ + && cargo build --release -p create_snapshot \ + && sccache --stop-server RUN target/release/create_snapshot v8env/dist/v8env.js v8env.bin -RUN cargo build --release +ARG BUILD_VERSION +ENV BUILD_VERSION=$BUILD_VERSION -RUN ls -lah target/release +RUN sccache --start-server \ + && cargo build --target x86_64-alpine-linux-musl --no-default-features --release -p distributed-fly \ + && cargo build --target x86_64-alpine-linux-musl --no-default-features --release --bin fly \ + && sccache --stop-server -RUN ldd target/release/server +FROM scratch -RUN strip target/release/server && strip target/release/dns +COPY --from=builder /usr/src/myapp/target/x86_64-alpine-linux-musl/release/distributed-fly /fly-dist +COPY --from=builder /usr/src/myapp/target/x86_64-alpine-linux-musl/release/fly /fly -FROM liuchong/rustup:1.29.1 as bin -COPY --from=builder /usr/src/myapp/target/release/server /app/server -COPY --from=builder /usr/src/myapp/target/release/dns /app/dns \ No newline at end of file +CMD ["/fly"] \ No newline at end of file diff --git a/README.md b/README.md index e1ee115..58cc2e9 100644 --- a/README.md +++ b/README.md @@ -93,8 +93,14 @@ There's an issue: [#5](https://github.com/superfly/fly.rs/issues/5) - `cd ..` - `cargo run --bin dns hello-world.js` -### Running v8env tests (currently not working) +### Running tests +1. Runtime tests: +```bash +cargo test ``` -cargo run --bin test "v8env/tests/**/*.spec.js" + +2. Javascript tests +``` +cargo run --bin fly test "v8env/tests/**/*.spec.js" ``` diff --git a/build.rs b/build.rs index 068be68..fbc69ab 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,6 @@ use std::process::Command; fn main() { - let output = Command::new("sh").arg("./scripts/build-number.sh").output().unwrap(); - let git_hash = String::from_utf8(output.stdout).unwrap(); - println!("cargo:rustc-env=GIT_HASH={}", git_hash.to_string()); -} + let output = Command::new("sh").arg("./scripts/build-version.sh").output().unwrap(); + println!("cargo:rustc-env=BUILD_VERSION={}", String::from_utf8(output.stdout).unwrap()); +} \ No newline at end of file diff --git a/distributed-fly/Cargo.toml b/distributed-fly/Cargo.toml index 84bb4c8..cd143d9 100644 --- a/distributed-fly/Cargo.toml +++ b/distributed-fly/Cargo.toml @@ -5,28 +5,37 @@ authors = ["Jerome Gravel-Niquet "] edition = "2018" [dependencies] +base64 = "0.10" +bytes = "*" +chrono = "0.4.6" +config = "0.9" fly = { path="../" } -env_logger = "*" -log = "*" -lazy_static = "1.1" -tokio = "0.1" futures = "0.1" hyper = "0.12" -openssl = {version="0.10",features=["vendored"]} -tokio-openssl = "0.3" +lazy_static = "1.1" +log = {version="*", features = ["max_level_debug", "release_max_level_info"] } +prometheus = "0.5" r2d2 = "*" r2d2_redis = "*" rmp-serde = "0.13.7" rmpv = {version="0.4", features=["with-serde"]} -serde_derive = "1" -serde = "1" -serde_json = "*" +serde = {version="1.0",default-features = false} +serde_derive = "1.0" +serde_json = "1.0" rusoto_core = "0.35" -rusoto_kms = "0.35" rusoto_credential = "0.14" -base64 = "0.10" -config = "0.9" +rusoto_kms = "0.35" +sentry = { version = "0.13", features = ["with_panic", "with_log", "with_backtrace", "with_device_info", "with_rust_info"] } sha2 = "0.8" -bytes = "*" -prometheus = "0.4" -sentry = "0.12" +slog = {version="2.4.1", features = ["max_level_debug", "release_max_level_info"] } +slog-async = "2.3.0" +slog-json = "2.3.0" +slog-scope = "4.1.1" +slog-stdlog = "3.0.2" +tempfile = "3.0.5" +tokio = "0.1" +tokio-openssl = "0.3" +openssl = "0.10.16" + +[features] +openssl_vendored = ["openssl/vendored"] \ No newline at end of file diff --git a/distributed-fly/src/cert.rs b/distributed-fly/src/cert.rs index a15b6fc..e9f2e3b 100644 --- a/distributed-fly/src/cert.rs +++ b/distributed-fly/src/cert.rs @@ -5,12 +5,103 @@ use std::sync::RwLock; use super::REDIS_POOL; use crate::kms::decrypt; +use crate::settings::GLOBAL_SETTINGS; use r2d2_redis::redis; lazy_static! { static ref CTX_STORE: RwLock> = RwLock::new(HashMap::new()); + static ref SESSION_CACHE: RwLock, ssl::SslSession>> = + RwLock::new(HashMap::new()); + static ref DEFAULT_CTX: ssl::SslContext = { + let mut builder = ssl::SslContextBuilder::new(ssl::SslMethod::tls()).unwrap(); + + setup_base_ctx(&mut builder); + + let certs_path = { + match GLOBAL_SETTINGS.read().unwrap().certs_path { + Some(ref cp) => cp.clone(), + None => "certs".to_string(), + } + }; + builder + .set_certificate_file( + &format!("{}/default.crt", certs_path), + openssl::ssl::SslFiletype::PEM, + ) + .unwrap(); + builder + .set_private_key_file( + &format!("{}/default.pem", certs_path), + openssl::ssl::SslFiletype::PEM, + ) + .unwrap(); + builder + .set_certificate_file( + &format!("{}/default.ecdsa.crt", certs_path), + openssl::ssl::SslFiletype::PEM, + ) + .unwrap(); + builder + .set_private_key_file( + &format!("{}/default.ecdsa.pem", certs_path), + openssl::ssl::SslFiletype::PEM, + ) + .unwrap(); + builder.build() + }; +} + +fn setup_base_ctx(builder: &mut ssl::SslContextBuilder) { + builder.options().insert(ssl::SslOptions::NO_TICKET); + builder.set_alpn_protos(b"\x02h2\x08http/1.1").unwrap(); + builder.set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x02h2\x08http/1.1", client).ok_or(ssl::AlpnError::NOACK) + }); + // builder.set_session_cache_mode( + // ssl::SslSessionCacheMode::SERVER | ssl::SslSessionCacheMode::NO_INTERNAL, + // ); + + // builder.set_new_session_callback(new_session_callback); + // unsafe { + // builder.set_get_session_callback(get_session_callback); + // } + // builder.set_remove_session_callback(remove_session_callback); } +// fn new_session_callback(_ssl_ref: &mut ssl::SslRef, sess: ssl::SslSession) { +// info!("NEW SESSION callback! id: {:?}", sess.id()); +// let mut w = match SESSION_CACHE.write() { +// Ok(w) => w, +// Err(e) => { +// error!("ssl session cache is poisoned! {}", e); +// e.into_inner() +// } +// }; + +// w.insert(sess.id().to_vec(), sess); +// } +// fn remove_session_callback(_ctx: &ssl::SslContextRef, sess: &ssl::SslSessionRef) { +// info!("REMOVE SESSION callback! id: {:?}", sess.id()); +// let mut w = match SESSION_CACHE.write() { +// Ok(w) => w, +// Err(e) => { +// error!("ssl session cache is poisoned! {}", e); +// e.into_inner() +// } +// }; +// w.remove(sess.id()); +// } +// fn get_session_callback(_ssl_ref: &mut ssl::SslRef, id: &[u8]) -> Option { +// info!("GET SESSION callback! id: {:?}", id); +// match SESSION_CACHE.read() { +// Err(e) => { +// error!("ssl session cache read error: {}", e); +// return None; +// } +// Ok(r) => return r.get(id).cloned(), +// } +// } + pub fn get_cached_ctx(servername: &str) -> Option { debug!("trying to get cached ssl context for: {}", servername); if let Ok(store) = CTX_STORE.read() { @@ -57,6 +148,7 @@ pub fn get_ctx(servername: &str) -> Result, String> { Err(e) => Err(format!("{}", e)), Ok(mut builder) => { debug!("building ssl ctx"); + setup_base_ctx(&mut builder); let mut added = 0; for c in res.iter() { if !c.is_empty() { @@ -113,7 +205,7 @@ pub fn get_ctx(servername: &str) -> Result, String> { if let Some(ref wc) = wildcard { return get_ctx(wc.as_str()); } else { - return Ok(None); + return Ok(Some(DEFAULT_CTX.clone())); } } let ctx = builder.build(); diff --git a/distributed-fly/src/conn.rs b/distributed-fly/src/conn.rs new file mode 100644 index 0000000..52b8b05 --- /dev/null +++ b/distributed-fly/src/conn.rs @@ -0,0 +1,67 @@ +use bytes::{Buf, BufMut}; +use futures::Poll; +use std::io::{self, Read, Write}; +use tokio::io::{AsyncRead, AsyncWrite}; + +use crate::proxy; + +pub enum Conn { + Tls(tokio_openssl::SslStream), + Tcp(proxy::ProxyTcpStream), +} + +impl Read for Conn { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match self { + Conn::Tcp(proxy_stream) => proxy_stream.read(buf), + Conn::Tls(ssl_stream) => ssl_stream.read(buf), + } + } +} + +impl Write for Conn { + fn write(&mut self, buf: &[u8]) -> io::Result { + match self { + Conn::Tcp(proxy_stream) => proxy_stream.write(buf), + Conn::Tls(ssl_stream) => ssl_stream.write(buf), + } + } + fn flush(&mut self) -> io::Result<()> { + match self { + Conn::Tcp(proxy_stream) => proxy_stream.flush(), + Conn::Tls(ssl_stream) => ssl_stream.flush(), + } + } +} + +impl AsyncRead for Conn { + unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { + match self { + Conn::Tcp(proxy_stream) => proxy_stream.prepare_uninitialized_buffer(buf), + Conn::Tls(ssl_stream) => ssl_stream.prepare_uninitialized_buffer(buf), + } + } + + fn read_buf(&mut self, buf: &mut B) -> Poll { + match self { + Conn::Tcp(proxy_stream) => proxy_stream.read_buf(buf), + Conn::Tls(ssl_stream) => ssl_stream.read_buf(buf), + } + } +} + +impl AsyncWrite for Conn { + fn shutdown(&mut self) -> Poll<(), io::Error> { + match self { + Conn::Tcp(proxy_stream) => proxy_stream.shutdown(), + Conn::Tls(ssl_stream) => ssl_stream.shutdown(), + } + } + + fn write_buf(&mut self, buf: &mut B) -> Poll { + match self { + Conn::Tcp(proxy_stream) => proxy_stream.write_buf(buf), + Conn::Tls(ssl_stream) => ssl_stream.write_buf(buf), + } + } +} diff --git a/distributed-fly/src/logging.rs b/distributed-fly/src/logging.rs new file mode 100644 index 0000000..00719f7 --- /dev/null +++ b/distributed-fly/src/logging.rs @@ -0,0 +1,128 @@ +use slog::{o, Drain, Level}; +use slog_json; + +use std::env; + +pub fn build_logger() -> slog::Logger { + build_logger_internal(std::io::stdout()) +} + +fn build_logger_internal(io: W) -> slog::Logger { + let runtime_drain = slog_json::Json::new(io).build().ignore_res(); + + let logger = match std::net::TcpStream::connect("localhost:9514") { + Ok(stream) => { + println!("connected to tcp"); + let app_drain = slog_json::Json::new(stream).build().ignore_res(); + fly::logging::build_routing_logger(runtime_drain, app_drain) + } + Err(e) => { + println!("did not connect to tcp {} ", e); + eprintln!( + "Error connecting to app log endpoint, falling back to stdout: {} ", + e + ); + fly::logging::build_logger(runtime_drain) + } + }; + + logger.new(o!( + "rt_version" => fly::BUILD_VERSION, + "message" => slog::PushFnValue(move |record : &slog::Record, ser| { + ser.emit(record.msg()) + }), + "level" => slog::FnValue(move |rinfo : &slog::Record| { + numeric_level(rinfo.level()) + }), + "timestamp" => slog::PushFnValue(move |_ : &slog::Record, ser| { + ser.emit(chrono::Utc::now().to_rfc3339()) + }), + "region" => env::var("REGION").unwrap_or_default(), + "host" => env::var("HOST").unwrap_or_default(), + )) +} + +fn numeric_level(level: Level) -> u8 { + match level { + Level::Critical => 2, + Level::Error => 3, + Level::Warning => 4, + Level::Info => 6, + Level::Debug => 7, + Level::Trace => 7, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use slog::slog_info; + use std::process::{Command, Stdio}; + use std::time; + use tempfile; + + #[test] + fn test_syslog_available() { + let tmpio = tempfile::NamedTempFile::new().unwrap(); + let nc = Command::new("nc") + .args(&["-l", "9514"]) + .stdout(Stdio::piped()) + .spawn() + .expect("failed to start netcat"); + + // give netcat a chance to start + std::thread::sleep(time::Duration::from_millis(100)); + + { + let _logger = build_logger_internal(tmpio.reopen().unwrap()); + + slog_info!(_logger, #"runtime", "runtime-message"); + slog_info!(_logger, #"app", "app-message"); + } + + let output = nc.wait_with_output().unwrap(); + let tcp_output = String::from_utf8_lossy(&output.stdout); + let stdio_output = std::fs::read_to_string(tmpio.path()).unwrap(); + + assert!( + tcp_output.contains("app-message"), + "app log was not written to app drain!" + ); + assert!( + !tcp_output.contains("runtime-message"), + "runtime message was written to app drain!" + ); + + assert!( + !stdio_output.contains("app-message"), + "app log was written to stdout!" + ); + assert!( + stdio_output.contains("runtime-message"), + "runtime message was not written to stdout!" + ); + } + + #[test] + fn test_syslog_not_available() { + let tmpio = tempfile::NamedTempFile::new().unwrap(); + + { + let _logger = build_logger_internal(tmpio.reopen().unwrap()); + + slog_info!(_logger, #"runtime", "runtime-message"); + slog_info!(_logger, #"app", "app-message"); + } + + let stdio_output = std::fs::read_to_string(tmpio.path()).unwrap(); + + assert!( + stdio_output.contains("app-message"), + "app log was not written to stdout!" + ); + assert!( + stdio_output.contains("runtime-message"), + "runtime message was not written to stdout!" + ); + } +} diff --git a/distributed-fly/src/main.rs b/distributed-fly/src/main.rs index b754582..4e52944 100644 --- a/distributed-fly/src/main.rs +++ b/distributed-fly/src/main.rs @@ -1,8 +1,10 @@ +use std::alloc::System; + +#[global_allocator] +static A: System = System; + #[macro_use] extern crate serde_derive; -extern crate rmp_serde as rmps; - -extern crate serde; #[macro_use] extern crate lazy_static; @@ -12,13 +14,9 @@ extern crate log; #[macro_use] extern crate futures; - -// use fly::dns_server::DnsServer; - use std::time::Duration; use tokio::timer::Interval; -extern crate hyper; use futures::{future, Future, Stream}; use hyper::service::{make_service_fn, service_fn}; @@ -26,10 +24,6 @@ use hyper::Server; use tokio::net::{TcpListener, TcpStream}; -use env_logger::Env; - -// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - mod release; mod settings; @@ -49,19 +43,35 @@ use tokio_openssl::SslAcceptorExt; extern crate prometheus; mod cert; +mod conn; +mod libs; +mod logging; mod metrics; mod proxy; -mod libs; +use crate::conn::*; use crate::metrics::*; use fly::metrics::*; use r2d2_redis::RedisConnectionManager; +use slog_scope; + +use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT}; +pub static INTERRUPTING: AtomicBool = ATOMIC_BOOL_INIT; +pub fn is_interrupting() -> bool { + return INTERRUPTING.load(Ordering::SeqCst); +} +fn interrupt() { + INTERRUPTING.store(true, Ordering::SeqCst); +} + +static mut SELECTOR: Option = None; lazy_static! { - static ref SELECTOR: DistributedRuntimeSelector = DistributedRuntimeSelector::new(); pub static ref AWS_CREDENTIALS: AwsCredentials = EnvironmentProvider::default().credentials().wait().unwrap(); pub static ref REDIS_POOL: r2d2::Pool = r2d2::Pool::builder() + .max_size(100) + .min_idle(Some(0)) .build( RedisConnectionManager::new(GLOBAL_SETTINGS.read().unwrap().redis_url.as_str()) .unwrap() @@ -70,12 +80,17 @@ lazy_static! { } fn main() { - let env = Env::default().filter_or("LOG_LEVEL", "info"); - env_logger::init_from_env(env); + let logger = crate::logging::build_logger(); + let _log_guard = slog_scope::set_global_logger(logger); + slog_stdlog::init().unwrap(); let _guard = { if let Some(ref sentry_dsn) = GLOBAL_SETTINGS.read().unwrap().sentry_dsn { - Some(sentry::init(sentry_dsn.as_str())) + let mut opts = sentry::ClientOptions::from(sentry_dsn.as_str()); + opts.release = Some(fly::BUILD_VERSION.into()); + let c = sentry::init(opts); + sentry::integrations::panic::register_panic_handler(); + Some(c) } else { None } @@ -105,9 +120,6 @@ fn main() { .parse() .unwrap(); - let http_listener = TcpListener::bind(&addr).unwrap(); - let tls_listener = TcpListener::bind(&tls_addr).unwrap(); - let mut tls_builder = openssl::ssl::SslAcceptor::mozilla_intermediate(openssl::ssl::SslMethod::tls()).unwrap(); @@ -169,42 +181,38 @@ fn main() { ) .unwrap(); - tls_builder.set_session_cache_mode(openssl::ssl::SslSessionCacheMode::BOTH); + tls_builder.set_session_cache_mode(openssl::ssl::SslSessionCacheMode::SERVER); let tls_acceptor = tls_builder.build(); + let tls_listener = TcpListener::bind(&tls_addr).unwrap(); + let tls_stream = tls_listener .incoming() - .and_then(|stream| proxy::ProxyTcpStream::peek(stream)) - .map_err(|e| error!("error in incoming tls conn: {}", e)) - .for_each(move |stream| { - let remote_addr = stream.peer_addr().unwrap(); + .and_then(|stream| proxy::ProxyTcpStream::from_tcp_stream(stream, true)) + .and_then(move |pstream| { let timer = TLS_HANDSHAKE_TIME_HISTOGRAM.start_timer(); - tokio::spawn( - tls_acceptor - .accept_async(stream) - .map_err(|e| error!("error handshake conn: {}", e)) - .and_then(move |stream| { - timer.observe_duration(); - let h = hyper::server::conn::Http::new(); - h.serve_connection( - stream, - service_fn(move |req| serve_http(true, req, &*SELECTOR, remote_addr)), - ) - .map_err(|e| error!("error serving conn: {}", e)) - }), - ); - Ok(()) - }); + tls_acceptor.accept_async(pstream).then(|r| { + timer.observe_duration(); + match r { + Ok(stream) => Ok(Some(Conn::Tls(stream))), + Err(e) => { + error!("error accepting TLS connection: {}", e); + Ok(None) + } + } + }) + }) + .filter_map(|ssl_stream| ssl_stream); - let make_svc = make_service_fn(|conn: &proxy::ProxyTcpStream| { - let remote_addr = conn.peer_addr().unwrap_or("0.0.0.0:0".parse().unwrap()); - service_fn(move |req| serve_http(false, req, &*SELECTOR, remote_addr)) - }); + let tcp_listener = TcpListener::bind(&addr).unwrap(); - let http_stream = http_listener + let tcp_stream = tcp_listener .incoming() - .and_then(|stream| proxy::ProxyTcpStream::peek(stream)); + .and_then(|stream| proxy::ProxyTcpStream::from_tcp_stream(stream, false)) + .map(|pstream| Conn::Tcp(pstream)); + + let all_stream = tcp_stream.select(tls_stream); let prom_listener: Option = { let s = GLOBAL_SETTINGS.read().unwrap(); @@ -221,17 +229,47 @@ fn main() { } }; - tokio::run(future::lazy(move || { - tokio::spawn(runtime_monitoring()); + let (sigfut, sigrx) = fly::utils::signal_monitor(); + let (srv_shutdown_tx, srv_shutdown_rx) = futures::sync::oneshot::channel(); + let (prom_shutdown_tx, prom_shutdown_rx) = futures::sync::oneshot::channel(); + let http_server = Server::builder(all_stream) + .serve(make_service_fn(|conn: &Conn| { + let (remote_addr, tls) = match conn { + Conn::Tcp(c) => (c.peer_addr(), false), + Conn::Tls(c) => (c.get_ref().get_ref().peer_addr(), true), + }; + let remote_addr = remote_addr + .unwrap_or_else(|_| "0.0.0.0:0".parse().unwrap()); + service_fn(move |req| { + serve_http(tls, req, unsafe { SELECTOR.as_ref().unwrap() }, remote_addr) + }) + })) + .with_graceful_shutdown(srv_shutdown_rx) + .map_err(|e| { + error!("server error: {}", e); + }) + .and_then(move |_| { + info!("http server closed."); + unsafe { SELECTOR = None }; // Drops the selector + Ok(()) + }); + + tokio::run(future::lazy(move || { + unsafe { SELECTOR = Some(DistributedRuntimeSelector::new()) }; tokio::spawn( - Server::builder(http_stream) - .serve(make_svc) - .map_err(|e| error!("error in http server: {}", e)), + sigrx + .map_err(|e| error!("error receiving signal: {}", e)) + .and_then(move |_| { + interrupt(); + srv_shutdown_tx.send(()).ok(); + prom_shutdown_tx.send(()).ok(); + Ok(()) + }), ); + tokio::spawn(runtime_monitoring()); + tokio::spawn(http_server); info!("HTTP listening on {}", addr); - - tokio::spawn(tls_stream); info!("HTTPS listening on {}", tls_addr); if let Some(prom_ln) = prom_listener { @@ -241,16 +279,16 @@ fn main() { .serve(make_service_fn(|_conn: &TcpStream| { service_fn(move |req| fly::metrics::serve_metrics_http(req)) })) + .with_graceful_shutdown(prom_shutdown_rx) .map_err(|e| error!("error in http prom server: {}", e)), ); info!("Prometheus listening on {}", addr); } - Ok(()) + sigfut })); } -use std::sync::atomic::Ordering; use std::time; static MAX_RUNTIME_IDLE_SECONDS: usize = 5 * 60; @@ -258,8 +296,9 @@ static MAX_RUNTIME_IDLE_SECONDS: usize = 5 * 60; fn runtime_monitoring() -> impl Future + Send + 'static { Interval::new_interval(Duration::from_secs(15)) .map_err(|e| error!("timer error: {}", e)) + .take_while(|_| Ok(unsafe { SELECTOR.is_some() })) .for_each(|_| { - match SELECTOR.runtimes.read() { + match unsafe { SELECTOR.as_ref().unwrap() }.runtimes.read() { Err(e) => error!("error getting read lock on runtime selector: {}", e), Ok(guard) => { guard.iter().for_each(|(k, rt)| { @@ -294,17 +333,24 @@ fn runtime_monitoring() -> impl Future + Send + 'static { { let key = k.clone(); tokio::spawn(future::lazy(move || { - match SELECTOR.runtimes.write() { - Err(e) => error!( - "error getting write lock on runtime selector: {}", - e - ), - Ok(mut guard) => match guard.remove(&key) { - None => {} - Some(mut rt) => { - rt.dispose(); - } - }, + let mut w = match unsafe { SELECTOR.as_ref().unwrap() } + .runtimes + .write() + { + Ok(w) => w, + Err(poisoned) => { + error!( + "error getting write lock on runtime selector: {}", + poisoned + ); + poisoned.into_inner() + } + }; + match w.remove(&key) { + None => {} + Some(mut rt) => { + rt.dispose(); + } }; Ok(()) })); diff --git a/distributed-fly/src/proxy.rs b/distributed-fly/src/proxy.rs index b56ddb5..500aefe 100644 --- a/distributed-fly/src/proxy.rs +++ b/distributed-fly/src/proxy.rs @@ -6,22 +6,30 @@ use tokio::io::{AsyncRead, AsyncWrite}; use tokio::net::TcpStream; use std::io::BufRead; +use std::time::Duration; #[derive(Debug)] pub struct ProxyTcpStream { + pub tls: bool, stream: TcpStream, remote_addr: SocketAddr, } impl ProxyTcpStream { - pub fn peek(stream: TcpStream) -> impl Future { + pub fn from_tcp_stream( + stream: TcpStream, + tls: bool, + ) -> impl Future { let mut bytes = [0; 107]; + stream.set_nodelay(true).ok(); + stream.set_keepalive(Some(Duration::from_secs(10))).ok(); let mut stream = Some(stream); future::poll_fn(move || { let _n = try_ready!(stream.as_mut().unwrap().poll_peek(&mut bytes)); // TODO: check bytes[..n] for PROXY line let mut stream = stream.take().unwrap(); - let mut remote_addr: SocketAddr = stream.peer_addr().unwrap(); + let mut remote_addr: SocketAddr = + stream.peer_addr().unwrap_or("0.0.0.0:0".parse().unwrap()); let mut s = String::new(); match bytes.as_ref().read_line(&mut s) { Ok(ln) => { @@ -30,15 +38,16 @@ impl ProxyTcpStream { let mut v = vec![0; ln]; stream.read_exact(&mut v).unwrap(); let mut split = s.split(" ").skip(2); - let ip = split.next().unwrap(); - let port = split.skip(1).next().unwrap(); + let ip = split.next().unwrap_or("0.0.0.0"); + let port = split.skip(1).next().unwrap_or("0"); remote_addr = format!("{}:{}", ip, port).parse().unwrap(); debug!("using proxy proto, remote addr: {}", remote_addr); } } - Err(e) => error!("error reading PROXY line: {}", e), + Err(e) => debug!("error reading PROXY protocol line: {}", e), }; Ok(Async::Ready(ProxyTcpStream { + tls, stream, remote_addr, })) diff --git a/distributed-fly/src/release.rs b/distributed-fly/src/release.rs index 4913b79..87d4301 100644 --- a/distributed-fly/src/release.rs +++ b/distributed-fly/src/release.rs @@ -1,22 +1,16 @@ use std::collections::HashMap; use std::sync::RwLock; -use crate::rmps::Deserializer; -use r2d2; +use rmp_serde::Deserializer; use serde::Deserialize; -use self::redis::Commands; -use r2d2_redis::redis; +use crate::is_interrupting; +use r2d2_redis::redis::{self, Commands}; -extern crate serde_json; - -extern crate rmpv; -use self::rmpv::Value; +use rmpv::Value; use crate::kms::decrypt; -extern crate base64; - use crate::settings::GLOBAL_SETTINGS; use super::REDIS_POOL; @@ -75,10 +69,15 @@ impl Release { } match get_by_app_key(&*conn, app_key.as_str())? { Some(rel) => { - RELEASES_BY_APP - .write() - .unwrap() - .insert(app_key, rel.clone()); + let mut w = match RELEASES_BY_APP.write() { + Ok(w) => w, + Err(e) => { + error!("poisoned RELEASES_BY_APP lock! {}", e); + e.into_inner() + } + }; + + w.insert(app_key, rel.clone()); Ok(Some(rel)) } None => Ok(None), @@ -220,118 +219,163 @@ fn find_cached_release(host: &str) -> Option { use std::time; +fn sleep_a_bit() { + thread::sleep(time::Duration::from_secs(5)); // probably want to do backoff later +} + pub fn start_new_release_check() { thread::Builder::new() .name("redis-release-pubsub".to_string()) .spawn(|| { - let redis_url = { GLOBAL_SETTINGS.read().unwrap().redis_url.clone() }; - let client = redis::Client::open(redis_url.as_str()).unwrap(); - let mut con = client.get_connection().unwrap(); - let mut pubsub = con.as_pubsub(); - pubsub.subscribe("__keyspace@0__:notifications").unwrap(); - info!("subscribed to keyspace notifications"); - let mut last_updated_at = time::SystemTime::now() .duration_since(time::UNIX_EPOCH) .unwrap() .as_secs(); + while !is_interrupting() { + let redis_url = { GLOBAL_SETTINGS.read().unwrap().redis_url.clone() }; + let client = match redis::Client::open(redis_url.as_str()) { + Ok(c) => c, + Err(e) => { + error!("unable to connect to redis for release checking: {}", e); + sleep_a_bit(); + continue; + } + }; + let mut con = match client.get_connection() { + Ok(c) => c, + Err(e) => { + error!( + "unable to get the redis connection for release checking: {}", + e + ); + sleep_a_bit(); + continue; + } + }; + let mut pubsub = con.as_pubsub(); + match pubsub.subscribe("__keyspace@0__:notifications") { + Ok(_) => {} + Err(e) => { + error!("unable to subscribe to redis keyspace notifications: {}", e); + sleep_a_bit(); + continue; + } + }; + info!("subscribed to keyspace notifications"); - loop { - let msg = pubsub.get_message().unwrap(); - let payload: String = msg.get_payload().unwrap(); - info!("channel '{}': {}", msg.get_channel_name(), payload,); - let now = time::SystemTime::now() - .duration_since(time::UNIX_EPOCH) - .unwrap() - .as_secs(); - match REDIS_POOL.get() { - Err(e) => error!("could not acquire redis conn: {}", e), - Ok(conn) => match redis::cmd("ZRANGEBYSCORE") - .arg("notifications") - .arg(last_updated_at) - .arg(now) - .query::>(&*conn) - { - Err(e) => error!("error getting notifications range: {}", e), - Ok(notifications) => { - for n in notifications.iter() { - match serde_json::from_str::(n.as_str()) { - Err(e) => error!("could not parse notification: {}", e), - Ok(notif) => { - use self::NotificationAction::*; - if notif.key.starts_with("app:") { - match notif.action { - Delete => match RELEASES_BY_APP.write() { - Ok(mut guard) => { - guard.remove(notif.key.as_str()); - } - Err(e) => error!("error getting RELEASES_BY_APP write lock: {}", e), - }, - Update => match get_by_app_key(&*conn, notif.key.as_str()) { - Ok(maybe_rel) => match maybe_rel { - Some(rel) => match RELEASES_BY_APP.write() { - Ok(mut guard) => { - guard.insert(notif.key.clone(), rel); - } - Err(e) => error!("error getting RELEASES_BY_APP write lock: {}", e), - }, - None => {} + while !is_interrupting() { + let msg = match pubsub.get_message() { + Ok(m) => m, + Err(e) => { + error!("error getting message from pubsub: {}", e); + sleep_a_bit(); + continue; + } + }; + let payload: String = match msg.get_payload() { + Ok(p) => p, + Err(e) => { + error!("error getting payload from pubsub message: {}", e); + sleep_a_bit(); + continue; + } + }; + info!("channel '{}': {}", msg.get_channel_name(), payload); + let now = time::SystemTime::now() + .duration_since(time::UNIX_EPOCH) + .unwrap() + .as_secs(); + match REDIS_POOL.get() { + Err(e) => error!("could not acquire redis conn: {}", e), + Ok(conn) => match redis::cmd("ZRANGEBYSCORE") + .arg("notifications") + .arg(last_updated_at) + .arg(now) + .query::>(&*conn) + { + Err(e) => error!("error getting notifications range: {}", e), + Ok(notifications) => { + for n in notifications.iter() { + match serde_json::from_str::(n.as_str()) { + Err(e) => error!("could not parse notification: {}", e), + Ok(notif) => { + use self::NotificationAction::*; + if notif.key.starts_with("app:") { + match notif.action { + Delete => match RELEASES_BY_APP.write() { + Ok(mut guard) => { + guard.remove(notif.key.as_str()); + } + Err(e) => error!("error getting RELEASES_BY_APP write lock: {}", e), }, - Err(e) => error!("error getting app by key: {}", e), - }, - } - } else if notif.key.starts_with("app_hosts") { - use self::serde_json::Value; - match notif.context { - Value::Array(arr) => { - let hostnames: Vec = arr - .iter() - .map(|v| match v { - Value::String(h) => h.clone(), - _ => unimplemented!(), - }) - .collect(); - match notif.action { - Delete => match APP_BY_HOSTNAME.write() { - Ok(mut guard) => { - for h in hostnames.iter() { - guard.remove(h); + Update => match get_by_app_key(&*conn, notif.key.as_str()) { + Ok(maybe_rel) => match maybe_rel { + Some(rel) => match RELEASES_BY_APP.write() { + Ok(mut guard) => { + guard.insert(notif.key.clone(), rel); } - } - Err(e) => error!("error acquiring APP_BY_HOSTNAME write lock: {}", e), + Err(e) => error!("error getting RELEASES_BY_APP write lock: {}", e), + }, + None => {} }, - Update => { - for h in hostnames.iter() { - match redis::cmd("HGET") - .arg("app_hosts") - .arg(h) - .query::>(&*conn) - { - Ok(Some(app_key)) => match APP_BY_HOSTNAME.write() { - Ok(mut guard) => { - guard.insert(h.clone(), app_key); - } - Err(e) => { - error!("error acquiring APP_BY_HOSTNAME write lock: {}", e) - } - }, - Ok(None) => debug!("no app host found for {}", h), - Err(e) => error!("could not get app_hosts for {}: {}", h, e), + Err(e) => error!("error getting app by key: {}", e), + }, + } + } else if notif.key.starts_with("app_hosts") { + use serde_json::Value; + match notif.context { + Value::Array(arr) => { + let hostnames: Vec = arr + .iter() + .map(|v| match v { + Value::String(h) => h.clone(), + _ => unimplemented!(), + }) + .collect(); + match notif.action { + Delete => match APP_BY_HOSTNAME.write() { + Ok(mut guard) => { + for h in hostnames.iter() { + guard.remove(h); + } + } + Err(e) => { + error!("error acquiring APP_BY_HOSTNAME write lock: {}", e) + } + }, + Update => { + for h in hostnames.iter() { + match redis::cmd("HGET") + .arg("app_hosts") + .arg(h) + .query::>(&*conn) + { + Ok(Some(app_key)) => match APP_BY_HOSTNAME.write() { + Ok(mut guard) => { + guard.insert(h.clone(), app_key); + } + Err(e) => { + error!("error acquiring APP_BY_HOSTNAME write lock: {}", e) + } + }, + Ok(None) => debug!("no app host found for {}", h), + Err(e) => error!("could not get app_hosts for {}: {}", h, e), + } } } } } + _ => unimplemented!(), } - _ => unimplemented!(), } } } } + last_updated_at = now; } - last_updated_at = now; - } - }, - }; + }, + }; + } } }) .unwrap(); diff --git a/distributed-fly/src/runtime_selector.rs b/distributed-fly/src/runtime_selector.rs index 40a73d3..53b0940 100644 --- a/distributed-fly/src/runtime_selector.rs +++ b/distributed-fly/src/runtime_selector.rs @@ -1,6 +1,9 @@ use futures::Future; -use fly::{runtime::Runtime, RuntimeSelector, SelectorError}; +use fly::{ + runtime::{Runtime, RuntimeConfig}, + RuntimeSelector, SelectorError, +}; use std::collections::HashMap; use std::sync::RwLock; @@ -10,17 +13,32 @@ use crate::release::Release; use crate::settings::GLOBAL_SETTINGS; pub struct DistributedRuntimeSelector { - pub runtimes: RwLock>>, + uuid_to_runtime: RwLock>>, + hostname_to_runtime: RwLock>>, } impl DistributedRuntimeSelector { pub fn new() -> Self { DistributedRuntimeSelector { - runtimes: RwLock::new(HashMap::new()), + uuid_to_runtime: RwLock::new(HashMap::new()), + hostname_to_runtime: RwLock::new(HashMap::new()), } } } +impl Drop for DistributedRuntimeSelector { + fn drop(&mut self) { + let mut writer = match self.runtimes.write() { + Ok(w) => w, + Err(poisoned) => poisoned.into_inner(), + }; + writer.iter_mut().for_each(|(k, rt)| { + debug!("Disposing of runtime: {}", k); + rt.dispose(); + }); + } +} + impl RuntimeSelector for DistributedRuntimeSelector { fn get_by_hostname(&self, hostname: &str) -> Result, SelectorError> { let rel = match Release::get(hostname) { @@ -35,108 +53,128 @@ impl RuntimeSelector for DistributedRuntimeSelector { let runtimes = &self.runtimes; - { - if !runtimes.read().unwrap().contains_key(&key) { - let mut writer = runtimes.write().unwrap(); - let settings = { - use fly::settings::*; - let global_settings = &*GLOBAL_SETTINGS.read().unwrap(); - Settings { - data_store: Some(DataStore::Postgres(PostgresStoreConfig { - url: global_settings.cockroach_host.clone(), - database: Some(format!("objectstore_{}", rel.app_id)), - tls_ca_crt: if let Some(ref certs_path) = - global_settings.cockroach_certs_path - { - Some(format!("{}/ca.crt", certs_path)) - } else { - None - }, - tls_client_crt: if let Some(ref certs_path) = - global_settings.cockroach_certs_path - { - Some(format!("{}/client.root.crt", certs_path)) - } else { - None - }, - tls_client_key: if let Some(ref certs_path) = - global_settings.cockroach_certs_path - { - Some(format!("{}/client.root.key", certs_path)) - } else { - None - }, - })), // TODO: use postgres store - cache_store: Some(CacheStore::Redis(RedisStoreConfig { - url: global_settings.redis_cache_url.clone(), - namespace: Some(rel.app_id.to_string()), - })), // TODO: use redis store - cache_store_notifier: match global_settings.redis_cache_notifier_url { - Some(ref url) => { - Some(CacheStoreNotifier::Redis(RedisCacheNotifierConfig { - reader_url: url.clone(), - writer_url: global_settings - .redis_cache_notifier_writer_url - .as_ref() - .unwrap_or(url) - .clone(), - })) - } - None => None, + let exists = { + match runtimes.read() { + Ok(guard) => guard.contains_key(&key), + Err(e) => return Err(SelectorError::Failure(format!("{}", e))), + } + }; + + if !exists { + let mut writer = match runtimes.write() { + Ok(w) => w, + Err(poisoned) => { + error!("runtimes writer is poisoned! {}", poisoned); + poisoned.into_inner() // recover... + } + }; + let settings = { + use fly::settings::*; + let global_settings = &*GLOBAL_SETTINGS.read().unwrap(); + Settings { + data_store: Some(DataStore::Postgres(PostgresStoreConfig { + url: global_settings.cockroach_host.clone(), + database: Some(format!("objectstore_{}", rel.app_id)), + tls_ca_crt: if let Some(ref certs_path) = + global_settings.cockroach_certs_path + { + Some(format!("{}/ca.crt", certs_path)) + } else { + None }, - fs_store: Some(FsStore::Redis(RedisStoreConfig { - namespace: Some(format!("app:{}:release:latest:file:", rel.app_id)), - url: global_settings.redis_url.clone(), - })), - acme_store: Some(AcmeStoreConfig::Redis(RedisStoreConfig { - url: global_settings.redis_url.clone(), - namespace: None, - })), - } - }; - let mut rt = Runtime::new( - Some(rel.app_id.to_string()), - Some(rel.version.to_string()), - &settings, - ); - let merged_conf = rel.clone().parsed_config().unwrap(); - rt.eval( - "", - &format!("window.fly.app = {{ config: {} }};", merged_conf), - ); - - // load external libraries if requested - if let Some(libs) = rel.libs { - match fetch_libs(&libs[..]) { - Ok(lib_sources) => { - for (key, source) in lib_sources.iter() { - if let Some(source) = source { - rt.eval(&format!("", key), source); - } else { - warn!("app {} requested missing lib: {}", &rel.app_id, &key); - } - } + tls_client_crt: if let Some(ref certs_path) = + global_settings.cockroach_certs_path + { + Some(format!("{}/client.root.crt", certs_path)) + } else { + None + }, + tls_client_key: if let Some(ref certs_path) = + global_settings.cockroach_certs_path + { + Some(format!("{}/client.root.key", certs_path)) + } else { + None + }, + })), // TODO: use postgres store + cache_store: Some(CacheStore::Redis(RedisStoreConfig { + url: global_settings.redis_cache_url.clone(), + namespace: Some(rel.app_id.to_string()), + })), // TODO: use redis store + cache_store_notifier: match global_settings.redis_cache_notifier_url { + Some(ref url) => { + Some(CacheStoreNotifier::Redis(RedisCacheNotifierConfig { + reader_url: url.clone(), + writer_url: global_settings + .redis_cache_notifier_writer_url + .as_ref() + .unwrap_or(url) + .clone(), + })) } - Err(e) => warn!("error loading libs for app {}: {}", &rel.app, e), - } + None => None, + }, + fs_store: Some(FsStore::Redis(RedisStoreConfig { + namespace: Some(format!("app:{}:release:latest:file:", rel.app_id)), + url: global_settings.redis_url.clone(), + })), + acme_store: Some(AcmeStoreConfig::Redis(RedisStoreConfig { + url: global_settings.redis_url.clone(), + namespace: None, + })), } + }; - rt.eval("app.js", &rel.source); - let app = rel.app; - let app_id = rel.app_id; - let version = rel.version; + let mut rt = Runtime::new(RuntimeConfig { + name: Some(rel.app_id.to_string()), + version: Some(rel.version.to_string()), + settings: &settings, + module_resolvers: Some(vec![]), + app_logger: &slog_scope::logger(), + msg_handler: None, + permissions: None, + dev_tools: false, + }); + let merged_conf = rel.clone().parsed_config().unwrap(); + rt.eval( + "", + &format!( + "window.fly.app = {{ config: {}, version: {} }};", + merged_conf, rel.version + ), + ); - // TODO: ughh, refactor! - // let _key2 = key.clone(); - tokio::spawn(rt.run().then(move |res: Result<(), _>| { - if let Err(_) = res { - error!("app: {} ({}) v{} ended abruptly", app, app_id, version); + // load external libraries if requested + if let Some(libs) = rel.libs { + match fetch_libs(&libs[..]) { + Ok(lib_sources) => { + for (key, source) in lib_sources.iter() { + if let Some(source) = source { + rt.eval(&format!("", key), source); + } else { + warn!("app {} requested missing lib: {}", &rel.app_id, &key); + } + } } - // runtimes.write().unwrap().remove(&key2); - Ok(()) - })); - writer.insert(key.clone(), rt); + Err(e) => warn!("error loading libs for app {}: {}", &rel.app, e), + } } + + rt.eval("app.js", &rel.source); + let app = rel.app; + let app_id = rel.app_id; + let version = rel.version; + + // TODO: ughh, refactor! + // let _key2 = key.clone(); + tokio::spawn(rt.run().then(move |res: Result<(), _>| { + if let Err(_) = res { + error!("app: {} ({}) v{} ended abruptly", app, app_id, version); + } + // runtimes.write().unwrap().remove(&key2); + Ok(()) + })); + writer.insert(key.clone(), rt); } let runtimes = runtimes.read().unwrap(); // TODO: no unwrap diff --git a/hello-world.js b/hello-world.js index 7ee8887..8646236 100644 --- a/hello-world.js +++ b/hello-world.js @@ -1,3 +1,7 @@ +// Requires the secrets module loader, not enabled everywhere yet. +// import someSecret from "secrets:///secretObject/subSecret"; +// console.log(someSecret); + console.log("hello world") const helloWorldStr = "Hello World"; const helloWorld = new TextEncoder().encode(helloWorldStr); @@ -17,14 +21,19 @@ addEventListener("fetch", function (event) { else if (url.pathname == "/kitchensink") { const coll = fly.data.collection("testing") - coll.put("id", { foo: "bar" }).then(b => { + coll.put("id", { foo: "bar", counter: 10 }).then(b => { console.log("put returned:", b); coll.get("id").then(d => { console.log("get returned:", d) - coll.del("id").then(b => { - console.log("del returned:", b) + coll.increment("id", "counter", 3).then(b => { coll.get("id").then(d => { - console.log("get returned:", d); + console.log("get after incr returned:", d) + coll.del("id").then(b => { + console.log("del returned:", b) + coll.get("id").then(d => { + console.log("get returned:", d); + }).catch(console.log) + }).catch(console.log) }).catch(console.log) }).catch(console.log) }).catch(console.log) @@ -59,7 +68,7 @@ addEventListener("fetch", function (event) { else if (url.pathname == "/image") { event.respondWith(fetch(url.searchParams.get("url")).then(res => { let img = new fly.Image(res.body); - img.webp({ lossless: false, quality: 75 }); + img.resize({ width: 512, height: 512 }).webp({ lossless: false, quality: 75 }); return img.transform().then(stream => { console.log("image accepted!"); return new Response(stream, { @@ -115,4 +124,8 @@ addEventListener("resolv", event => { } ], { authoritative: true }) }) -}) \ No newline at end of file +}) + +setTimeout(async () => { + console.log(await serviceRequest("test", { data: "test" })); +}, 5000); \ No newline at end of file diff --git a/libfly/binding.cc b/libfly/binding.cc index 9bf0c97..587d322 100644 --- a/libfly/binding.cc +++ b/libfly/binding.cc @@ -64,6 +64,10 @@ static inline v8::Local v8_str(const char *s) v8::NewStringType::kNormal) .ToLocalChecked(); } +static inline v8::Local v8_str_from_fly_simple_buf(v8::Isolate *iso, fly_simple_buf buf) +{ + return v8::String::NewFromUtf8(iso, buf.ptr, v8::NewStringType::kNormal, buf.len).ToLocalChecked(); +} // Extracts a C string from a v8::V8 Utf8Value. // const char *ToCString(const v8::String::Utf8Value &value) @@ -78,6 +82,11 @@ char *str_to_char(const v8::String::Utf8Value &src) js_runtime *FromIsolate(v8::Isolate *isolate) { + if (!isolate) + { + printf("isolate has been disposed\n"); + return nullptr; + } return static_cast(isolate->GetData(0)); } @@ -86,6 +95,11 @@ void HandleExceptionStr(v8::Local context, std::string *exception_str) { auto *isolate = context->GetIsolate(); + if (!isolate) + { + printf("isolate has been disposed\n"); + return; + } js_runtime *rt = FromIsolate(isolate); v8::HandleScope handle_scope(isolate); @@ -177,6 +191,11 @@ void HandleException(v8::Local context, void GetNextStreamId(const v8::FunctionCallbackInfo &args) { v8::Isolate *isolate = args.GetIsolate(); + if (!isolate) + { + printf("isolate has been disposed\n"); + return; + } args.GetReturnValue().Set(v8::Number::New(isolate, c_get_next_stream_id())); } @@ -184,6 +203,11 @@ void Print(const v8::FunctionCallbackInfo &args) { // TODO: assert arguments (level:Number, msg:String) v8::Isolate *isolate = args.GetIsolate(); + if (!isolate) + { + printf("isolate has been disposed\n"); + return; + } js_runtime *rt = static_cast(isolate->GetData(0)); auto lvl = v8::Int32::Cast(*args[0])->Value(); @@ -239,11 +263,33 @@ static fly_buf GetContents(const js_runtime *rt, return buf; } +static fly_buf GetArrayBufferContents(const js_runtime *rt, + v8::Local ab) +{ + auto contents = ab->GetContents(); + + auto length = ab->ByteLength(); + + fly_buf buf; + buf.alloc_ptr = reinterpret_cast(contents.Data()); + buf.alloc_len = contents.ByteLength(); + buf.data_ptr = buf.alloc_ptr; + buf.data_len = length; + + return buf; +} + bool ExecuteV8StringSource(v8::Local context, const char *filename, const char *code) { auto *isolate = context->GetIsolate(); + if (!isolate) + { + printf("isolate has been disposed\n"); + return false; + } + v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); @@ -276,10 +322,119 @@ bool ExecuteV8StringSource(v8::Local context, return true; } +v8::MaybeLocal ModuleImportCallback( + v8::Local context, + v8::Local specifier, + v8::Local referrer) +{ + auto *isolate = context->GetIsolate(); + + js_runtime *rt = static_cast(isolate->GetData(0)); + + v8::String::Utf8Value specifier_utf_val(isolate, specifier); + + js_compiled_module module_data = rt->resolve_cb(rt, *specifier_utf_val, referrer->GetIdentityHash()); + + v8::Persistent *module_persistent = static_cast *>(module_data.ptr); + + v8::Local module_local = module_persistent->Get(isolate); + + return module_local; +} + +bool ExecuteV8Module(v8::Local context, js_compiled_module module_data) +{ + auto *isolate = context->GetIsolate(); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + + v8::Context::Scope context_scope(context); + + v8::TryCatch try_catch(isolate); + + v8::Persistent *module_persistent = static_cast *>(module_data.ptr); + + v8::Local module_local = module_persistent->Get(isolate); + + auto module_instantiated = module_local->InstantiateModule(context, &ModuleImportCallback); + + if (module_instantiated.FromMaybe(false)) + { + // DCHECK(try_catch.HasCaught()); + HandleException(context, try_catch.Exception()); + return false; + } + + auto result = module_local->Evaluate(context); + + if (result.IsEmpty()) + { + // DCHECK(try_catch.HasCaught()); + HandleException(context, try_catch.Exception()); + return false; + } + + return true; +} + +js_compile_module_result CompileV8Module(v8::Local context, js_module_data module_data) +{ + auto *isolate = context->GetIsolate(); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + + v8::Context::Scope context_scope(context); + + v8::TryCatch try_catch(isolate); + + v8::ScriptOrigin origin(v8_str(isolate, module_data.origin_url), + Integer::New(isolate, 0), // line offset + Integer::New(isolate, 0), // column offset + False(isolate), // is cross origin + Local(), // script id + Local(), // source map URL + False(isolate), // is opaque + v8::Boolean::New(isolate, module_data.is_wasm), // is WASM + True(isolate)); // is ES6 module + + v8::ScriptCompiler::Source module_source(v8_str_from_fly_simple_buf(isolate, module_data.source_code), origin); + + auto module = v8::ScriptCompiler::CompileModule(isolate, &module_source); + + if (module.IsEmpty()) + { + // DCHECK(try_catch.HasCaught()); + HandleException(context, try_catch.Exception()); + return js_compile_module_result{ + NULL, + false, + }; + } + + auto module_local = module.ToLocalChecked(); + + v8::Persistent module_persistent(isolate, module_local); + + auto compiled_module = js_compiled_module { + module_local->GetIdentityHash(), + module_data, + &module_persistent, + }; + + return js_compile_module_result{ + &compiled_module, + true, + }; +} + // Sets the recv callback. -void Recv(const v8::FunctionCallbackInfo &args) +void Recv(const v8::FunctionCallbackInfo &args) { v8::Isolate *isolate = args.GetIsolate(); + if (!isolate) + { + return; + } js_runtime *rt = reinterpret_cast(isolate->GetData(0)); // DCHECK_EQ(d->isolate, isolate); @@ -301,6 +456,10 @@ void Recv(const v8::FunctionCallbackInfo &args) void Send(const v8::FunctionCallbackInfo &args) { v8::Isolate *isolate = args.GetIsolate(); + if (!isolate) + { + return; + } js_runtime *rt = static_cast(isolate->GetData(0)); // DCHECK_EQ(d->isolate, isolate); @@ -319,6 +478,10 @@ void Send(const v8::FunctionCallbackInfo &args) { raw = GetContents(rt, v8::Local::Cast(args[1])); } + else if (args[1]->IsArrayBuffer()) + { + raw = GetArrayBufferContents(rt, v8::Local::Cast(args[1])); + } rt->current_args = &args; rt->recv_cb(rt, buf, raw); @@ -416,8 +579,9 @@ extern "C" void promise_rejected_cb(v8::PromiseRejectMessage message) { - printf("Unhandled promise rejection:\n"); auto iso = v8::Isolate::GetCurrent(); + if (!iso) + return; auto rt = FromIsolate(iso); v8::HandleScope handle_scope(rt->isolate); auto error = message.GetValue(); @@ -428,18 +592,18 @@ extern "C" switch (message.GetEvent()) { case v8::kPromiseRejectWithNoHandler: - printf("no handler!\n"); + printf("Unhandled promise rejection:\n"); printf("is native error? %s\n", error->IsNativeError() ? "true" : "false"); printf("%s\n", *v8::String::Utf8Value(v8::Isolate::GetCurrent(), error)); break; - case v8::kPromiseRejectAfterResolved: - printf("promise reject after resolved\n"); - break; case v8::kPromiseHandlerAddedAfterReject: printf("promise handler added after reject\n"); break; + case v8::kPromiseRejectAfterResolved: + // ignore + break; case v8::kPromiseResolveAfterResolved: - printf("promise resolved after resolved\n"); + // ignore break; } } @@ -503,6 +667,11 @@ extern "C" int js_send(const js_runtime *rt, fly_buf buf, fly_buf raw) { + if (!rt->isolate) + { + printf("isolate has been disposed\n"); + return 0; + } v8::Locker locker(rt->isolate); v8::Isolate::Scope isolate_scope(rt->isolate); v8::HandleScope handle_scope(rt->isolate); @@ -547,6 +716,11 @@ extern "C" void js_set_response(const js_runtime *rt, fly_buf buf) { + if (!rt->isolate) + { + printf("isolate has been disposed\n"); + return; + } auto ab = ImportBuf(rt, buf); free_fly_buf(buf); rt->current_args->GetReturnValue().Set(ab); @@ -554,6 +728,11 @@ extern "C" void js_runtime_terminate(js_runtime *rt) { + if (!rt->isolate) + { + printf("isolate has been disposed\n"); + return; + } rt->context.Reset(); rt->isolate->Dispose(); free(rt); @@ -561,11 +740,21 @@ extern "C" void js_runtime_run_micro_tasks(const js_runtime *rt) { + if (!rt->isolate) + { + printf("isolate has been disposed\n"); + return; + } rt->isolate->RunMicrotasks(); } bool js_eval(const js_runtime *rt, const char *filename, const char *code) { + if (!rt->isolate) + { + printf("isolate has been disposed\n"); + return false; + } VALUE_SCOPE(rt->isolate, rt->context); return ExecuteV8StringSource(ctx, filename, code); // v8::TryCatch try_catch(rt->isolate); @@ -591,6 +780,12 @@ extern "C" // } } + bool js_run_module(const js_runtime *rt, js_compiled_module module_data) + { + VALUE_SCOPE(rt->isolate, rt->context); + return ExecuteV8Module(ctx, module_data); + } + // StartupData js_snapshot_create(const char *js) // { // v8::StartupData data = v8::V8::CreateSnapshotDataBlob(js); @@ -599,6 +794,11 @@ extern "C" js_heap_stats js_runtime_heap_statistics(const js_runtime *rt) { + if (!rt->isolate) + { + printf("isolate has been disposed\n"); + return js_heap_stats{}; + } v8::Isolate *isolate = rt->isolate; v8::HeapStatistics hs; { @@ -641,6 +841,11 @@ extern "C" void js_runtime_dispose(const runtime *rt) { + if (!rt->isolate) + { + printf("isolate has been disposed\n"); + return; + } rt->isolate->Dispose(); delete rt; } @@ -669,4 +874,10 @@ extern "C" return fly_simple_buf{blob.data, blob.raw_size}; } + + js_compile_module_result js_compile_module(const runtime *rt, js_module_data module_data) + { + VALUE_SCOPE(rt->isolate, rt->context); + return CompileV8Module(ctx, module_data); + } } diff --git a/libfly/binding.h b/libfly/binding.h index eba15d1..b879a19 100644 --- a/libfly/binding.h +++ b/libfly/binding.h @@ -35,6 +35,24 @@ struct fly_buf uintptr_t data_len; }; +struct js_module_data { + const char *origin_url; + const char *source_map_url; + bool is_wasm; + fly_simple_buf source_code; +}; + +struct js_compiled_module { + int hash; + js_module_data data; + void *ptr; // pointer to v8::Persistent +}; + +struct js_compile_module_result { + const js_compiled_module *compiled_module; + bool success; +}; + struct js_runtime; typedef struct js_runtime runtime; @@ -42,12 +60,15 @@ typedef void (*fly_recv_cb)(runtime *rt, fly_buf control_buf, fly_buf data_buf); typedef void (*fly_print_cb)(runtime *rt, int8_t lvl, const char *msg); +typedef js_compiled_module (*fly_resolve_cb)(runtime *rt, const char *specifier, int referer_identity_hash); + struct js_runtime_options { fly_simple_buf snapshot; void *data; fly_recv_cb recv_cb; fly_print_cb print_cb; + fly_resolve_cb resolve_cb; size_t soft_memory_limit; size_t hard_memory_limit; }; @@ -62,6 +83,8 @@ extern "C" extern bool js_eval(const runtime *rt, const char *filename, const char *code); + extern bool js_run_module(const runtime *rt, js_compiled_module module_data); + extern const void *js_get_data(const runtime *rt); extern void js_init(); @@ -79,6 +102,8 @@ extern "C" extern const char *js_version(); + extern js_compile_module_result js_compile_module(const runtime *rt, js_module_data module_data); + } // extern "C" #endif // libfly diff --git a/libfly/build.rs b/libfly/build.rs index 77858c6..99d71b3 100644 --- a/libfly/build.rs +++ b/libfly/build.rs @@ -29,16 +29,27 @@ fn main() { // .expect("Unable to generate bindings") // .write_to_file("binding.h"); - cc::Build::new() - .file("binding.cc") + let mut b = cc::Build::new(); + + b.file("binding.cc") .include(Path::new("v8/include/")) .cpp(true) .static_flag(true) .extra_warnings(false) - .flag("--std=c++11") - // .cpp_set_stdlib("c++") - .compile("libfly.a"); + .flag("--std=c++11"); + if cfg!(target_env = "musl") { + b.flag("-static-libstdc++") + .cpp_link_stdlib(None) + .static_crt(true); + } + + b.compile("libfly.a"); + + if cfg!(target_env = "musl") { + println!("cargo:rustc-link-search=native=/usr/lib"); + println!("cargo:rustc-link-lib=static=stdc++"); + } println!( "cargo:rustc-link-search=native={}/v8/out.gn/lib/obj", crate_dir diff --git a/libfly/runtime.h b/libfly/runtime.h index 71eec25..89898aa 100644 --- a/libfly/runtime.h +++ b/libfly/runtime.h @@ -21,6 +21,7 @@ extern "C" fly_recv_cb recv_cb; fly_print_cb print_cb; std::string last_exception; + fly_resolve_cb resolve_cb; }; } diff --git a/libfly/src/lib.rs b/libfly/src/lib.rs index de56d09..581fb6c 100644 --- a/libfly/src/lib.rs +++ b/libfly/src/lib.rs @@ -29,6 +29,7 @@ pub struct js_runtime_options { pub data: *mut c_void, pub recv_cb: RecvCb, pub print_cb: PrintCb, + pub resolve_cb: ResolveCb, pub soft_memory_limit: size_t, pub hard_memory_limit: size_t, } @@ -38,6 +39,27 @@ pub struct js_runtime { _unused: [u8; 0], } +#[repr(C)] +pub struct js_module_data { + pub origin_url: *const c_char, + pub source_map_url: *const c_char, + pub is_wasm: bool, + pub source_code: fly_simple_buf, +} + +#[repr(C)] +pub struct js_compiled_module { + pub hash: c_int, + pub data: js_module_data, + pub ptr: *mut c_void, +} + +#[repr(C)] +pub struct js_compile_module_result { + pub compiled_module: js_compiled_module, + pub success: bool, +} + #[repr(C)] pub struct js_value { _unused: [u8; 0], @@ -71,6 +93,7 @@ pub fn version() -> String { type RecvCb = unsafe extern "C" fn(rt: *const js_runtime, buf: fly_buf, data_buf: fly_buf); type PrintCb = unsafe extern "C" fn(rt: *const js_runtime, lvl: i8, msg: *const c_char); +type ResolveCb = unsafe extern "C" fn(rt: *const js_runtime, specifier: *const c_char, referer_identity_hash: i32) -> js_compiled_module; extern "C" { pub fn js_init(); @@ -86,6 +109,8 @@ extern "C" { pub fn js_dump_heap_snapshot(rt: *const js_runtime, filename: *const c_char) -> bool; pub fn js_eval(rt: *const js_runtime, filename: *const c_char, code: *const c_char) -> bool; + pub fn js_run_module(rt: *const js_runtime, module_data: js_compiled_module) -> bool; + pub fn js_compile_module(rt: *const js_runtime, module_data: js_module_data) -> js_compile_module_result; } #[no_mangle] diff --git a/msg.fbs b/msg.fbs index 7f56546..e84da21 100644 --- a/msg.fbs +++ b/msg.fbs @@ -1,7 +1,9 @@ include "src/ops/dns.fbs"; include "src/ops/cache.fbs"; +include "src/ops/data.fbs"; include "src/ops/image.fbs"; include "src/ops/acme.fbs"; +include "src/ops/os.fbs"; union Any { TimerStart, @@ -33,6 +35,7 @@ union Any { DataGet, DataGetReady, DataDel, + DataIncr, DataDropCollection, DnsQuery, DnsRequest, @@ -44,6 +47,11 @@ union Any { ImageReady, AcmeGetChallenge, AcmeGetChallengeReady, + ServiceRequest, + ServiceResponse, + RequestServiceRequest, + RequestServiceResponse, + OsExit, } enum ErrorKind: byte { @@ -141,6 +149,7 @@ table HttpRequest { method: HttpMethod; url: string; headers: [HttpHeader]; + remote_addr: string; has_body: bool; } @@ -193,29 +202,10 @@ table SourceMapReady { frames: [Frame]; } -table DataPut { - collection: string; - key: string; - json: string; -} -table DataGet { - collection: string; - key: string; -} -table DataGetReady { - json: string; -} -table DataDel { - collection: string; - key: string; -} -table DataDropCollection { - collection: string; -} - enum EventType: byte { Fetch = 0, Resolv, + Serve, } table AddEventListener { @@ -223,14 +213,35 @@ table AddEventListener { } table LoadModule { - module_specifier: string; - containing_file: string; + specifier_url: string; + referer_origin_url: string; } table LoadModuleResp { - module_id: string; - file_name: string; + origin_url: string; source_code: string; } +table ServiceRequest { + id: uint; + sender: string; + data: string; +} + +table ServiceResponse { + id: uint; + success: bool; + data: string; +} + +table RequestServiceRequest { + destination_name: string; + data: string; +} + +table RequestServiceResponse { + success: bool; + data: string; +} + root_type Base; \ No newline at end of file diff --git a/scripts/build-number.sh b/scripts/build-number.sh deleted file mode 100755 index d274944..0000000 --- a/scripts/build-number.sh +++ /dev/null @@ -1,7 +0,0 @@ -version=$(git rev-parse HEAD | cut -c-8) - -if [ -z "$CI" ]; then - version="$version-dev" -fi - -printf "$version" \ No newline at end of file diff --git a/scripts/build-release.sh b/scripts/build-release.sh index 5d8d242..dc54a37 100755 --- a/scripts/build-release.sh +++ b/scripts/build-release.sh @@ -3,5 +3,5 @@ set -e cargo run -p create_snapshot v8env/dist/v8env.js v8env.bin -cargo build --bin dns --release -cargo build -p distributed-fly --release \ No newline at end of file +cargo build --features openssl_vendored --bin fly --release +cargo build --features openssl_vendored -p distributed-fly --release diff --git a/scripts/build-version.sh b/scripts/build-version.sh new file mode 100755 index 0000000..7ec6ba1 --- /dev/null +++ b/scripts/build-version.sh @@ -0,0 +1,8 @@ +commit_sha=${BUILD_VERSION:-${TRAVIS_COMMIT:-${BUILDKITE_COMMIT:-$(git rev-parse HEAD)}}} +version=$(echo $commit_sha | cut -c-8) + +if [ -z "$CI" ]; then + version="$version-dev" +fi + +printf $version \ No newline at end of file diff --git a/scripts/prepare-release.sh b/scripts/prepare-release.sh index d11682c..ff60ca5 100755 --- a/scripts/prepare-release.sh +++ b/scripts/prepare-release.sh @@ -1,7 +1,7 @@ -strip target/release/dns -cp target/release/dns fly-dns +strip target/release/fly +cp target/release/fly fly strip target/release/distributed-fly cp target/release/distributed-fly fly-dist -tar czf $RELEASE_FILENAME fly-dns fly-dist +tar czf $RELEASE_FILENAME fly fly-dist mkdir -p release mv $RELEASE_FILENAME release/ \ No newline at end of file diff --git a/secrets.json b/secrets.json new file mode 100644 index 0000000..cc0fc52 --- /dev/null +++ b/secrets.json @@ -0,0 +1,6 @@ +{ + "someSecret": "secretData", + "secretObject": { + "subSecret": "data" + } +} \ No newline at end of file diff --git a/src/bin/dns/main.rs b/src/bin/dns/main.rs deleted file mode 100644 index 5e94184..0000000 --- a/src/bin/dns/main.rs +++ /dev/null @@ -1,79 +0,0 @@ -extern crate futures; -use futures::{future, Future}; - -extern crate tokio; - -extern crate trust_dns as dns; -extern crate trust_dns_proto; -extern crate trust_dns_server; - -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; - -extern crate flatbuffers; - -#[macro_use] -extern crate log; -extern crate env_logger; -extern crate fly; -extern crate libfly; - -use fly::runtime::*; -use fly::settings::SETTINGS; -use fly::{dns_server::DnsServer, fixed_runtime_selector::FixedRuntimeSelector}; - -use env_logger::Env; - -extern crate clap; - -static mut SELECTOR: Option = None; - -fn main() { - let env = Env::default().filter_or("LOG_LEVEL", "info"); - env_logger::init_from_env(env); - debug!("V8 version: {}", libfly::version()); - - let matches = clap::App::new("fly-dns") - .version("0.0.1-alpha") - .about("Fly DNS server") - .arg( - clap::Arg::with_name("port") - .short("p") - .long("port") - .takes_value(true), - ) - .arg( - clap::Arg::with_name("input") - .help("Sets the input file to use") - .required(true) - .index(1), - ) - .get_matches(); - - let entry_file = matches.value_of("input").unwrap(); - let mut runtime = Runtime::new(None, None, &SETTINGS.read().unwrap()); - - debug!("Loading dev tools"); - runtime.eval_file("v8env/dist/dev-tools.js"); - runtime.eval("", "installDevTools();"); - debug!("Loading dev tools done"); - runtime.eval(entry_file, &format!("dev.run('{}')", entry_file)); - - let port: u16 = match matches.value_of("port") { - Some(pstr) => pstr.parse::().unwrap(), - None => 8053, - }; - - let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port); - - tokio::run(future::lazy(move || -> Result<(), ()> { - tokio::spawn( - runtime - .run() - .map_err(|e| error!("error running runtime event loop: {}", e)), - ); - unsafe { SELECTOR = Some(FixedRuntimeSelector::new(runtime)) } - let server = DnsServer::new(addr, unsafe {SELECTOR.as_ref().unwrap()}); - server.start(); - Ok(()) - })); -} diff --git a/src/bin/eval/main.rs b/src/bin/eval/main.rs deleted file mode 100644 index 0b216d4..0000000 --- a/src/bin/eval/main.rs +++ /dev/null @@ -1,42 +0,0 @@ -extern crate clap; -extern crate futures; -extern crate tokio; - -#[macro_use] -extern crate log; -extern crate env_logger; - -use env_logger::Env; - -extern crate fly; -use fly::runtime::Runtime; -use fly::settings::SETTINGS; - -use futures::Future; - -fn main() { - let env = Env::default().filter_or("LOG_LEVEL", "debug"); - env_logger::init_from_env(env); - debug!("V8 version: {}", libfly::version()); - - let matches = clap::App::new("fly-tsc") - .version("0.0.1-alpha") - .about("Fly typescript compiler") - .arg( - clap::Arg::with_name("input") - .help("Sets the input file to use") - .required(true) - .index(1), - ).get_matches(); - - let mut runtime = Runtime::new(None, None, &SETTINGS.read().unwrap()); - debug!("Loading dev tools"); - runtime.eval_file("v8env/dist/dev-tools.js"); - runtime.eval("", "installDevTools();"); - debug!("Loading dev tools done"); - - let entry_file = matches.value_of("input").unwrap(); - - runtime.eval(entry_file, &format!("dev.run('{}')", entry_file)); - runtime.run().wait().unwrap(); -} diff --git a/src/bin/fly/commands/dns.rs b/src/bin/fly/commands/dns.rs new file mode 100644 index 0000000..2aa4fc1 --- /dev/null +++ b/src/bin/fly/commands/dns.rs @@ -0,0 +1,167 @@ +use crate::errors::*; +use crate::util::*; +use clap::{Arg, ArgMatches}; + +extern crate futures; +use futures::{future, Future}; +extern crate tokio; +extern crate trust_dns as dns; +extern crate trust_dns_server; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +extern crate flatbuffers; +extern crate fly; +extern crate libfly; +use fly::module_resolver::{JsonSecretsResolver, LocalDiskModuleResolver, ModuleResolver}; +use fly::runtime::*; +use fly::settings::SETTINGS; +use fly::{dns_server::DnsServer, standard_runtime_manager::StandardRuntimeManager, runtime_manager::RuntimeManager, runtime_manager::RuntimeManagerError}; +extern crate clap; +use std::path::PathBuf; + +pub fn cli() -> App { + subcommand("dns") + .about("Fly DNS server") + .arg( + Arg::with_name("path") + .help("The app to run") + .required(true) + .index(1), + ) + .arg( + clap::Arg::with_name("port") + .short("p") + .long("port") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("bind") + .short("b") + .long("bind") + .takes_value(true), + ) +} + +pub fn exec(args: &ArgMatches<'_>) -> FlyCliResult<()> { + debug!("V8 version: {}", libfly::version()); + + let mut module_resolvers: Vec> = std::vec::Vec::new(); + let mut test_service_module_resolvers: Vec> = std::vec::Vec::new(); + + let secrets_file = match args.value_of("secrets-file") { + Some(v) => v, + None => "./secrets.json", + }; + + let secrets_file_path = PathBuf::from(secrets_file); + info!( + "Loading secrets file from path {}", + secrets_file_path.to_str().unwrap().to_string() + ); + match secrets_file_path.is_file() { + true => { + let secrets_json = + match std::fs::read_to_string(&secrets_file_path.to_str().unwrap().to_string()) { + Ok(v) => v, + Err(_err) => { + info!("Failed to load secrets file!"); + "{}".to_string() + } + }; + let json_value: serde_json::Value = match serde_json::from_str(secrets_json.as_str()) { + Ok(v) => v, + Err(_err) => { + // TODO: actual error output + info!("Failed to parse json"); + serde_json::from_str("{}").unwrap() + } + }; + module_resolvers.push(Box::new(JsonSecretsResolver::new(json_value))); + } + false => { + info!("Secrets file invalid"); + } + }; + + module_resolvers.push(Box::new(LocalDiskModuleResolver::new(None))); + test_service_module_resolvers.push(Box::new(LocalDiskModuleResolver::new(None))); + + info!( + "Module resolvers length {}", + module_resolvers.len().to_string() + ); + + let entry_file = args.value_of("path").unwrap(); + + let rt_manager = StandardRuntimeManager::new(); + + let runtime = rt_manager.write().unwrap().new_runtime(RuntimeConfig { + name: None, + version: None, + settings: &SETTINGS.read().unwrap(), + module_resolvers: Some(module_resolvers), + app_logger: &slog_scope::logger(), + msg_handler: None, + permissions: None, + dev_tools: true, + }); + + let test_service_runtime = rt_manager.write().unwrap().new_runtime(RuntimeConfig { + name: None, + version: None, + settings: &SETTINGS.read().unwrap(), + module_resolvers: Some(test_service_module_resolvers), + app_logger: &slog_scope::logger(), + msg_handler: None, + permissions: None, + dev_tools: true, + }); + + { + let rt_arc_clone = runtime.clone(); + let rt_lock = rt_arc_clone.read().unwrap(); + rt_lock.eval_file_with_dev_tools(entry_file); + let test_rt_arc_clone = test_service_runtime.clone(); + let test_rt_lock = test_rt_arc_clone.read().unwrap(); + test_rt_lock.eval_file_with_dev_tools("./test-service-runtime.js"); + match rt_manager.write().unwrap().bind_servicename_to(uuid::Uuid::parse_str(test_rt_lock.get_uuid().as_str()).unwrap(), "test") { + Ok(v) => { + debug!("Assigned servicename success!"); + }, + Err(RuntimeManagerError::Failure(e)) => { + debug!("Failed to assign: {}", e); + }, + }; + match rt_manager.write().unwrap().bind_hostname_to(uuid::Uuid::parse_str(rt_lock.get_uuid().as_str()).unwrap(), "test.com") { + Ok(v) => { + debug!("Assigned hostname success!"); + }, + Err(RuntimeManagerError::Failure(e)) => { + debug!("Failed to assign: {}", e); + }, + } + } + + + + let port: u16 = match args.value_of("port") { + Some(pstr) => pstr.parse::().unwrap(), + None => 8053, + }; + + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port); + + tokio::run(future::lazy(move || -> Result<(), ()> { + let rt_lock = runtime.read().unwrap(); + tokio::spawn( + rt_lock + .ptr.to_runtime() + .run() + .map_err(|e| error!("error running runtime event loop: {}", e)), + ); + let server = DnsServer::new(addr, rt_manager.clone()); + server.start(); + Ok(()) + })); + + Ok(()) +} diff --git a/src/bin/fly/commands/eval.rs b/src/bin/fly/commands/eval.rs new file mode 100644 index 0000000..2dd9e88 --- /dev/null +++ b/src/bin/fly/commands/eval.rs @@ -0,0 +1,34 @@ +use crate::errors::*; +use crate::util::*; +use clap::{Arg, ArgMatches}; +use fly::runtime::{Runtime, RuntimeConfig}; +use fly::settings::SETTINGS; +use futures::Future; + +pub fn cli() -> App { + subcommand("eval").about("Run a file").arg( + Arg::with_name("input") + .help("the input file to use") + .required(true) + .index(1), + ) +} + +pub fn exec(args: &ArgMatches<'_>) -> FlyCliResult<()> { + let mut runtime = Runtime::new(RuntimeConfig { + name: None, + version: None, + settings: &SETTINGS.read().unwrap(), + module_resolvers: None, + app_logger: &slog_scope::logger(), + msg_handler: None, + permissions: None, + dev_tools: true, + }); + + let entry_file = args.value_of("input").unwrap(); + runtime.eval_file_with_dev_tools(entry_file); + runtime.run().wait().unwrap(); + + Ok(()) +} diff --git a/src/bin/fly/commands/http.rs b/src/bin/fly/commands/http.rs new file mode 100644 index 0000000..718e3da --- /dev/null +++ b/src/bin/fly/commands/http.rs @@ -0,0 +1,132 @@ +use crate::errors::*; +use crate::util::*; +use clap::{Arg, ArgMatches}; + +use hyper::rt::Future; +use hyper::server::conn::AddrStream; +use hyper::service::{make_service_fn, service_fn}; +use hyper::Server; + +use tokio::prelude::*; + +use fly::{dns_server::DnsServer, standard_runtime_manager::StandardRuntimeManager, runtime_manager::RuntimeManager}; +use fly::http_server::serve_http; +use fly::runtime::*; +use fly::settings::SETTINGS; + +pub fn cli() -> App { + subcommand("http") + .about("Fly HTTP server") + .arg( + Arg::with_name("path") + .help("The app to run") + .default_value("./index.{ts,js}") + .index(1), + ) + .arg( + clap::Arg::with_name("port") + .short("p") + .long("port") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("bind") + .short("b") + .long("bind") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("lib") + .short("l") + .long("lib") + .help("Libraries or shims to load before app code") + .takes_value(true) + .multiple(true), + ) +} + +pub fn exec(args: &ArgMatches<'_>) -> FlyCliResult<()> { + info!("V8 version: {}", libfly::version()); + + let rt_manager = StandardRuntimeManager::new(); + + let runtime = rt_manager.write().unwrap().new_runtime(RuntimeConfig { + name: None, + version: None, + settings: &SETTINGS.read().unwrap(), + module_resolvers: None, + app_logger: &slog_scope::logger(), + msg_handler: None, + permissions: None, + dev_tools: true, + }); + + { + let rt_ref_clone = runtime.clone(); + let rt_lock = rt_ref_clone.read().unwrap(); + if args.is_present("lib") { + for lib_path in glob(args.values_of("lib").unwrap().collect(), None)? { + rt_lock.eval_file(&lib_path); + } + } + + if let Some(path) = glob(vec![args.value_of("path").unwrap()], Some(1))?.first() { + println!("Running app {}", path); + rt_lock.eval_file_with_dev_tools(path); + } else { + return Err(FlyCliError::from("No source code found")); + } + } + + + let bind = match args.value_of("bind") { + Some(b) => b, + None => "127.0.0.1", + }; + let port: u16 = match args.value_of("port") { + Some(pstr) => pstr.parse::().unwrap(), + None => 8080, + }; + + let addr = format!("{}:{}", bind, port).parse().unwrap(); + + let (sigfut, sigrx) = fly::utils::signal_monitor(); + + let server = Server::bind(&addr) + .serve(make_service_fn(move |conn: &AddrStream| { + let remote_addr = conn.remote_addr(); + let rt_manager_clone = rt_manager.clone(); + service_fn(move |req| { + serve_http( + false, + req, + rt_manager_clone.clone(), + remote_addr, + ) + }) + })) + .with_graceful_shutdown(sigrx) + .map_err(|e| error!("server error: {}", e)) + .and_then(|_| { + info!("HTTP server closed."); + Ok(()) + }); + + tokio::run(future::lazy(move || { + let rt_lock = runtime.read().unwrap(); + tokio::spawn( + rt_lock + .ptr.to_runtime() + .run() + .map_err(|e| error!("error running runtime event loop: {}", e)), + ); + + tokio::spawn(server); + + println!("Listening on http://{}", addr); + + sigfut + })); + + Ok(()) +} diff --git a/src/bin/fly/commands/mod.rs b/src/bin/fly/commands/mod.rs new file mode 100644 index 0000000..a21fb9b --- /dev/null +++ b/src/bin/fly/commands/mod.rs @@ -0,0 +1,22 @@ +use crate::util::*; + +pub fn commands() -> Vec { + vec![http::cli(), test::cli(), dns::cli(), eval::cli()] +} + +pub fn command_exec(name: &str) -> Option { + let exec = match name { + "dns" => dns::exec, + "eval" => eval::exec, + "http" => http::exec, + "test" => test::exec, + _ => return None, + }; + + Some(exec) +} + +pub mod dns; +pub mod eval; +pub mod http; +pub mod test; diff --git a/src/bin/fly/commands/test.rs b/src/bin/fly/commands/test.rs new file mode 100644 index 0000000..da88547 --- /dev/null +++ b/src/bin/fly/commands/test.rs @@ -0,0 +1,65 @@ +use crate::errors::*; +use crate::util::*; +use clap::{Arg, ArgMatches}; +use fly::runtime::{Runtime, RuntimeConfig}; +use fly::runtime_permissions::RuntimePermissions; +use fly::settings::SETTINGS; +use futures::Future; + +const PATTERN_DEFAULT: &str = "**/*.{test,spec}.{js,ts}"; + +pub fn cli() -> App { + subcommand("test") + .about("Run unit tests") + .arg( + Arg::with_name("paths") + .help("Paths or patterns for test files to run.") + .default_value(PATTERN_DEFAULT) + .multiple(true) + .index(1), + ) + .arg( + clap::Arg::with_name("lib") + .short("l") + .long("lib") + .help("Libraries or shims to load before app code") + .takes_value(true) + .multiple(true), + ) +} + +pub fn exec(args: &ArgMatches<'_>) -> FlyCliResult<()> { + let mut rt = Runtime::new(RuntimeConfig { + name: None, + version: None, + settings: &SETTINGS.read().unwrap(), + module_resolvers: None, + app_logger: &slog_scope::logger(), + msg_handler: None, + permissions: Some(RuntimePermissions::new(true)), + dev_tools: true, + }); + + if args.is_present("lib") { + for lib_path in glob(args.values_of("lib").unwrap().collect(), None)? { + rt.eval_file(&lib_path); + } + } + + let test_files = glob(args.values_of("paths").unwrap().collect(), None)?; + + rt.eval( + "", + &format!( + "dev.runTests({});", + serde_json::to_string(&test_files).expect("error loading test files") + ), + ); + + tokio::run( + rt.run() + .map_err(|_| error!("error running runtime event loop")), + ); + + Ok(()) +} diff --git a/src/bin/fly/errors.rs b/src/bin/fly/errors.rs new file mode 100644 index 0000000..2cafa05 --- /dev/null +++ b/src/bin/fly/errors.rs @@ -0,0 +1,81 @@ +use std; +use std::fmt; +use std::io; + +pub type FlyCliResult = Result; + +#[derive(Debug)] +pub struct FlyCliError { + repr: Repr, +} + +#[derive(Debug)] +enum Repr { + Simple(String), + IoErr(io::Error), + ClapError(clap::Error), +} + +impl fmt::Display for FlyCliError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.repr { + Repr::IoErr(ref err) => err.fmt(f), + Repr::Simple(ref s) => write!(f, "{}", s), + Repr::ClapError(ref err) => err.fmt(f), + } + } +} + +impl std::error::Error for FlyCliError { + fn description(&self) -> &str { + match self.repr { + Repr::IoErr(ref err) => err.description(), + Repr::Simple(ref s) => s.as_str(), + Repr::ClapError(ref err) => err.description(), + } + } + + fn cause(&self) -> Option<&std::error::Error> { + match self.repr { + Repr::IoErr(ref err) => Some(err), + Repr::Simple(_) => None, + Repr::ClapError(ref err) => Some(err), + } + } +} + +impl From for FlyCliError { + #[inline] + fn from(err: io::Error) -> FlyCliError { + FlyCliError { + repr: Repr::IoErr(err), + } + } +} + +impl From for FlyCliError { + #[inline] + fn from(err: clap::Error) -> FlyCliError { + FlyCliError { + repr: Repr::ClapError(err), + } + } +} + +impl From<&str> for FlyCliError { + #[inline] + fn from(err: &str) -> FlyCliError { + FlyCliError { + repr: Repr::Simple(err.to_owned()), + } + } +} + +impl From<()> for FlyCliError { + #[inline] + fn from(_: ()) -> FlyCliError { + FlyCliError { + repr: Repr::Simple("Errored with non message error.".to_string()), + } + } +} diff --git a/src/bin/fly/main.rs b/src/bin/fly/main.rs new file mode 100644 index 0000000..5e7cb9c --- /dev/null +++ b/src/bin/fly/main.rs @@ -0,0 +1,48 @@ +mod commands; +mod errors; +mod util; + +#[macro_use] +extern crate log; +use crate::errors::FlyCliResult; +use crate::util::*; +use clap::AppSettings; +use slog::{Drain, Level}; + +fn main() -> FlyCliResult<()> { + let logger = build_logger(); + let _guard = slog_scope::set_global_logger(logger); + slog_stdlog::init().unwrap(); + + let args = cli().get_matches(); + let (cmd, subcommand_args) = args.subcommand(); + let exec_fn = commands::command_exec(cmd).expect("Unknown command"); + + exec_fn(subcommand_args.unwrap()) +} + +fn cli() -> App { + App::new("fly") + .global_settings(&[ + AppSettings::DeriveDisplayOrder, + AppSettings::DontCollapseArgsInUsage, + AppSettings::ArgRequiredElseHelp, + AppSettings::UnifiedHelpMessage, + ]) + .about("Edge application runtime") + .subcommands(commands::commands()) +} + +fn build_logger() -> slog::Logger { + fly::logging::build_routing_logger( + slog_term::term_full() + .filter_level(fly::logging::log_level_from_env( + "FLY_LOG_LEVEL", + Level::Warning, + )) + .fuse(), + slog_term::term_full() + .filter_level(fly::logging::log_level_from_env("LOG_LEVEL", Level::Info)) + .fuse(), + ) +} diff --git a/src/bin/fly/util.rs b/src/bin/fly/util.rs new file mode 100644 index 0000000..b4c79c0 --- /dev/null +++ b/src/bin/fly/util.rs @@ -0,0 +1,54 @@ +use crate::errors::{FlyCliError, FlyCliResult}; +use clap::{AppSettings, ArgMatches, SubCommand}; +use std::error::Error; + +pub type App = clap::App<'static, 'static>; + +pub type ExecFn = fn(&ArgMatches<'_>) -> FlyCliResult<()>; + +pub fn subcommand(name: &'static str) -> App { + SubCommand::with_name(name).settings(&[ + AppSettings::UnifiedHelpMessage, + AppSettings::DeriveDisplayOrder, + AppSettings::DontCollapseArgsInUsage, + ]) +} + +pub fn glob(patterns: Vec<&str>, max_depth: Option) -> FlyCliResult> { + let patterns: Vec<&str> = patterns.into_iter().map(clean_pattern).collect(); + + let mut builder = globwalk::GlobWalkerBuilder::from_patterns(".", &patterns); + + if let Some(d) = max_depth { + builder = builder.max_depth(d); + } + + let walker = builder + .build() + .map_err(|e| FlyCliError::from(e.description()))?; + + let mut files: Vec = vec![]; + + for entry in walker { + if let Ok(entry) = entry { + let path = entry.path(); + + if !path.is_file() { + continue; + } + + if let Some(path) = path.to_str() { + files.push(path.to_owned()); + } + } + } + + Ok(files) +} + +fn clean_pattern(pattern: &str) -> &str { + if pattern.starts_with("./") { + return &pattern[2..]; + } + pattern +} diff --git a/src/bin/http/main.rs b/src/bin/http/main.rs deleted file mode 100644 index 15edce1..0000000 --- a/src/bin/http/main.rs +++ /dev/null @@ -1,105 +0,0 @@ -#[macro_use] -extern crate log; - -extern crate clap; - -extern crate env_logger; -extern crate fly; -extern crate tokio; - -extern crate libfly; - -extern crate hyper; -use hyper::rt::Future; -use hyper::server::conn::AddrStream; -use hyper::service::{make_service_fn, service_fn}; -use hyper::Server; - -extern crate futures; - -use tokio::prelude::*; - -use fly::fixed_runtime_selector::FixedRuntimeSelector; -use fly::http_server::serve_http; -use fly::runtime::*; -use fly::settings::SETTINGS; - -use env_logger::Env; - -static mut SELECTOR: Option = None; - -fn main() { - let env = Env::default().filter_or("LOG_LEVEL", "info"); - - env_logger::init_from_env(env); - - let matches = clap::App::new("fly-http") - .version("0.0.1-alpha") - .about("Fly HTTP server") - .arg( - clap::Arg::with_name("port") - .short("p") - .long("port") - .takes_value(true), - ) - .arg( - clap::Arg::with_name("bind") - .short("b") - .long("bind") - .takes_value(true), - ) - .arg( - clap::Arg::with_name("input") - .help("Sets the input file to use") - .required(true) - .index(1), - ) - .get_matches(); - - info!("V8 version: {}", libfly::version()); - - let entry_file = matches.value_of("input").unwrap(); - let mut runtime = Runtime::new(None, None, &SETTINGS.read().unwrap()); - - debug!("Loading dev tools"); - runtime.eval_file("v8env/dist/dev-tools.js"); - runtime.eval("", "installDevTools();"); - debug!("Loading dev tools done"); - runtime.eval(entry_file, &format!("dev.run('{}')", entry_file)); - - let bind = match matches.value_of("bind") { - Some(b) => b, - None => "127.0.0.1", - }; - let port: u16 = match matches.value_of("port") { - Some(pstr) => pstr.parse::().unwrap(), - None => 8080, - }; - - let addr = format!("{}:{}", bind, port).parse().unwrap(); - - tokio::run(future::lazy(move || { - tokio::spawn( - runtime - .run() - .map_err(|e| error!("error running runtime event loop: {}", e)), - ); - unsafe { SELECTOR = Some(FixedRuntimeSelector::new(runtime)) } - let server = Server::bind(&addr) - .serve(make_service_fn(move |conn: &AddrStream| { - let remote_addr = conn.remote_addr(); - service_fn(move |req| { - serve_http( - false, - req, - unsafe { SELECTOR.as_ref().unwrap() }, - remote_addr, - ) - }) - })) - .map_err(|e| eprintln!("server error: {}", e)); - - info!("Listening on http://{}", addr); - server - })); -} diff --git a/src/bin/test/chai.js b/src/bin/test/chai.js deleted file mode 100644 index 3aea762..0000000 --- a/src/bin/test/chai.js +++ /dev/null @@ -1,10707 +0,0 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.chai = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o - * MIT Licensed - */ - -var used = []; - -/*! - * Chai version - */ - -exports.version = '4.1.2'; - -/*! - * Assertion Error - */ - -exports.AssertionError = require('assertion-error'); - -/*! - * Utils for plugins (not exported) - */ - -var util = require('./chai/utils'); - -/** - * # .use(function) - * - * Provides a way to extend the internals of Chai. - * - * @param {Function} - * @returns {this} for chaining - * @api public - */ - -exports.use = function (fn) { - if (!~used.indexOf(fn)) { - fn(exports, util); - used.push(fn); - } - - return exports; -}; - -/*! - * Utility Functions - */ - -exports.util = util; - -/*! - * Configuration - */ - -var config = require('./chai/config'); -exports.config = config; - -/*! - * Primary `Assertion` prototype - */ - -var assertion = require('./chai/assertion'); -exports.use(assertion); - -/*! - * Core Assertions - */ - -var core = require('./chai/core/assertions'); -exports.use(core); - -/*! - * Expect interface - */ - -var expect = require('./chai/interface/expect'); -exports.use(expect); - -/*! - * Should interface - */ - -var should = require('./chai/interface/should'); -exports.use(should); - -/*! - * Assert interface - */ - -var assert = require('./chai/interface/assert'); -exports.use(assert); - -},{"./chai/assertion":3,"./chai/config":4,"./chai/core/assertions":5,"./chai/interface/assert":6,"./chai/interface/expect":7,"./chai/interface/should":8,"./chai/utils":22,"assertion-error":33}],3:[function(require,module,exports){ -/*! - * chai - * http://chaijs.com - * Copyright(c) 2011-2014 Jake Luer - * MIT Licensed - */ - -var config = require('./config'); - -module.exports = function (_chai, util) { - /*! - * Module dependencies. - */ - - var AssertionError = _chai.AssertionError - , flag = util.flag; - - /*! - * Module export. - */ - - _chai.Assertion = Assertion; - - /*! - * Assertion Constructor - * - * Creates object for chaining. - * - * `Assertion` objects contain metadata in the form of flags. Three flags can - * be assigned during instantiation by passing arguments to this constructor: - * - * - `object`: This flag contains the target of the assertion. For example, in - * the assertion `expect(numKittens).to.equal(7);`, the `object` flag will - * contain `numKittens` so that the `equal` assertion can reference it when - * needed. - * - * - `message`: This flag contains an optional custom error message to be - * prepended to the error message that's generated by the assertion when it - * fails. - * - * - `ssfi`: This flag stands for "start stack function indicator". It - * contains a function reference that serves as the starting point for - * removing frames from the stack trace of the error that's created by the - * assertion when it fails. The goal is to provide a cleaner stack trace to - * end users by removing Chai's internal functions. Note that it only works - * in environments that support `Error.captureStackTrace`, and only when - * `Chai.config.includeStack` hasn't been set to `false`. - * - * - `lockSsfi`: This flag controls whether or not the given `ssfi` flag - * should retain its current value, even as assertions are chained off of - * this object. This is usually set to `true` when creating a new assertion - * from within another assertion. It's also temporarily set to `true` before - * an overwritten assertion gets called by the overwriting assertion. - * - * @param {Mixed} obj target of the assertion - * @param {String} msg (optional) custom error message - * @param {Function} ssfi (optional) starting point for removing stack frames - * @param {Boolean} lockSsfi (optional) whether or not the ssfi flag is locked - * @api private - */ - - function Assertion (obj, msg, ssfi, lockSsfi) { - flag(this, 'ssfi', ssfi || Assertion); - flag(this, 'lockSsfi', lockSsfi); - flag(this, 'object', obj); - flag(this, 'message', msg); - - return util.proxify(this); - } - - Object.defineProperty(Assertion, 'includeStack', { - get: function() { - console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); - return config.includeStack; - }, - set: function(value) { - console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); - config.includeStack = value; - } - }); - - Object.defineProperty(Assertion, 'showDiff', { - get: function() { - console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); - return config.showDiff; - }, - set: function(value) { - console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); - config.showDiff = value; - } - }); - - Assertion.addProperty = function (name, fn) { - util.addProperty(this.prototype, name, fn); - }; - - Assertion.addMethod = function (name, fn) { - util.addMethod(this.prototype, name, fn); - }; - - Assertion.addChainableMethod = function (name, fn, chainingBehavior) { - util.addChainableMethod(this.prototype, name, fn, chainingBehavior); - }; - - Assertion.overwriteProperty = function (name, fn) { - util.overwriteProperty(this.prototype, name, fn); - }; - - Assertion.overwriteMethod = function (name, fn) { - util.overwriteMethod(this.prototype, name, fn); - }; - - Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) { - util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior); - }; - - /** - * ### .assert(expression, message, negateMessage, expected, actual, showDiff) - * - * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. - * - * @name assert - * @param {Philosophical} expression to be tested - * @param {String|Function} message or function that returns message to display if expression fails - * @param {String|Function} negatedMessage or function that returns negatedMessage to display if negated expression fails - * @param {Mixed} expected value (remember to check for negation) - * @param {Mixed} actual (optional) will default to `this.obj` - * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails - * @api private - */ - - Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { - var ok = util.test(this, arguments); - if (false !== showDiff) showDiff = true; - if (undefined === expected && undefined === _actual) showDiff = false; - if (true !== config.showDiff) showDiff = false; - - if (!ok) { - msg = util.getMessage(this, arguments); - var actual = util.getActual(this, arguments); - throw new AssertionError(msg, { - actual: actual - , expected: expected - , showDiff: showDiff - }, (config.includeStack) ? this.assert : flag(this, 'ssfi')); - } - }; - - /*! - * ### ._obj - * - * Quick reference to stored `actual` value for plugin developers. - * - * @api private - */ - - Object.defineProperty(Assertion.prototype, '_obj', - { get: function () { - return flag(this, 'object'); - } - , set: function (val) { - flag(this, 'object', val); - } - }); -}; - -},{"./config":4}],4:[function(require,module,exports){ -module.exports = { - - /** - * ### config.includeStack - * - * User configurable property, influences whether stack trace - * is included in Assertion error message. Default of false - * suppresses stack trace in the error message. - * - * chai.config.includeStack = true; // enable stack on error - * - * @param {Boolean} - * @api public - */ - - includeStack: false, - - /** - * ### config.showDiff - * - * User configurable property, influences whether or not - * the `showDiff` flag should be included in the thrown - * AssertionErrors. `false` will always be `false`; `true` - * will be true when the assertion has requested a diff - * be shown. - * - * @param {Boolean} - * @api public - */ - - showDiff: true, - - /** - * ### config.truncateThreshold - * - * User configurable property, sets length threshold for actual and - * expected values in assertion errors. If this threshold is exceeded, for - * example for large data structures, the value is replaced with something - * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`. - * - * Set it to zero if you want to disable truncating altogether. - * - * This is especially userful when doing assertions on arrays: having this - * set to a reasonable large value makes the failure messages readily - * inspectable. - * - * chai.config.truncateThreshold = 0; // disable truncating - * - * @param {Number} - * @api public - */ - - truncateThreshold: 40, - - /** - * ### config.useProxy - * - * User configurable property, defines if chai will use a Proxy to throw - * an error when a non-existent property is read, which protects users - * from typos when using property-based assertions. - * - * Set it to false if you want to disable this feature. - * - * chai.config.useProxy = false; // disable use of Proxy - * - * This feature is automatically disabled regardless of this config value - * in environments that don't support proxies. - * - * @param {Boolean} - * @api public - */ - - useProxy: true, - - /** - * ### config.proxyExcludedKeys - * - * User configurable property, defines which properties should be ignored - * instead of throwing an error if they do not exist on the assertion. - * This is only applied if the environment Chai is running in supports proxies and - * if the `useProxy` configuration setting is enabled. - * By default, `then` and `inspect` will not throw an error if they do not exist on the - * assertion object because the `.inspect` property is read by `util.inspect` (for example, when - * using `console.log` on the assertion object) and `.then` is necessary for promise type-checking. - * - * // By default these keys will not throw an error if they do not exist on the assertion object - * chai.config.proxyExcludedKeys = ['then', 'inspect']; - * - * @param {Array} - * @api public - */ - - proxyExcludedKeys: ['then', 'inspect', 'toJSON'] -}; - -},{}],5:[function(require,module,exports){ -/*! - * chai - * http://chaijs.com - * Copyright(c) 2011-2014 Jake Luer - * MIT Licensed - */ - -module.exports = function (chai, _) { - var Assertion = chai.Assertion - , AssertionError = chai.AssertionError - , flag = _.flag; - - /** - * ### Language Chains - * - * The following are provided as chainable getters to improve the readability - * of your assertions. - * - * **Chains** - * - * - to - * - be - * - been - * - is - * - that - * - which - * - and - * - has - * - have - * - with - * - at - * - of - * - same - * - but - * - does - * - * @name language chains - * @namespace BDD - * @api public - */ - - [ 'to', 'be', 'been' - , 'is', 'and', 'has', 'have' - , 'with', 'that', 'which', 'at' - , 'of', 'same', 'but', 'does' ].forEach(function (chain) { - Assertion.addProperty(chain); - }); - - /** - * ### .not - * - * Negates all assertions that follow in the chain. - * - * expect(function () {}).to.not.throw(); - * expect({a: 1}).to.not.have.property('b'); - * expect([1, 2]).to.be.an('array').that.does.not.include(3); - * - * Just because you can negate any assertion with `.not` doesn't mean you - * should. With great power comes great responsibility. It's often best to - * assert that the one expected output was produced, rather than asserting - * that one of countless unexpected outputs wasn't produced. See individual - * assertions for specific guidance. - * - * expect(2).to.equal(2); // Recommended - * expect(2).to.not.equal(1); // Not recommended - * - * @name not - * @namespace BDD - * @api public - */ - - Assertion.addProperty('not', function () { - flag(this, 'negate', true); - }); - - /** - * ### .deep - * - * Causes all `.equal`, `.include`, `.members`, `.keys`, and `.property` - * assertions that follow in the chain to use deep equality instead of strict - * (`===`) equality. See the `deep-eql` project page for info on the deep - * equality algorithm: https://github.com/chaijs/deep-eql. - * - * // Target object deeply (but not strictly) equals `{a: 1}` - * expect({a: 1}).to.deep.equal({a: 1}); - * expect({a: 1}).to.not.equal({a: 1}); - * - * // Target array deeply (but not strictly) includes `{a: 1}` - * expect([{a: 1}]).to.deep.include({a: 1}); - * expect([{a: 1}]).to.not.include({a: 1}); - * - * // Target object deeply (but not strictly) includes `x: {a: 1}` - * expect({x: {a: 1}}).to.deep.include({x: {a: 1}}); - * expect({x: {a: 1}}).to.not.include({x: {a: 1}}); - * - * // Target array deeply (but not strictly) has member `{a: 1}` - * expect([{a: 1}]).to.have.deep.members([{a: 1}]); - * expect([{a: 1}]).to.not.have.members([{a: 1}]); - * - * // Target set deeply (but not strictly) has key `{a: 1}` - * expect(new Set([{a: 1}])).to.have.deep.keys([{a: 1}]); - * expect(new Set([{a: 1}])).to.not.have.keys([{a: 1}]); - * - * // Target object deeply (but not strictly) has property `x: {a: 1}` - * expect({x: {a: 1}}).to.have.deep.property('x', {a: 1}); - * expect({x: {a: 1}}).to.not.have.property('x', {a: 1}); - * - * @name deep - * @namespace BDD - * @api public - */ - - Assertion.addProperty('deep', function () { - flag(this, 'deep', true); - }); - - /** - * ### .nested - * - * Enables dot- and bracket-notation in all `.property` and `.include` - * assertions that follow in the chain. - * - * expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]'); - * expect({a: {b: ['x', 'y']}}).to.nested.include({'a.b[1]': 'y'}); - * - * If `.` or `[]` are part of an actual property name, they can be escaped by - * adding two backslashes before them. - * - * expect({'.a': {'[b]': 'x'}}).to.have.nested.property('\\.a.\\[b\\]'); - * expect({'.a': {'[b]': 'x'}}).to.nested.include({'\\.a.\\[b\\]': 'x'}); - * - * `.nested` cannot be combined with `.own`. - * - * @name nested - * @namespace BDD - * @api public - */ - - Assertion.addProperty('nested', function () { - flag(this, 'nested', true); - }); - - /** - * ### .own - * - * Causes all `.property` and `.include` assertions that follow in the chain - * to ignore inherited properties. - * - * Object.prototype.b = 2; - * - * expect({a: 1}).to.have.own.property('a'); - * expect({a: 1}).to.have.property('b').but.not.own.property('b'); - * - * expect({a: 1}).to.own.include({a: 1}); - * expect({a: 1}).to.include({b: 2}).but.not.own.include({b: 2}); - * - * `.own` cannot be combined with `.nested`. - * - * @name own - * @namespace BDD - * @api public - */ - - Assertion.addProperty('own', function () { - flag(this, 'own', true); - }); - - /** - * ### .ordered - * - * Causes all `.members` assertions that follow in the chain to require that - * members be in the same order. - * - * expect([1, 2]).to.have.ordered.members([1, 2]) - * .but.not.have.ordered.members([2, 1]); - * - * When `.include` and `.ordered` are combined, the ordering begins at the - * start of both arrays. - * - * expect([1, 2, 3]).to.include.ordered.members([1, 2]) - * .but.not.include.ordered.members([2, 3]); - * - * @name ordered - * @namespace BDD - * @api public - */ - - Assertion.addProperty('ordered', function () { - flag(this, 'ordered', true); - }); - - /** - * ### .any - * - * Causes all `.keys` assertions that follow in the chain to only require that - * the target have at least one of the given keys. This is the opposite of - * `.all`, which requires that the target have all of the given keys. - * - * expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd'); - * - * See the `.keys` doc for guidance on when to use `.any` or `.all`. - * - * @name any - * @namespace BDD - * @api public - */ - - Assertion.addProperty('any', function () { - flag(this, 'any', true); - flag(this, 'all', false); - }); - - - /** - * ### .all - * - * Causes all `.keys` assertions that follow in the chain to require that the - * target have all of the given keys. This is the opposite of `.any`, which - * only requires that the target have at least one of the given keys. - * - * expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); - * - * Note that `.all` is used by default when neither `.all` nor `.any` are - * added earlier in the chain. However, it's often best to add `.all` anyway - * because it improves readability. - * - * See the `.keys` doc for guidance on when to use `.any` or `.all`. - * - * @name all - * @namespace BDD - * @api public - */ - - Assertion.addProperty('all', function () { - flag(this, 'all', true); - flag(this, 'any', false); - }); - - /** - * ### .a(type[, msg]) - * - * Asserts that the target's type is equal to the given string `type`. Types - * are case insensitive. See the `type-detect` project page for info on the - * type detection algorithm: https://github.com/chaijs/type-detect. - * - * expect('foo').to.be.a('string'); - * expect({a: 1}).to.be.an('object'); - * expect(null).to.be.a('null'); - * expect(undefined).to.be.an('undefined'); - * expect(new Error).to.be.an('error'); - * expect(Promise.resolve()).to.be.a('promise'); - * expect(new Float32Array).to.be.a('float32array'); - * expect(Symbol()).to.be.a('symbol'); - * - * `.a` supports objects that have a custom type set via `Symbol.toStringTag`. - * - * var myObj = { - * [Symbol.toStringTag]: 'myCustomType' - * }; - * - * expect(myObj).to.be.a('myCustomType').but.not.an('object'); - * - * It's often best to use `.a` to check a target's type before making more - * assertions on the same target. That way, you avoid unexpected behavior from - * any assertion that does different things based on the target's type. - * - * expect([1, 2, 3]).to.be.an('array').that.includes(2); - * expect([]).to.be.an('array').that.is.empty; - * - * Add `.not` earlier in the chain to negate `.a`. However, it's often best to - * assert that the target is the expected type, rather than asserting that it - * isn't one of many unexpected types. - * - * expect('foo').to.be.a('string'); // Recommended - * expect('foo').to.not.be.an('array'); // Not recommended - * - * `.a` accepts an optional `msg` argument which is a custom error message to - * show when the assertion fails. The message can also be given as the second - * argument to `expect`. - * - * expect(1).to.be.a('string', 'nooo why fail??'); - * expect(1, 'nooo why fail??').to.be.a('string'); - * - * `.a` can also be used as a language chain to improve the readability of - * your assertions. - * - * expect({b: 2}).to.have.a.property('b'); - * - * The alias `.an` can be used interchangeably with `.a`. - * - * @name a - * @alias an - * @param {String} type - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function an (type, msg) { - if (msg) flag(this, 'message', msg); - type = type.toLowerCase(); - var obj = flag(this, 'object') - , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; - - this.assert( - type === _.type(obj).toLowerCase() - , 'expected #{this} to be ' + article + type - , 'expected #{this} not to be ' + article + type - ); - } - - Assertion.addChainableMethod('an', an); - Assertion.addChainableMethod('a', an); - - /** - * ### .include(val[, msg]) - * - * When the target is a string, `.include` asserts that the given string `val` - * is a substring of the target. - * - * expect('foobar').to.include('foo'); - * - * When the target is an array, `.include` asserts that the given `val` is a - * member of the target. - * - * expect([1, 2, 3]).to.include(2); - * - * When the target is an object, `.include` asserts that the given object - * `val`'s properties are a subset of the target's properties. - * - * expect({a: 1, b: 2, c: 3}).to.include({a: 1, b: 2}); - * - * When the target is a Set or WeakSet, `.include` asserts that the given `val` is a - * member of the target. SameValueZero equality algorithm is used. - * - * expect(new Set([1, 2])).to.include(2); - * - * When the target is a Map, `.include` asserts that the given `val` is one of - * the values of the target. SameValueZero equality algorithm is used. - * - * expect(new Map([['a', 1], ['b', 2]])).to.include(2); - * - * Because `.include` does different things based on the target's type, it's - * important to check the target's type before using `.include`. See the `.a` - * doc for info on testing a target's type. - * - * expect([1, 2, 3]).to.be.an('array').that.includes(2); - * - * By default, strict (`===`) equality is used to compare array members and - * object properties. Add `.deep` earlier in the chain to use deep equality - * instead (WeakSet targets are not supported). See the `deep-eql` project - * page for info on the deep equality algorithm: https://github.com/chaijs/deep-eql. - * - * // Target array deeply (but not strictly) includes `{a: 1}` - * expect([{a: 1}]).to.deep.include({a: 1}); - * expect([{a: 1}]).to.not.include({a: 1}); - * - * // Target object deeply (but not strictly) includes `x: {a: 1}` - * expect({x: {a: 1}}).to.deep.include({x: {a: 1}}); - * expect({x: {a: 1}}).to.not.include({x: {a: 1}}); - * - * By default, all of the target's properties are searched when working with - * objects. This includes properties that are inherited and/or non-enumerable. - * Add `.own` earlier in the chain to exclude the target's inherited - * properties from the search. - * - * Object.prototype.b = 2; - * - * expect({a: 1}).to.own.include({a: 1}); - * expect({a: 1}).to.include({b: 2}).but.not.own.include({b: 2}); - * - * Note that a target object is always only searched for `val`'s own - * enumerable properties. - * - * `.deep` and `.own` can be combined. - * - * expect({a: {b: 2}}).to.deep.own.include({a: {b: 2}}); - * - * Add `.nested` earlier in the chain to enable dot- and bracket-notation when - * referencing nested properties. - * - * expect({a: {b: ['x', 'y']}}).to.nested.include({'a.b[1]': 'y'}); - * - * If `.` or `[]` are part of an actual property name, they can be escaped by - * adding two backslashes before them. - * - * expect({'.a': {'[b]': 2}}).to.nested.include({'\\.a.\\[b\\]': 2}); - * - * `.deep` and `.nested` can be combined. - * - * expect({a: {b: [{c: 3}]}}).to.deep.nested.include({'a.b[0]': {c: 3}}); - * - * `.own` and `.nested` cannot be combined. - * - * Add `.not` earlier in the chain to negate `.include`. - * - * expect('foobar').to.not.include('taco'); - * expect([1, 2, 3]).to.not.include(4); - * - * However, it's dangerous to negate `.include` when the target is an object. - * The problem is that it creates uncertain expectations by asserting that the - * target object doesn't have all of `val`'s key/value pairs but may or may - * not have some of them. It's often best to identify the exact output that's - * expected, and then write an assertion that only accepts that exact output. - * - * When the target object isn't even expected to have `val`'s keys, it's - * often best to assert exactly that. - * - * expect({c: 3}).to.not.have.any.keys('a', 'b'); // Recommended - * expect({c: 3}).to.not.include({a: 1, b: 2}); // Not recommended - * - * When the target object is expected to have `val`'s keys, it's often best to - * assert that each of the properties has its expected value, rather than - * asserting that each property doesn't have one of many unexpected values. - * - * expect({a: 3, b: 4}).to.include({a: 3, b: 4}); // Recommended - * expect({a: 3, b: 4}).to.not.include({a: 1, b: 2}); // Not recommended - * - * `.include` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. - * - * expect([1, 2, 3]).to.include(4, 'nooo why fail??'); - * expect([1, 2, 3], 'nooo why fail??').to.include(4); - * - * `.include` can also be used as a language chain, causing all `.members` and - * `.keys` assertions that follow in the chain to require the target to be a - * superset of the expected set, rather than an identical set. Note that - * `.members` ignores duplicates in the subset when `.include` is added. - * - * // Target object's keys are a superset of ['a', 'b'] but not identical - * expect({a: 1, b: 2, c: 3}).to.include.all.keys('a', 'b'); - * expect({a: 1, b: 2, c: 3}).to.not.have.all.keys('a', 'b'); - * - * // Target array is a superset of [1, 2] but not identical - * expect([1, 2, 3]).to.include.members([1, 2]); - * expect([1, 2, 3]).to.not.have.members([1, 2]); - * - * // Duplicates in the subset are ignored - * expect([1, 2, 3]).to.include.members([1, 2, 2, 2]); - * - * Note that adding `.any` earlier in the chain causes the `.keys` assertion - * to ignore `.include`. - * - * // Both assertions are identical - * expect({a: 1}).to.include.any.keys('a', 'b'); - * expect({a: 1}).to.have.any.keys('a', 'b'); - * - * The aliases `.includes`, `.contain`, and `.contains` can be used - * interchangeably with `.include`. - * - * @name include - * @alias contain - * @alias includes - * @alias contains - * @param {Mixed} val - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function SameValueZero(a, b) { - return (_.isNaN(a) && _.isNaN(b)) || a === b; - } - - function includeChainingBehavior () { - flag(this, 'contains', true); - } - - function include (val, msg) { - if (msg) flag(this, 'message', msg); - - var obj = flag(this, 'object') - , objType = _.type(obj).toLowerCase() - , flagMsg = flag(this, 'message') - , negate = flag(this, 'negate') - , ssfi = flag(this, 'ssfi') - , isDeep = flag(this, 'deep') - , descriptor = isDeep ? 'deep ' : ''; - - flagMsg = flagMsg ? flagMsg + ': ' : ''; - - var included = false; - - switch (objType) { - case 'string': - included = obj.indexOf(val) !== -1; - break; - - case 'weakset': - if (isDeep) { - throw new AssertionError( - flagMsg + 'unable to use .deep.include with WeakSet', - undefined, - ssfi - ); - } - - included = obj.has(val); - break; - - case 'map': - var isEql = isDeep ? _.eql : SameValueZero; - obj.forEach(function (item) { - included = included || isEql(item, val); - }); - break; - - case 'set': - if (isDeep) { - obj.forEach(function (item) { - included = included || _.eql(item, val); - }); - } else { - included = obj.has(val); - } - break; - - case 'array': - if (isDeep) { - included = obj.some(function (item) { - return _.eql(item, val); - }) - } else { - included = obj.indexOf(val) !== -1; - } - break; - - default: - // This block is for asserting a subset of properties in an object. - // `_.expectTypes` isn't used here because `.include` should work with - // objects with a custom `@@toStringTag`. - if (val !== Object(val)) { - throw new AssertionError( - flagMsg + 'object tested must be an array, a map, an object,' - + ' a set, a string, or a weakset, but ' + objType + ' given', - undefined, - ssfi - ); - } - - var props = Object.keys(val) - , firstErr = null - , numErrs = 0; - - props.forEach(function (prop) { - var propAssertion = new Assertion(obj); - _.transferFlags(this, propAssertion, true); - flag(propAssertion, 'lockSsfi', true); - - if (!negate || props.length === 1) { - propAssertion.property(prop, val[prop]); - return; - } - - try { - propAssertion.property(prop, val[prop]); - } catch (err) { - if (!_.checkError.compatibleConstructor(err, AssertionError)) { - throw err; - } - if (firstErr === null) firstErr = err; - numErrs++; - } - }, this); - - // When validating .not.include with multiple properties, we only want - // to throw an assertion error if all of the properties are included, - // in which case we throw the first property assertion error that we - // encountered. - if (negate && props.length > 1 && numErrs === props.length) { - throw firstErr; - } - return; - } - - // Assert inclusion in collection or substring in a string. - this.assert( - included - , 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val) - , 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val)); - } - - Assertion.addChainableMethod('include', include, includeChainingBehavior); - Assertion.addChainableMethod('contain', include, includeChainingBehavior); - Assertion.addChainableMethod('contains', include, includeChainingBehavior); - Assertion.addChainableMethod('includes', include, includeChainingBehavior); - - /** - * ### .ok - * - * Asserts that the target is loosely (`==`) equal to `true`. However, it's - * often best to assert that the target is strictly (`===`) or deeply equal to - * its expected value. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.be.ok; // Not recommended - * - * expect(true).to.be.true; // Recommended - * expect(true).to.be.ok; // Not recommended - * - * Add `.not` earlier in the chain to negate `.ok`. - * - * expect(0).to.equal(0); // Recommended - * expect(0).to.not.be.ok; // Not recommended - * - * expect(false).to.be.false; // Recommended - * expect(false).to.not.be.ok; // Not recommended - * - * expect(null).to.be.null; // Recommended - * expect(null).to.not.be.ok; // Not recommended - * - * expect(undefined).to.be.undefined; // Recommended - * expect(undefined).to.not.be.ok; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect(false, 'nooo why fail??').to.be.ok; - * - * @name ok - * @namespace BDD - * @api public - */ - - Assertion.addProperty('ok', function () { - this.assert( - flag(this, 'object') - , 'expected #{this} to be truthy' - , 'expected #{this} to be falsy'); - }); - - /** - * ### .true - * - * Asserts that the target is strictly (`===`) equal to `true`. - * - * expect(true).to.be.true; - * - * Add `.not` earlier in the chain to negate `.true`. However, it's often best - * to assert that the target is equal to its expected value, rather than not - * equal to `true`. - * - * expect(false).to.be.false; // Recommended - * expect(false).to.not.be.true; // Not recommended - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.not.be.true; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect(false, 'nooo why fail??').to.be.true; - * - * @name true - * @namespace BDD - * @api public - */ - - Assertion.addProperty('true', function () { - this.assert( - true === flag(this, 'object') - , 'expected #{this} to be true' - , 'expected #{this} to be false' - , flag(this, 'negate') ? false : true - ); - }); - - /** - * ### .false - * - * Asserts that the target is strictly (`===`) equal to `false`. - * - * expect(false).to.be.false; - * - * Add `.not` earlier in the chain to negate `.false`. However, it's often - * best to assert that the target is equal to its expected value, rather than - * not equal to `false`. - * - * expect(true).to.be.true; // Recommended - * expect(true).to.not.be.false; // Not recommended - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.not.be.false; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect(true, 'nooo why fail??').to.be.false; - * - * @name false - * @namespace BDD - * @api public - */ - - Assertion.addProperty('false', function () { - this.assert( - false === flag(this, 'object') - , 'expected #{this} to be false' - , 'expected #{this} to be true' - , flag(this, 'negate') ? true : false - ); - }); - - /** - * ### .null - * - * Asserts that the target is strictly (`===`) equal to `null`. - * - * expect(null).to.be.null; - * - * Add `.not` earlier in the chain to negate `.null`. However, it's often best - * to assert that the target is equal to its expected value, rather than not - * equal to `null`. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.not.be.null; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect(42, 'nooo why fail??').to.be.null; - * - * @name null - * @namespace BDD - * @api public - */ - - Assertion.addProperty('null', function () { - this.assert( - null === flag(this, 'object') - , 'expected #{this} to be null' - , 'expected #{this} not to be null' - ); - }); - - /** - * ### .undefined - * - * Asserts that the target is strictly (`===`) equal to `undefined`. - * - * expect(undefined).to.be.undefined; - * - * Add `.not` earlier in the chain to negate `.undefined`. However, it's often - * best to assert that the target is equal to its expected value, rather than - * not equal to `undefined`. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.not.be.undefined; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect(42, 'nooo why fail??').to.be.undefined; - * - * @name undefined - * @namespace BDD - * @api public - */ - - Assertion.addProperty('undefined', function () { - this.assert( - undefined === flag(this, 'object') - , 'expected #{this} to be undefined' - , 'expected #{this} not to be undefined' - ); - }); - - /** - * ### .NaN - * - * Asserts that the target is exactly `NaN`. - * - * expect(NaN).to.be.NaN; - * - * Add `.not` earlier in the chain to negate `.NaN`. However, it's often best - * to assert that the target is equal to its expected value, rather than not - * equal to `NaN`. - * - * expect('foo').to.equal('foo'); // Recommended - * expect('foo').to.not.be.NaN; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect(42, 'nooo why fail??').to.be.NaN; - * - * @name NaN - * @namespace BDD - * @api public - */ - - Assertion.addProperty('NaN', function () { - this.assert( - _.isNaN(flag(this, 'object')) - , 'expected #{this} to be NaN' - , 'expected #{this} not to be NaN' - ); - }); - - /** - * ### .exist - * - * Asserts that the target is not strictly (`===`) equal to either `null` or - * `undefined`. However, it's often best to assert that the target is equal to - * its expected value. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.exist; // Not recommended - * - * expect(0).to.equal(0); // Recommended - * expect(0).to.exist; // Not recommended - * - * Add `.not` earlier in the chain to negate `.exist`. - * - * expect(null).to.be.null; // Recommended - * expect(null).to.not.exist; // Not recommended - * - * expect(undefined).to.be.undefined; // Recommended - * expect(undefined).to.not.exist; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect(null, 'nooo why fail??').to.exist; - * - * @name exist - * @namespace BDD - * @api public - */ - - Assertion.addProperty('exist', function () { - var val = flag(this, 'object'); - this.assert( - val !== null && val !== undefined - , 'expected #{this} to exist' - , 'expected #{this} to not exist' - ); - }); - - /** - * ### .empty - * - * When the target is a string or array, `.empty` asserts that the target's - * `length` property is strictly (`===`) equal to `0`. - * - * expect([]).to.be.empty; - * expect('').to.be.empty; - * - * When the target is a map or set, `.empty` asserts that the target's `size` - * property is strictly equal to `0`. - * - * expect(new Set()).to.be.empty; - * expect(new Map()).to.be.empty; - * - * When the target is a non-function object, `.empty` asserts that the target - * doesn't have any own enumerable properties. Properties with Symbol-based - * keys are excluded from the count. - * - * expect({}).to.be.empty; - * - * Because `.empty` does different things based on the target's type, it's - * important to check the target's type before using `.empty`. See the `.a` - * doc for info on testing a target's type. - * - * expect([]).to.be.an('array').that.is.empty; - * - * Add `.not` earlier in the chain to negate `.empty`. However, it's often - * best to assert that the target contains its expected number of values, - * rather than asserting that it's not empty. - * - * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended - * expect([1, 2, 3]).to.not.be.empty; // Not recommended - * - * expect(new Set([1, 2, 3])).to.have.property('size', 3); // Recommended - * expect(new Set([1, 2, 3])).to.not.be.empty; // Not recommended - * - * expect(Object.keys({a: 1})).to.have.lengthOf(1); // Recommended - * expect({a: 1}).to.not.be.empty; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect([1, 2, 3], 'nooo why fail??').to.be.empty; - * - * @name empty - * @namespace BDD - * @api public - */ - - Assertion.addProperty('empty', function () { - var val = flag(this, 'object') - , ssfi = flag(this, 'ssfi') - , flagMsg = flag(this, 'message') - , itemsCount; - - flagMsg = flagMsg ? flagMsg + ': ' : ''; - - switch (_.type(val).toLowerCase()) { - case 'array': - case 'string': - itemsCount = val.length; - break; - case 'map': - case 'set': - itemsCount = val.size; - break; - case 'weakmap': - case 'weakset': - throw new AssertionError( - flagMsg + '.empty was passed a weak collection', - undefined, - ssfi - ); - case 'function': - var msg = flagMsg + '.empty was passed a function ' + _.getName(val); - throw new AssertionError(msg.trim(), undefined, ssfi); - default: - if (val !== Object(val)) { - throw new AssertionError( - flagMsg + '.empty was passed non-string primitive ' + _.inspect(val), - undefined, - ssfi - ); - } - itemsCount = Object.keys(val).length; - } - - this.assert( - 0 === itemsCount - , 'expected #{this} to be empty' - , 'expected #{this} not to be empty' - ); - }); - - /** - * ### .arguments - * - * Asserts that the target is an `arguments` object. - * - * function test () { - * expect(arguments).to.be.arguments; - * } - * - * test(); - * - * Add `.not` earlier in the chain to negate `.arguments`. However, it's often - * best to assert which type the target is expected to be, rather than - * asserting that its not an `arguments` object. - * - * expect('foo').to.be.a('string'); // Recommended - * expect('foo').to.not.be.arguments; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect({}, 'nooo why fail??').to.be.arguments; - * - * The alias `.Arguments` can be used interchangeably with `.arguments`. - * - * @name arguments - * @alias Arguments - * @namespace BDD - * @api public - */ - - function checkArguments () { - var obj = flag(this, 'object') - , type = _.type(obj); - this.assert( - 'Arguments' === type - , 'expected #{this} to be arguments but got ' + type - , 'expected #{this} to not be arguments' - ); - } - - Assertion.addProperty('arguments', checkArguments); - Assertion.addProperty('Arguments', checkArguments); - - /** - * ### .equal(val[, msg]) - * - * Asserts that the target is strictly (`===`) equal to the given `val`. - * - * expect(1).to.equal(1); - * expect('foo').to.equal('foo'); - * - * Add `.deep` earlier in the chain to use deep equality instead. See the - * `deep-eql` project page for info on the deep equality algorithm: - * https://github.com/chaijs/deep-eql. - * - * // Target object deeply (but not strictly) equals `{a: 1}` - * expect({a: 1}).to.deep.equal({a: 1}); - * expect({a: 1}).to.not.equal({a: 1}); - * - * // Target array deeply (but not strictly) equals `[1, 2]` - * expect([1, 2]).to.deep.equal([1, 2]); - * expect([1, 2]).to.not.equal([1, 2]); - * - * Add `.not` earlier in the chain to negate `.equal`. However, it's often - * best to assert that the target is equal to its expected value, rather than - * not equal to one of countless unexpected values. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.not.equal(2); // Not recommended - * - * `.equal` accepts an optional `msg` argument which is a custom error message - * to show when the assertion fails. The message can also be given as the - * second argument to `expect`. - * - * expect(1).to.equal(2, 'nooo why fail??'); - * expect(1, 'nooo why fail??').to.equal(2); - * - * The aliases `.equals` and `eq` can be used interchangeably with `.equal`. - * - * @name equal - * @alias equals - * @alias eq - * @param {Mixed} val - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertEqual (val, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'deep')) { - return this.eql(val); - } else { - this.assert( - val === obj - , 'expected #{this} to equal #{exp}' - , 'expected #{this} to not equal #{exp}' - , val - , this._obj - , true - ); - } - } - - Assertion.addMethod('equal', assertEqual); - Assertion.addMethod('equals', assertEqual); - Assertion.addMethod('eq', assertEqual); - - /** - * ### .eql(obj[, msg]) - * - * Asserts that the target is deeply equal to the given `obj`. See the - * `deep-eql` project page for info on the deep equality algorithm: - * https://github.com/chaijs/deep-eql. - * - * // Target object is deeply (but not strictly) equal to {a: 1} - * expect({a: 1}).to.eql({a: 1}).but.not.equal({a: 1}); - * - * // Target array is deeply (but not strictly) equal to [1, 2] - * expect([1, 2]).to.eql([1, 2]).but.not.equal([1, 2]); - * - * Add `.not` earlier in the chain to negate `.eql`. However, it's often best - * to assert that the target is deeply equal to its expected value, rather - * than not deeply equal to one of countless unexpected values. - * - * expect({a: 1}).to.eql({a: 1}); // Recommended - * expect({a: 1}).to.not.eql({b: 2}); // Not recommended - * - * `.eql` accepts an optional `msg` argument which is a custom error message - * to show when the assertion fails. The message can also be given as the - * second argument to `expect`. - * - * expect({a: 1}).to.eql({b: 2}, 'nooo why fail??'); - * expect({a: 1}, 'nooo why fail??').to.eql({b: 2}); - * - * The alias `.eqls` can be used interchangeably with `.eql`. - * - * The `.deep.equal` assertion is almost identical to `.eql` but with one - * difference: `.deep.equal` causes deep equality comparisons to also be used - * for any other assertions that follow in the chain. - * - * @name eql - * @alias eqls - * @param {Mixed} obj - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertEql(obj, msg) { - if (msg) flag(this, 'message', msg); - this.assert( - _.eql(obj, flag(this, 'object')) - , 'expected #{this} to deeply equal #{exp}' - , 'expected #{this} to not deeply equal #{exp}' - , obj - , this._obj - , true - ); - } - - Assertion.addMethod('eql', assertEql); - Assertion.addMethod('eqls', assertEql); - - /** - * ### .above(n[, msg]) - * - * Asserts that the target is a number or a date greater than the given number or date `n` respectively. - * However, it's often best to assert that the target is equal to its expected - * value. - * - * expect(2).to.equal(2); // Recommended - * expect(2).to.be.above(1); // Not recommended - * - * Add `.lengthOf` earlier in the chain to assert that the value of the - * target's `length` property is greater than the given number `n`. - * - * expect('foo').to.have.lengthOf(3); // Recommended - * expect('foo').to.have.lengthOf.above(2); // Not recommended - * - * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended - * expect([1, 2, 3]).to.have.lengthOf.above(2); // Not recommended - * - * Add `.not` earlier in the chain to negate `.above`. - * - * expect(2).to.equal(2); // Recommended - * expect(1).to.not.be.above(2); // Not recommended - * - * `.above` accepts an optional `msg` argument which is a custom error message - * to show when the assertion fails. The message can also be given as the - * second argument to `expect`. - * - * expect(1).to.be.above(2, 'nooo why fail??'); - * expect(1, 'nooo why fail??').to.be.above(2); - * - * The aliases `.gt` and `.greaterThan` can be used interchangeably with - * `.above`. - * - * @name above - * @alias gt - * @alias greaterThan - * @param {Number} n - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertAbove (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , doLength = flag(this, 'doLength') - , flagMsg = flag(this, 'message') - , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') - , ssfi = flag(this, 'ssfi') - , objType = _.type(obj).toLowerCase() - , nType = _.type(n).toLowerCase() - , shouldThrow = true; - - if (doLength) { - new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); - } - - if (!doLength && (objType === 'date' && nType !== 'date')) { - errorMessage = msgPrefix + 'the argument to above must be a date'; - } else if (nType !== 'number' && (doLength || objType === 'number')) { - errorMessage = msgPrefix + 'the argument to above must be a number'; - } else if (!doLength && (objType !== 'date' && objType !== 'number')) { - var printObj = (objType === 'string') ? "'" + obj + "'" : obj; - errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; - } else { - shouldThrow = false; - } - - if (shouldThrow) { - throw new AssertionError(errorMessage, undefined, ssfi); - } - - if (doLength) { - var len = obj.length; - this.assert( - len > n - , 'expected #{this} to have a length above #{exp} but got #{act}' - , 'expected #{this} to not have a length above #{exp}' - , n - , len - ); - } else { - this.assert( - obj > n - , 'expected #{this} to be above #{exp}' - , 'expected #{this} to be at most #{exp}' - , n - ); - } - } - - Assertion.addMethod('above', assertAbove); - Assertion.addMethod('gt', assertAbove); - Assertion.addMethod('greaterThan', assertAbove); - - /** - * ### .least(n[, msg]) - * - * Asserts that the target is a number or a date greater than or equal to the given - * number or date `n` respectively. However, it's often best to assert that the target is equal to - * its expected value. - * - * expect(2).to.equal(2); // Recommended - * expect(2).to.be.at.least(1); // Not recommended - * expect(2).to.be.at.least(2); // Not recommended - * - * Add `.lengthOf` earlier in the chain to assert that the value of the - * target's `length` property is greater than or equal to the given number - * `n`. - * - * expect('foo').to.have.lengthOf(3); // Recommended - * expect('foo').to.have.lengthOf.at.least(2); // Not recommended - * - * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended - * expect([1, 2, 3]).to.have.lengthOf.at.least(2); // Not recommended - * - * Add `.not` earlier in the chain to negate `.least`. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.not.be.at.least(2); // Not recommended - * - * `.least` accepts an optional `msg` argument which is a custom error message - * to show when the assertion fails. The message can also be given as the - * second argument to `expect`. - * - * expect(1).to.be.at.least(2, 'nooo why fail??'); - * expect(1, 'nooo why fail??').to.be.at.least(2); - * - * The alias `.gte` can be used interchangeably with `.least`. - * - * @name least - * @alias gte - * @param {Number} n - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertLeast (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , doLength = flag(this, 'doLength') - , flagMsg = flag(this, 'message') - , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') - , ssfi = flag(this, 'ssfi') - , objType = _.type(obj).toLowerCase() - , nType = _.type(n).toLowerCase() - , shouldThrow = true; - - if (doLength) { - new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); - } - - if (!doLength && (objType === 'date' && nType !== 'date')) { - errorMessage = msgPrefix + 'the argument to least must be a date'; - } else if (nType !== 'number' && (doLength || objType === 'number')) { - errorMessage = msgPrefix + 'the argument to least must be a number'; - } else if (!doLength && (objType !== 'date' && objType !== 'number')) { - var printObj = (objType === 'string') ? "'" + obj + "'" : obj; - errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; - } else { - shouldThrow = false; - } - - if (shouldThrow) { - throw new AssertionError(errorMessage, undefined, ssfi); - } - - if (doLength) { - var len = obj.length; - this.assert( - len >= n - , 'expected #{this} to have a length at least #{exp} but got #{act}' - , 'expected #{this} to have a length below #{exp}' - , n - , len - ); - } else { - this.assert( - obj >= n - , 'expected #{this} to be at least #{exp}' - , 'expected #{this} to be below #{exp}' - , n - ); - } - } - - Assertion.addMethod('least', assertLeast); - Assertion.addMethod('gte', assertLeast); - - /** - * ### .below(n[, msg]) - * - * Asserts that the target is a number or a date less than the given number or date `n` respectively. - * However, it's often best to assert that the target is equal to its expected - * value. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.be.below(2); // Not recommended - * - * Add `.lengthOf` earlier in the chain to assert that the value of the - * target's `length` property is less than the given number `n`. - * - * expect('foo').to.have.lengthOf(3); // Recommended - * expect('foo').to.have.lengthOf.below(4); // Not recommended - * - * expect([1, 2, 3]).to.have.length(3); // Recommended - * expect([1, 2, 3]).to.have.lengthOf.below(4); // Not recommended - * - * Add `.not` earlier in the chain to negate `.below`. - * - * expect(2).to.equal(2); // Recommended - * expect(2).to.not.be.below(1); // Not recommended - * - * `.below` accepts an optional `msg` argument which is a custom error message - * to show when the assertion fails. The message can also be given as the - * second argument to `expect`. - * - * expect(2).to.be.below(1, 'nooo why fail??'); - * expect(2, 'nooo why fail??').to.be.below(1); - * - * The aliases `.lt` and `.lessThan` can be used interchangeably with - * `.below`. - * - * @name below - * @alias lt - * @alias lessThan - * @param {Number} n - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertBelow (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , doLength = flag(this, 'doLength') - , flagMsg = flag(this, 'message') - , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') - , ssfi = flag(this, 'ssfi') - , objType = _.type(obj).toLowerCase() - , nType = _.type(n).toLowerCase() - , shouldThrow = true; - - if (doLength) { - new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); - } - - if (!doLength && (objType === 'date' && nType !== 'date')) { - errorMessage = msgPrefix + 'the argument to below must be a date'; - } else if (nType !== 'number' && (doLength || objType === 'number')) { - errorMessage = msgPrefix + 'the argument to below must be a number'; - } else if (!doLength && (objType !== 'date' && objType !== 'number')) { - var printObj = (objType === 'string') ? "'" + obj + "'" : obj; - errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; - } else { - shouldThrow = false; - } - - if (shouldThrow) { - throw new AssertionError(errorMessage, undefined, ssfi); - } - - if (doLength) { - var len = obj.length; - this.assert( - len < n - , 'expected #{this} to have a length below #{exp} but got #{act}' - , 'expected #{this} to not have a length below #{exp}' - , n - , len - ); - } else { - this.assert( - obj < n - , 'expected #{this} to be below #{exp}' - , 'expected #{this} to be at least #{exp}' - , n - ); - } - } - - Assertion.addMethod('below', assertBelow); - Assertion.addMethod('lt', assertBelow); - Assertion.addMethod('lessThan', assertBelow); - - /** - * ### .most(n[, msg]) - * - * Asserts that the target is a number or a date less than or equal to the given number - * or date `n` respectively. However, it's often best to assert that the target is equal to its - * expected value. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.be.at.most(2); // Not recommended - * expect(1).to.be.at.most(1); // Not recommended - * - * Add `.lengthOf` earlier in the chain to assert that the value of the - * target's `length` property is less than or equal to the given number `n`. - * - * expect('foo').to.have.lengthOf(3); // Recommended - * expect('foo').to.have.lengthOf.at.most(4); // Not recommended - * - * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended - * expect([1, 2, 3]).to.have.lengthOf.at.most(4); // Not recommended - * - * Add `.not` earlier in the chain to negate `.most`. - * - * expect(2).to.equal(2); // Recommended - * expect(2).to.not.be.at.most(1); // Not recommended - * - * `.most` accepts an optional `msg` argument which is a custom error message - * to show when the assertion fails. The message can also be given as the - * second argument to `expect`. - * - * expect(2).to.be.at.most(1, 'nooo why fail??'); - * expect(2, 'nooo why fail??').to.be.at.most(1); - * - * The alias `.lte` can be used interchangeably with `.most`. - * - * @name most - * @alias lte - * @param {Number} n - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertMost (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , doLength = flag(this, 'doLength') - , flagMsg = flag(this, 'message') - , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') - , ssfi = flag(this, 'ssfi') - , objType = _.type(obj).toLowerCase() - , nType = _.type(n).toLowerCase() - , shouldThrow = true; - - if (doLength) { - new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); - } - - if (!doLength && (objType === 'date' && nType !== 'date')) { - errorMessage = msgPrefix + 'the argument to most must be a date'; - } else if (nType !== 'number' && (doLength || objType === 'number')) { - errorMessage = msgPrefix + 'the argument to most must be a number'; - } else if (!doLength && (objType !== 'date' && objType !== 'number')) { - var printObj = (objType === 'string') ? "'" + obj + "'" : obj; - errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; - } else { - shouldThrow = false; - } - - if (shouldThrow) { - throw new AssertionError(errorMessage, undefined, ssfi); - } - - if (doLength) { - var len = obj.length; - this.assert( - len <= n - , 'expected #{this} to have a length at most #{exp} but got #{act}' - , 'expected #{this} to have a length above #{exp}' - , n - , len - ); - } else { - this.assert( - obj <= n - , 'expected #{this} to be at most #{exp}' - , 'expected #{this} to be above #{exp}' - , n - ); - } - } - - Assertion.addMethod('most', assertMost); - Assertion.addMethod('lte', assertMost); - - /** - * ### .within(start, finish[, msg]) - * - * Asserts that the target is a number or a date greater than or equal to the given - * number or date `start`, and less than or equal to the given number or date `finish` respectively. - * However, it's often best to assert that the target is equal to its expected - * value. - * - * expect(2).to.equal(2); // Recommended - * expect(2).to.be.within(1, 3); // Not recommended - * expect(2).to.be.within(2, 3); // Not recommended - * expect(2).to.be.within(1, 2); // Not recommended - * - * Add `.lengthOf` earlier in the chain to assert that the value of the - * target's `length` property is greater than or equal to the given number - * `start`, and less than or equal to the given number `finish`. - * - * expect('foo').to.have.lengthOf(3); // Recommended - * expect('foo').to.have.lengthOf.within(2, 4); // Not recommended - * - * expect([1, 2, 3]).to.have.lengthOf(3); // Recommended - * expect([1, 2, 3]).to.have.lengthOf.within(2, 4); // Not recommended - * - * Add `.not` earlier in the chain to negate `.within`. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.not.be.within(2, 4); // Not recommended - * - * `.within` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. - * - * expect(4).to.be.within(1, 3, 'nooo why fail??'); - * expect(4, 'nooo why fail??').to.be.within(1, 3); - * - * @name within - * @param {Number} start lower bound inclusive - * @param {Number} finish upper bound inclusive - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - Assertion.addMethod('within', function (start, finish, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , doLength = flag(this, 'doLength') - , flagMsg = flag(this, 'message') - , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '') - , ssfi = flag(this, 'ssfi') - , objType = _.type(obj).toLowerCase() - , startType = _.type(start).toLowerCase() - , finishType = _.type(finish).toLowerCase() - , shouldThrow = true - , range = (startType === 'date' && finishType === 'date') - ? start.toUTCString() + '..' + finish.toUTCString() - : start + '..' + finish; - - if (doLength) { - new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); - } - - if (!doLength && (objType === 'date' && (startType !== 'date' || finishType !== 'date'))) { - errorMessage = msgPrefix + 'the arguments to within must be dates'; - } else if ((startType !== 'number' || finishType !== 'number') && (doLength || objType === 'number')) { - errorMessage = msgPrefix + 'the arguments to within must be numbers'; - } else if (!doLength && (objType !== 'date' && objType !== 'number')) { - var printObj = (objType === 'string') ? "'" + obj + "'" : obj; - errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date'; - } else { - shouldThrow = false; - } - - if (shouldThrow) { - throw new AssertionError(errorMessage, undefined, ssfi); - } - - if (doLength) { - var len = obj.length; - this.assert( - len >= start && len <= finish - , 'expected #{this} to have a length within ' + range - , 'expected #{this} to not have a length within ' + range - ); - } else { - this.assert( - obj >= start && obj <= finish - , 'expected #{this} to be within ' + range - , 'expected #{this} to not be within ' + range - ); - } - }); - - /** - * ### .instanceof(constructor[, msg]) - * - * Asserts that the target is an instance of the given `constructor`. - * - * function Cat () { } - * - * expect(new Cat()).to.be.an.instanceof(Cat); - * expect([1, 2]).to.be.an.instanceof(Array); - * - * Add `.not` earlier in the chain to negate `.instanceof`. - * - * expect({a: 1}).to.not.be.an.instanceof(Array); - * - * `.instanceof` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. - * - * expect(1).to.be.an.instanceof(Array, 'nooo why fail??'); - * expect(1, 'nooo why fail??').to.be.an.instanceof(Array); - * - * Due to limitations in ES5, `.instanceof` may not always work as expected - * when using a transpiler such as Babel or TypeScript. In particular, it may - * produce unexpected results when subclassing built-in object such as - * `Array`, `Error`, and `Map`. See your transpiler's docs for details: - * - * - ([Babel](https://babeljs.io/docs/usage/caveats/#classes)) - * - ([TypeScript](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work)) - * - * The alias `.instanceOf` can be used interchangeably with `.instanceof`. - * - * @name instanceof - * @param {Constructor} constructor - * @param {String} msg _optional_ - * @alias instanceOf - * @namespace BDD - * @api public - */ - - function assertInstanceOf (constructor, msg) { - if (msg) flag(this, 'message', msg); - - var target = flag(this, 'object') - var ssfi = flag(this, 'ssfi'); - var flagMsg = flag(this, 'message'); - - try { - var isInstanceOf = target instanceof constructor; - } catch (err) { - if (err instanceof TypeError) { - flagMsg = flagMsg ? flagMsg + ': ' : ''; - throw new AssertionError( - flagMsg + 'The instanceof assertion needs a constructor but ' - + _.type(constructor) + ' was given.', - undefined, - ssfi - ); - } - throw err; - } - - var name = _.getName(constructor); - if (name === null) { - name = 'an unnamed constructor'; - } - - this.assert( - isInstanceOf - , 'expected #{this} to be an instance of ' + name - , 'expected #{this} to not be an instance of ' + name - ); - }; - - Assertion.addMethod('instanceof', assertInstanceOf); - Assertion.addMethod('instanceOf', assertInstanceOf); - - /** - * ### .property(name[, val[, msg]]) - * - * Asserts that the target has a property with the given key `name`. - * - * expect({a: 1}).to.have.property('a'); - * - * When `val` is provided, `.property` also asserts that the property's value - * is equal to the given `val`. - * - * expect({a: 1}).to.have.property('a', 1); - * - * By default, strict (`===`) equality is used. Add `.deep` earlier in the - * chain to use deep equality instead. See the `deep-eql` project page for - * info on the deep equality algorithm: https://github.com/chaijs/deep-eql. - * - * // Target object deeply (but not strictly) has property `x: {a: 1}` - * expect({x: {a: 1}}).to.have.deep.property('x', {a: 1}); - * expect({x: {a: 1}}).to.not.have.property('x', {a: 1}); - * - * The target's enumerable and non-enumerable properties are always included - * in the search. By default, both own and inherited properties are included. - * Add `.own` earlier in the chain to exclude inherited properties from the - * search. - * - * Object.prototype.b = 2; - * - * expect({a: 1}).to.have.own.property('a'); - * expect({a: 1}).to.have.own.property('a', 1); - * expect({a: 1}).to.have.property('b').but.not.own.property('b'); - * - * `.deep` and `.own` can be combined. - * - * expect({x: {a: 1}}).to.have.deep.own.property('x', {a: 1}); - * - * Add `.nested` earlier in the chain to enable dot- and bracket-notation when - * referencing nested properties. - * - * expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]'); - * expect({a: {b: ['x', 'y']}}).to.have.nested.property('a.b[1]', 'y'); - * - * If `.` or `[]` are part of an actual property name, they can be escaped by - * adding two backslashes before them. - * - * expect({'.a': {'[b]': 'x'}}).to.have.nested.property('\\.a.\\[b\\]'); - * - * `.deep` and `.nested` can be combined. - * - * expect({a: {b: [{c: 3}]}}) - * .to.have.deep.nested.property('a.b[0]', {c: 3}); - * - * `.own` and `.nested` cannot be combined. - * - * Add `.not` earlier in the chain to negate `.property`. - * - * expect({a: 1}).to.not.have.property('b'); - * - * However, it's dangerous to negate `.property` when providing `val`. The - * problem is that it creates uncertain expectations by asserting that the - * target either doesn't have a property with the given key `name`, or that it - * does have a property with the given key `name` but its value isn't equal to - * the given `val`. It's often best to identify the exact output that's - * expected, and then write an assertion that only accepts that exact output. - * - * When the target isn't expected to have a property with the given key - * `name`, it's often best to assert exactly that. - * - * expect({b: 2}).to.not.have.property('a'); // Recommended - * expect({b: 2}).to.not.have.property('a', 1); // Not recommended - * - * When the target is expected to have a property with the given key `name`, - * it's often best to assert that the property has its expected value, rather - * than asserting that it doesn't have one of many unexpected values. - * - * expect({a: 3}).to.have.property('a', 3); // Recommended - * expect({a: 3}).to.not.have.property('a', 1); // Not recommended - * - * `.property` changes the target of any assertions that follow in the chain - * to be the value of the property from the original target object. - * - * expect({a: 1}).to.have.property('a').that.is.a('number'); - * - * `.property` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. When not providing `val`, only use the - * second form. - * - * // Recommended - * expect({a: 1}).to.have.property('a', 2, 'nooo why fail??'); - * expect({a: 1}, 'nooo why fail??').to.have.property('a', 2); - * expect({a: 1}, 'nooo why fail??').to.have.property('b'); - * - * // Not recommended - * expect({a: 1}).to.have.property('b', undefined, 'nooo why fail??'); - * - * The above assertion isn't the same thing as not providing `val`. Instead, - * it's asserting that the target object has a `b` property that's equal to - * `undefined`. - * - * The assertions `.ownProperty` and `.haveOwnProperty` can be used - * interchangeably with `.own.property`. - * - * @name property - * @param {String} name - * @param {Mixed} val (optional) - * @param {String} msg _optional_ - * @returns value of property for chaining - * @namespace BDD - * @api public - */ - - function assertProperty (name, val, msg) { - if (msg) flag(this, 'message', msg); - - var isNested = flag(this, 'nested') - , isOwn = flag(this, 'own') - , flagMsg = flag(this, 'message') - , obj = flag(this, 'object') - , ssfi = flag(this, 'ssfi'); - - if (isNested && isOwn) { - flagMsg = flagMsg ? flagMsg + ': ' : ''; - throw new AssertionError( - flagMsg + 'The "nested" and "own" flags cannot be combined.', - undefined, - ssfi - ); - } - - if (obj === null || obj === undefined) { - flagMsg = flagMsg ? flagMsg + ': ' : ''; - throw new AssertionError( - flagMsg + 'Target cannot be null or undefined.', - undefined, - ssfi - ); - } - - var isDeep = flag(this, 'deep') - , negate = flag(this, 'negate') - , pathInfo = isNested ? _.getPathInfo(obj, name) : null - , value = isNested ? pathInfo.value : obj[name]; - - var descriptor = ''; - if (isDeep) descriptor += 'deep '; - if (isOwn) descriptor += 'own '; - if (isNested) descriptor += 'nested '; - descriptor += 'property '; - - var hasProperty; - if (isOwn) hasProperty = Object.prototype.hasOwnProperty.call(obj, name); - else if (isNested) hasProperty = pathInfo.exists; - else hasProperty = _.hasProperty(obj, name); - - // When performing a negated assertion for both name and val, merely having - // a property with the given name isn't enough to cause the assertion to - // fail. It must both have a property with the given name, and the value of - // that property must equal the given val. Therefore, skip this assertion in - // favor of the next. - if (!negate || arguments.length === 1) { - this.assert( - hasProperty - , 'expected #{this} to have ' + descriptor + _.inspect(name) - , 'expected #{this} to not have ' + descriptor + _.inspect(name)); - } - - if (arguments.length > 1) { - this.assert( - hasProperty && (isDeep ? _.eql(val, value) : val === value) - , 'expected #{this} to have ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' - , 'expected #{this} to not have ' + descriptor + _.inspect(name) + ' of #{act}' - , val - , value - ); - } - - flag(this, 'object', value); - } - - Assertion.addMethod('property', assertProperty); - - function assertOwnProperty (name, value, msg) { - flag(this, 'own', true); - assertProperty.apply(this, arguments); - } - - Assertion.addMethod('ownProperty', assertOwnProperty); - Assertion.addMethod('haveOwnProperty', assertOwnProperty); - - /** - * ### .ownPropertyDescriptor(name[, descriptor[, msg]]) - * - * Asserts that the target has its own property descriptor with the given key - * `name`. Enumerable and non-enumerable properties are included in the - * search. - * - * expect({a: 1}).to.have.ownPropertyDescriptor('a'); - * - * When `descriptor` is provided, `.ownPropertyDescriptor` also asserts that - * the property's descriptor is deeply equal to the given `descriptor`. See - * the `deep-eql` project page for info on the deep equality algorithm: - * https://github.com/chaijs/deep-eql. - * - * expect({a: 1}).to.have.ownPropertyDescriptor('a', { - * configurable: true, - * enumerable: true, - * writable: true, - * value: 1, - * }); - * - * Add `.not` earlier in the chain to negate `.ownPropertyDescriptor`. - * - * expect({a: 1}).to.not.have.ownPropertyDescriptor('b'); - * - * However, it's dangerous to negate `.ownPropertyDescriptor` when providing - * a `descriptor`. The problem is that it creates uncertain expectations by - * asserting that the target either doesn't have a property descriptor with - * the given key `name`, or that it does have a property descriptor with the - * given key `name` but its not deeply equal to the given `descriptor`. It's - * often best to identify the exact output that's expected, and then write an - * assertion that only accepts that exact output. - * - * When the target isn't expected to have a property descriptor with the given - * key `name`, it's often best to assert exactly that. - * - * // Recommended - * expect({b: 2}).to.not.have.ownPropertyDescriptor('a'); - * - * // Not recommended - * expect({b: 2}).to.not.have.ownPropertyDescriptor('a', { - * configurable: true, - * enumerable: true, - * writable: true, - * value: 1, - * }); - * - * When the target is expected to have a property descriptor with the given - * key `name`, it's often best to assert that the property has its expected - * descriptor, rather than asserting that it doesn't have one of many - * unexpected descriptors. - * - * // Recommended - * expect({a: 3}).to.have.ownPropertyDescriptor('a', { - * configurable: true, - * enumerable: true, - * writable: true, - * value: 3, - * }); - * - * // Not recommended - * expect({a: 3}).to.not.have.ownPropertyDescriptor('a', { - * configurable: true, - * enumerable: true, - * writable: true, - * value: 1, - * }); - * - * `.ownPropertyDescriptor` changes the target of any assertions that follow - * in the chain to be the value of the property descriptor from the original - * target object. - * - * expect({a: 1}).to.have.ownPropertyDescriptor('a') - * .that.has.property('enumerable', true); - * - * `.ownPropertyDescriptor` accepts an optional `msg` argument which is a - * custom error message to show when the assertion fails. The message can also - * be given as the second argument to `expect`. When not providing - * `descriptor`, only use the second form. - * - * // Recommended - * expect({a: 1}).to.have.ownPropertyDescriptor('a', { - * configurable: true, - * enumerable: true, - * writable: true, - * value: 2, - * }, 'nooo why fail??'); - * - * // Recommended - * expect({a: 1}, 'nooo why fail??').to.have.ownPropertyDescriptor('a', { - * configurable: true, - * enumerable: true, - * writable: true, - * value: 2, - * }); - * - * // Recommended - * expect({a: 1}, 'nooo why fail??').to.have.ownPropertyDescriptor('b'); - * - * // Not recommended - * expect({a: 1}) - * .to.have.ownPropertyDescriptor('b', undefined, 'nooo why fail??'); - * - * The above assertion isn't the same thing as not providing `descriptor`. - * Instead, it's asserting that the target object has a `b` property - * descriptor that's deeply equal to `undefined`. - * - * The alias `.haveOwnPropertyDescriptor` can be used interchangeably with - * `.ownPropertyDescriptor`. - * - * @name ownPropertyDescriptor - * @alias haveOwnPropertyDescriptor - * @param {String} name - * @param {Object} descriptor _optional_ - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertOwnPropertyDescriptor (name, descriptor, msg) { - if (typeof descriptor === 'string') { - msg = descriptor; - descriptor = null; - } - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name); - if (actualDescriptor && descriptor) { - this.assert( - _.eql(descriptor, actualDescriptor) - , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor) - , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor) - , descriptor - , actualDescriptor - , true - ); - } else { - this.assert( - actualDescriptor - , 'expected #{this} to have an own property descriptor for ' + _.inspect(name) - , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name) - ); - } - flag(this, 'object', actualDescriptor); - } - - Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor); - Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor); - - /** - * ### .lengthOf(n[, msg]) - * - * Asserts that the target's `length` property is equal to the given number - * `n`. - * - * expect([1, 2, 3]).to.have.lengthOf(3); - * expect('foo').to.have.lengthOf(3); - * - * Add `.not` earlier in the chain to negate `.lengthOf`. However, it's often - * best to assert that the target's `length` property is equal to its expected - * value, rather than not equal to one of many unexpected values. - * - * expect('foo').to.have.lengthOf(3); // Recommended - * expect('foo').to.not.have.lengthOf(4); // Not recommended - * - * `.lengthOf` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. - * - * expect([1, 2, 3]).to.have.lengthOf(2, 'nooo why fail??'); - * expect([1, 2, 3], 'nooo why fail??').to.have.lengthOf(2); - * - * `.lengthOf` can also be used as a language chain, causing all `.above`, - * `.below`, `.least`, `.most`, and `.within` assertions that follow in the - * chain to use the target's `length` property as the target. However, it's - * often best to assert that the target's `length` property is equal to its - * expected length, rather than asserting that its `length` property falls - * within some range of values. - * - * // Recommended - * expect([1, 2, 3]).to.have.lengthOf(3); - * - * // Not recommended - * expect([1, 2, 3]).to.have.lengthOf.above(2); - * expect([1, 2, 3]).to.have.lengthOf.below(4); - * expect([1, 2, 3]).to.have.lengthOf.at.least(3); - * expect([1, 2, 3]).to.have.lengthOf.at.most(3); - * expect([1, 2, 3]).to.have.lengthOf.within(2,4); - * - * Due to a compatibility issue, the alias `.length` can't be chained directly - * off of an uninvoked method such as `.a`. Therefore, `.length` can't be used - * interchangeably with `.lengthOf` in every situation. It's recommended to - * always use `.lengthOf` instead of `.length`. - * - * expect([1, 2, 3]).to.have.a.length(3); // incompatible; throws error - * expect([1, 2, 3]).to.have.a.lengthOf(3); // passes as expected - * - * @name lengthOf - * @alias length - * @param {Number} n - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertLengthChain () { - flag(this, 'doLength', true); - } - - function assertLength (n, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , flagMsg = flag(this, 'message') - , ssfi = flag(this, 'ssfi'); - new Assertion(obj, flagMsg, ssfi, true).to.have.property('length'); - var len = obj.length; - - this.assert( - len == n - , 'expected #{this} to have a length of #{exp} but got #{act}' - , 'expected #{this} to not have a length of #{act}' - , n - , len - ); - } - - Assertion.addChainableMethod('length', assertLength, assertLengthChain); - Assertion.addChainableMethod('lengthOf', assertLength, assertLengthChain); - - /** - * ### .match(re[, msg]) - * - * Asserts that the target matches the given regular expression `re`. - * - * expect('foobar').to.match(/^foo/); - * - * Add `.not` earlier in the chain to negate `.match`. - * - * expect('foobar').to.not.match(/taco/); - * - * `.match` accepts an optional `msg` argument which is a custom error message - * to show when the assertion fails. The message can also be given as the - * second argument to `expect`. - * - * expect('foobar').to.match(/taco/, 'nooo why fail??'); - * expect('foobar', 'nooo why fail??').to.match(/taco/); - * - * The alias `.matches` can be used interchangeably with `.match`. - * - * @name match - * @alias matches - * @param {RegExp} re - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - function assertMatch(re, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - this.assert( - re.exec(obj) - , 'expected #{this} to match ' + re - , 'expected #{this} not to match ' + re - ); - } - - Assertion.addMethod('match', assertMatch); - Assertion.addMethod('matches', assertMatch); - - /** - * ### .string(str[, msg]) - * - * Asserts that the target string contains the given substring `str`. - * - * expect('foobar').to.have.string('bar'); - * - * Add `.not` earlier in the chain to negate `.string`. - * - * expect('foobar').to.not.have.string('taco'); - * - * `.string` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. - * - * expect('foobar').to.have.string(/taco/, 'nooo why fail??'); - * expect('foobar', 'nooo why fail??').to.have.string(/taco/); - * - * @name string - * @param {String} str - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - Assertion.addMethod('string', function (str, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , flagMsg = flag(this, 'message') - , ssfi = flag(this, 'ssfi'); - new Assertion(obj, flagMsg, ssfi, true).is.a('string'); - - this.assert( - ~obj.indexOf(str) - , 'expected #{this} to contain ' + _.inspect(str) - , 'expected #{this} to not contain ' + _.inspect(str) - ); - }); - - /** - * ### .keys(key1[, key2[, ...]]) - * - * Asserts that the target object, array, map, or set has the given keys. Only - * the target's own inherited properties are included in the search. - * - * When the target is an object or array, keys can be provided as one or more - * string arguments, a single array argument, or a single object argument. In - * the latter case, only the keys in the given object matter; the values are - * ignored. - * - * expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); - * expect(['x', 'y']).to.have.all.keys(0, 1); - * - * expect({a: 1, b: 2}).to.have.all.keys(['a', 'b']); - * expect(['x', 'y']).to.have.all.keys([0, 1]); - * - * expect({a: 1, b: 2}).to.have.all.keys({a: 4, b: 5}); // ignore 4 and 5 - * expect(['x', 'y']).to.have.all.keys({0: 4, 1: 5}); // ignore 4 and 5 - * - * When the target is a map or set, each key must be provided as a separate - * argument. - * - * expect(new Map([['a', 1], ['b', 2]])).to.have.all.keys('a', 'b'); - * expect(new Set(['a', 'b'])).to.have.all.keys('a', 'b'); - * - * Because `.keys` does different things based on the target's type, it's - * important to check the target's type before using `.keys`. See the `.a` doc - * for info on testing a target's type. - * - * expect({a: 1, b: 2}).to.be.an('object').that.has.all.keys('a', 'b'); - * - * By default, strict (`===`) equality is used to compare keys of maps and - * sets. Add `.deep` earlier in the chain to use deep equality instead. See - * the `deep-eql` project page for info on the deep equality algorithm: - * https://github.com/chaijs/deep-eql. - * - * // Target set deeply (but not strictly) has key `{a: 1}` - * expect(new Set([{a: 1}])).to.have.all.deep.keys([{a: 1}]); - * expect(new Set([{a: 1}])).to.not.have.all.keys([{a: 1}]); - * - * By default, the target must have all of the given keys and no more. Add - * `.any` earlier in the chain to only require that the target have at least - * one of the given keys. Also, add `.not` earlier in the chain to negate - * `.keys`. It's often best to add `.any` when negating `.keys`, and to use - * `.all` when asserting `.keys` without negation. - * - * When negating `.keys`, `.any` is preferred because `.not.any.keys` asserts - * exactly what's expected of the output, whereas `.not.all.keys` creates - * uncertain expectations. - * - * // Recommended; asserts that target doesn't have any of the given keys - * expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd'); - * - * // Not recommended; asserts that target doesn't have all of the given - * // keys but may or may not have some of them - * expect({a: 1, b: 2}).to.not.have.all.keys('c', 'd'); - * - * When asserting `.keys` without negation, `.all` is preferred because - * `.all.keys` asserts exactly what's expected of the output, whereas - * `.any.keys` creates uncertain expectations. - * - * // Recommended; asserts that target has all the given keys - * expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); - * - * // Not recommended; asserts that target has at least one of the given - * // keys but may or may not have more of them - * expect({a: 1, b: 2}).to.have.any.keys('a', 'b'); - * - * Note that `.all` is used by default when neither `.all` nor `.any` appear - * earlier in the chain. However, it's often best to add `.all` anyway because - * it improves readability. - * - * // Both assertions are identical - * expect({a: 1, b: 2}).to.have.all.keys('a', 'b'); // Recommended - * expect({a: 1, b: 2}).to.have.keys('a', 'b'); // Not recommended - * - * Add `.include` earlier in the chain to require that the target's keys be a - * superset of the expected keys, rather than identical sets. - * - * // Target object's keys are a superset of ['a', 'b'] but not identical - * expect({a: 1, b: 2, c: 3}).to.include.all.keys('a', 'b'); - * expect({a: 1, b: 2, c: 3}).to.not.have.all.keys('a', 'b'); - * - * However, if `.any` and `.include` are combined, only the `.any` takes - * effect. The `.include` is ignored in this case. - * - * // Both assertions are identical - * expect({a: 1}).to.have.any.keys('a', 'b'); - * expect({a: 1}).to.include.any.keys('a', 'b'); - * - * A custom error message can be given as the second argument to `expect`. - * - * expect({a: 1}, 'nooo why fail??').to.have.key('b'); - * - * The alias `.key` can be used interchangeably with `.keys`. - * - * @name keys - * @alias key - * @param {...String|Array|Object} keys - * @namespace BDD - * @api public - */ - - function assertKeys (keys) { - var obj = flag(this, 'object') - , objType = _.type(obj) - , keysType = _.type(keys) - , ssfi = flag(this, 'ssfi') - , isDeep = flag(this, 'deep') - , str - , deepStr = '' - , ok = true - , flagMsg = flag(this, 'message'); - - flagMsg = flagMsg ? flagMsg + ': ' : ''; - var mixedArgsMsg = flagMsg + 'when testing keys against an object or an array you must give a single Array|Object|String argument or multiple String arguments'; - - if (objType === 'Map' || objType === 'Set') { - deepStr = isDeep ? 'deeply ' : ''; - actual = []; - - // Map and Set '.keys' aren't supported in IE 11. Therefore, use .forEach. - obj.forEach(function (val, key) { actual.push(key) }); - - if (keysType !== 'Array') { - keys = Array.prototype.slice.call(arguments); - } - - } else { - actual = _.getOwnEnumerableProperties(obj); - - switch (keysType) { - case 'Array': - if (arguments.length > 1) { - throw new AssertionError(mixedArgsMsg, undefined, ssfi); - } - break; - case 'Object': - if (arguments.length > 1) { - throw new AssertionError(mixedArgsMsg, undefined, ssfi); - } - keys = Object.keys(keys); - break; - default: - keys = Array.prototype.slice.call(arguments); - } - - // Only stringify non-Symbols because Symbols would become "Symbol()" - keys = keys.map(function (val) { - return typeof val === 'symbol' ? val : String(val); - }); - } - - if (!keys.length) { - throw new AssertionError(flagMsg + 'keys required', undefined, ssfi); - } - - var len = keys.length - , any = flag(this, 'any') - , all = flag(this, 'all') - , expected = keys - , actual; - - if (!any && !all) { - all = true; - } - - // Has any - if (any) { - ok = expected.some(function(expectedKey) { - return actual.some(function(actualKey) { - if (isDeep) { - return _.eql(expectedKey, actualKey); - } else { - return expectedKey === actualKey; - } - }); - }); - } - - // Has all - if (all) { - ok = expected.every(function(expectedKey) { - return actual.some(function(actualKey) { - if (isDeep) { - return _.eql(expectedKey, actualKey); - } else { - return expectedKey === actualKey; - } - }); - }); - - if (!flag(this, 'contains')) { - ok = ok && keys.length == actual.length; - } - } - - // Key string - if (len > 1) { - keys = keys.map(function(key) { - return _.inspect(key); - }); - var last = keys.pop(); - if (all) { - str = keys.join(', ') + ', and ' + last; - } - if (any) { - str = keys.join(', ') + ', or ' + last; - } - } else { - str = _.inspect(keys[0]); - } - - // Form - str = (len > 1 ? 'keys ' : 'key ') + str; - - // Have / include - str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; - - // Assertion - this.assert( - ok - , 'expected #{this} to ' + deepStr + str - , 'expected #{this} to not ' + deepStr + str - , expected.slice(0).sort(_.compareByInspect) - , actual.sort(_.compareByInspect) - , true - ); - } - - Assertion.addMethod('keys', assertKeys); - Assertion.addMethod('key', assertKeys); - - /** - * ### .throw([errorLike], [errMsgMatcher], [msg]) - * - * When no arguments are provided, `.throw` invokes the target function and - * asserts that an error is thrown. - * - * var badFn = function () { throw new TypeError('Illegal salmon!'); }; - * - * expect(badFn).to.throw(); - * - * When one argument is provided, and it's an error constructor, `.throw` - * invokes the target function and asserts that an error is thrown that's an - * instance of that error constructor. - * - * var badFn = function () { throw new TypeError('Illegal salmon!'); }; - * - * expect(badFn).to.throw(TypeError); - * - * When one argument is provided, and it's an error instance, `.throw` invokes - * the target function and asserts that an error is thrown that's strictly - * (`===`) equal to that error instance. - * - * var err = new TypeError('Illegal salmon!'); - * var badFn = function () { throw err; }; - * - * expect(badFn).to.throw(err); - * - * When one argument is provided, and it's a string, `.throw` invokes the - * target function and asserts that an error is thrown with a message that - * contains that string. - * - * var badFn = function () { throw new TypeError('Illegal salmon!'); }; - * - * expect(badFn).to.throw('salmon'); - * - * When one argument is provided, and it's a regular expression, `.throw` - * invokes the target function and asserts that an error is thrown with a - * message that matches that regular expression. - * - * var badFn = function () { throw new TypeError('Illegal salmon!'); }; - * - * expect(badFn).to.throw(/salmon/); - * - * When two arguments are provided, and the first is an error instance or - * constructor, and the second is a string or regular expression, `.throw` - * invokes the function and asserts that an error is thrown that fulfills both - * conditions as described above. - * - * var err = new TypeError('Illegal salmon!'); - * var badFn = function () { throw err; }; - * - * expect(badFn).to.throw(TypeError, 'salmon'); - * expect(badFn).to.throw(TypeError, /salmon/); - * expect(badFn).to.throw(err, 'salmon'); - * expect(badFn).to.throw(err, /salmon/); - * - * Add `.not` earlier in the chain to negate `.throw`. - * - * var goodFn = function () {}; - * - * expect(goodFn).to.not.throw(); - * - * However, it's dangerous to negate `.throw` when providing any arguments. - * The problem is that it creates uncertain expectations by asserting that the - * target either doesn't throw an error, or that it throws an error but of a - * different type than the given type, or that it throws an error of the given - * type but with a message that doesn't include the given string. It's often - * best to identify the exact output that's expected, and then write an - * assertion that only accepts that exact output. - * - * When the target isn't expected to throw an error, it's often best to assert - * exactly that. - * - * var goodFn = function () {}; - * - * expect(goodFn).to.not.throw(); // Recommended - * expect(goodFn).to.not.throw(ReferenceError, 'x'); // Not recommended - * - * When the target is expected to throw an error, it's often best to assert - * that the error is of its expected type, and has a message that includes an - * expected string, rather than asserting that it doesn't have one of many - * unexpected types, and doesn't have a message that includes some string. - * - * var badFn = function () { throw new TypeError('Illegal salmon!'); }; - * - * expect(badFn).to.throw(TypeError, 'salmon'); // Recommended - * expect(badFn).to.not.throw(ReferenceError, 'x'); // Not recommended - * - * `.throw` changes the target of any assertions that follow in the chain to - * be the error object that's thrown. - * - * var err = new TypeError('Illegal salmon!'); - * err.code = 42; - * var badFn = function () { throw err; }; - * - * expect(badFn).to.throw(TypeError).with.property('code', 42); - * - * `.throw` accepts an optional `msg` argument which is a custom error message - * to show when the assertion fails. The message can also be given as the - * second argument to `expect`. When not providing two arguments, always use - * the second form. - * - * var goodFn = function () {}; - * - * expect(goodFn).to.throw(TypeError, 'x', 'nooo why fail??'); - * expect(goodFn, 'nooo why fail??').to.throw(); - * - * Due to limitations in ES5, `.throw` may not always work as expected when - * using a transpiler such as Babel or TypeScript. In particular, it may - * produce unexpected results when subclassing the built-in `Error` object and - * then passing the subclassed constructor to `.throw`. See your transpiler's - * docs for details: - * - * - ([Babel](https://babeljs.io/docs/usage/caveats/#classes)) - * - ([TypeScript](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work)) - * - * Beware of some common mistakes when using the `throw` assertion. One common - * mistake is to accidentally invoke the function yourself instead of letting - * the `throw` assertion invoke the function for you. For example, when - * testing if a function named `fn` throws, provide `fn` instead of `fn()` as - * the target for the assertion. - * - * expect(fn).to.throw(); // Good! Tests `fn` as desired - * expect(fn()).to.throw(); // Bad! Tests result of `fn()`, not `fn` - * - * If you need to assert that your function `fn` throws when passed certain - * arguments, then wrap a call to `fn` inside of another function. - * - * expect(function () { fn(42); }).to.throw(); // Function expression - * expect(() => fn(42)).to.throw(); // ES6 arrow function - * - * Another common mistake is to provide an object method (or any stand-alone - * function that relies on `this`) as the target of the assertion. Doing so is - * problematic because the `this` context will be lost when the function is - * invoked by `.throw`; there's no way for it to know what `this` is supposed - * to be. There are two ways around this problem. One solution is to wrap the - * method or function call inside of another function. Another solution is to - * use `bind`. - * - * expect(function () { cat.meow(); }).to.throw(); // Function expression - * expect(() => cat.meow()).to.throw(); // ES6 arrow function - * expect(cat.meow.bind(cat)).to.throw(); // Bind - * - * Finally, it's worth mentioning that it's a best practice in JavaScript to - * only throw `Error` and derivatives of `Error` such as `ReferenceError`, - * `TypeError`, and user-defined objects that extend `Error`. No other type of - * value will generate a stack trace when initialized. With that said, the - * `throw` assertion does technically support any type of value being thrown, - * not just `Error` and its derivatives. - * - * The aliases `.throws` and `.Throw` can be used interchangeably with - * `.throw`. - * - * @name throw - * @alias throws - * @alias Throw - * @param {Error|ErrorConstructor} errorLike - * @param {String|RegExp} errMsgMatcher error message - * @param {String} msg _optional_ - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types - * @returns error for chaining (null if no error) - * @namespace BDD - * @api public - */ - - function assertThrows (errorLike, errMsgMatcher, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , ssfi = flag(this, 'ssfi') - , flagMsg = flag(this, 'message') - , negate = flag(this, 'negate') || false; - new Assertion(obj, flagMsg, ssfi, true).is.a('function'); - - if (errorLike instanceof RegExp || typeof errorLike === 'string') { - errMsgMatcher = errorLike; - errorLike = null; - } - - var caughtErr; - try { - obj(); - } catch (err) { - caughtErr = err; - } - - // If we have the negate flag enabled and at least one valid argument it means we do expect an error - // but we want it to match a given set of criteria - var everyArgIsUndefined = errorLike === undefined && errMsgMatcher === undefined; - - // If we've got the negate flag enabled and both args, we should only fail if both aren't compatible - // See Issue #551 and PR #683@GitHub - var everyArgIsDefined = Boolean(errorLike && errMsgMatcher); - var errorLikeFail = false; - var errMsgMatcherFail = false; - - // Checking if error was thrown - if (everyArgIsUndefined || !everyArgIsUndefined && !negate) { - // We need this to display results correctly according to their types - var errorLikeString = 'an error'; - if (errorLike instanceof Error) { - errorLikeString = '#{exp}'; - } else if (errorLike) { - errorLikeString = _.checkError.getConstructorName(errorLike); - } - - this.assert( - caughtErr - , 'expected #{this} to throw ' + errorLikeString - , 'expected #{this} to not throw an error but #{act} was thrown' - , errorLike && errorLike.toString() - , (caughtErr instanceof Error ? - caughtErr.toString() : (typeof caughtErr === 'string' ? caughtErr : caughtErr && - _.checkError.getConstructorName(caughtErr))) - ); - } - - if (errorLike && caughtErr) { - // We should compare instances only if `errorLike` is an instance of `Error` - if (errorLike instanceof Error) { - var isCompatibleInstance = _.checkError.compatibleInstance(caughtErr, errorLike); - - if (isCompatibleInstance === negate) { - // These checks were created to ensure we won't fail too soon when we've got both args and a negate - // See Issue #551 and PR #683@GitHub - if (everyArgIsDefined && negate) { - errorLikeFail = true; - } else { - this.assert( - negate - , 'expected #{this} to throw #{exp} but #{act} was thrown' - , 'expected #{this} to not throw #{exp}' + (caughtErr && !negate ? ' but #{act} was thrown' : '') - , errorLike.toString() - , caughtErr.toString() - ); - } - } - } - - var isCompatibleConstructor = _.checkError.compatibleConstructor(caughtErr, errorLike); - if (isCompatibleConstructor === negate) { - if (everyArgIsDefined && negate) { - errorLikeFail = true; - } else { - this.assert( - negate - , 'expected #{this} to throw #{exp} but #{act} was thrown' - , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '') - , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike)) - , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr)) - ); - } - } - } - - if (caughtErr && errMsgMatcher !== undefined && errMsgMatcher !== null) { - // Here we check compatible messages - var placeholder = 'including'; - if (errMsgMatcher instanceof RegExp) { - placeholder = 'matching' - } - - var isCompatibleMessage = _.checkError.compatibleMessage(caughtErr, errMsgMatcher); - if (isCompatibleMessage === negate) { - if (everyArgIsDefined && negate) { - errMsgMatcherFail = true; - } else { - this.assert( - negate - , 'expected #{this} to throw error ' + placeholder + ' #{exp} but got #{act}' - , 'expected #{this} to throw error not ' + placeholder + ' #{exp}' - , errMsgMatcher - , _.checkError.getMessage(caughtErr) - ); - } - } - } - - // If both assertions failed and both should've matched we throw an error - if (errorLikeFail && errMsgMatcherFail) { - this.assert( - negate - , 'expected #{this} to throw #{exp} but #{act} was thrown' - , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '') - , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike)) - , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr)) - ); - } - - flag(this, 'object', caughtErr); - }; - - Assertion.addMethod('throw', assertThrows); - Assertion.addMethod('throws', assertThrows); - Assertion.addMethod('Throw', assertThrows); - - /** - * ### .respondTo(method[, msg]) - * - * When the target is a non-function object, `.respondTo` asserts that the - * target has a method with the given name `method`. The method can be own or - * inherited, and it can be enumerable or non-enumerable. - * - * function Cat () {} - * Cat.prototype.meow = function () {}; - * - * expect(new Cat()).to.respondTo('meow'); - * - * When the target is a function, `.respondTo` asserts that the target's - * `prototype` property has a method with the given name `method`. Again, the - * method can be own or inherited, and it can be enumerable or non-enumerable. - * - * function Cat () {} - * Cat.prototype.meow = function () {}; - * - * expect(Cat).to.respondTo('meow'); - * - * Add `.itself` earlier in the chain to force `.respondTo` to treat the - * target as a non-function object, even if it's a function. Thus, it asserts - * that the target has a method with the given name `method`, rather than - * asserting that the target's `prototype` property has a method with the - * given name `method`. - * - * function Cat () {} - * Cat.prototype.meow = function () {}; - * Cat.hiss = function () {}; - * - * expect(Cat).itself.to.respondTo('hiss').but.not.respondTo('meow'); - * - * When not adding `.itself`, it's important to check the target's type before - * using `.respondTo`. See the `.a` doc for info on checking a target's type. - * - * function Cat () {} - * Cat.prototype.meow = function () {}; - * - * expect(new Cat()).to.be.an('object').that.respondsTo('meow'); - * - * Add `.not` earlier in the chain to negate `.respondTo`. - * - * function Dog () {} - * Dog.prototype.bark = function () {}; - * - * expect(new Dog()).to.not.respondTo('meow'); - * - * `.respondTo` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. - * - * expect({}).to.respondTo('meow', 'nooo why fail??'); - * expect({}, 'nooo why fail??').to.respondTo('meow'); - * - * The alias `.respondsTo` can be used interchangeably with `.respondTo`. - * - * @name respondTo - * @alias respondsTo - * @param {String} method - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function respondTo (method, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , itself = flag(this, 'itself') - , context = ('function' === typeof obj && !itself) - ? obj.prototype[method] - : obj[method]; - - this.assert( - 'function' === typeof context - , 'expected #{this} to respond to ' + _.inspect(method) - , 'expected #{this} to not respond to ' + _.inspect(method) - ); - } - - Assertion.addMethod('respondTo', respondTo); - Assertion.addMethod('respondsTo', respondTo); - - /** - * ### .itself - * - * Forces all `.respondTo` assertions that follow in the chain to behave as if - * the target is a non-function object, even if it's a function. Thus, it - * causes `.respondTo` to assert that the target has a method with the given - * name, rather than asserting that the target's `prototype` property has a - * method with the given name. - * - * function Cat () {} - * Cat.prototype.meow = function () {}; - * Cat.hiss = function () {}; - * - * expect(Cat).itself.to.respondTo('hiss').but.not.respondTo('meow'); - * - * @name itself - * @namespace BDD - * @api public - */ - - Assertion.addProperty('itself', function () { - flag(this, 'itself', true); - }); - - /** - * ### .satisfy(matcher[, msg]) - * - * Invokes the given `matcher` function with the target being passed as the - * first argument, and asserts that the value returned is truthy. - * - * expect(1).to.satisfy(function(num) { - * return num > 0; - * }); - * - * Add `.not` earlier in the chain to negate `.satisfy`. - * - * expect(1).to.not.satisfy(function(num) { - * return num > 2; - * }); - * - * `.satisfy` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. - * - * expect(1).to.satisfy(function(num) { - * return num > 2; - * }, 'nooo why fail??'); - * - * expect(1, 'nooo why fail??').to.satisfy(function(num) { - * return num > 2; - * }); - * - * The alias `.satisfies` can be used interchangeably with `.satisfy`. - * - * @name satisfy - * @alias satisfies - * @param {Function} matcher - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function satisfy (matcher, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - var result = matcher(obj); - this.assert( - result - , 'expected #{this} to satisfy ' + _.objDisplay(matcher) - , 'expected #{this} to not satisfy' + _.objDisplay(matcher) - , flag(this, 'negate') ? false : true - , result - ); - } - - Assertion.addMethod('satisfy', satisfy); - Assertion.addMethod('satisfies', satisfy); - - /** - * ### .closeTo(expected, delta[, msg]) - * - * Asserts that the target is a number that's within a given +/- `delta` range - * of the given number `expected`. However, it's often best to assert that the - * target is equal to its expected value. - * - * // Recommended - * expect(1.5).to.equal(1.5); - * - * // Not recommended - * expect(1.5).to.be.closeTo(1, 0.5); - * expect(1.5).to.be.closeTo(2, 0.5); - * expect(1.5).to.be.closeTo(1, 1); - * - * Add `.not` earlier in the chain to negate `.closeTo`. - * - * expect(1.5).to.equal(1.5); // Recommended - * expect(1.5).to.not.be.closeTo(3, 1); // Not recommended - * - * `.closeTo` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. - * - * expect(1.5).to.be.closeTo(3, 1, 'nooo why fail??'); - * expect(1.5, 'nooo why fail??').to.be.closeTo(3, 1); - * - * The alias `.approximately` can be used interchangeably with `.closeTo`. - * - * @name closeTo - * @alias approximately - * @param {Number} expected - * @param {Number} delta - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function closeTo(expected, delta, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , flagMsg = flag(this, 'message') - , ssfi = flag(this, 'ssfi'); - - new Assertion(obj, flagMsg, ssfi, true).is.a('number'); - if (typeof expected !== 'number' || typeof delta !== 'number') { - flagMsg = flagMsg ? flagMsg + ': ' : ''; - throw new AssertionError( - flagMsg + 'the arguments to closeTo or approximately must be numbers', - undefined, - ssfi - ); - } - - this.assert( - Math.abs(obj - expected) <= delta - , 'expected #{this} to be close to ' + expected + ' +/- ' + delta - , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta - ); - } - - Assertion.addMethod('closeTo', closeTo); - Assertion.addMethod('approximately', closeTo); - - // Note: Duplicates are ignored if testing for inclusion instead of sameness. - function isSubsetOf(subset, superset, cmp, contains, ordered) { - if (!contains) { - if (subset.length !== superset.length) return false; - superset = superset.slice(); - } - - return subset.every(function(elem, idx) { - if (ordered) return cmp ? cmp(elem, superset[idx]) : elem === superset[idx]; - - if (!cmp) { - var matchIdx = superset.indexOf(elem); - if (matchIdx === -1) return false; - - // Remove match from superset so not counted twice if duplicate in subset. - if (!contains) superset.splice(matchIdx, 1); - return true; - } - - return superset.some(function(elem2, matchIdx) { - if (!cmp(elem, elem2)) return false; - - // Remove match from superset so not counted twice if duplicate in subset. - if (!contains) superset.splice(matchIdx, 1); - return true; - }); - }); - } - - /** - * ### .members(set[, msg]) - * - * Asserts that the target array has the same members as the given array - * `set`. - * - * expect([1, 2, 3]).to.have.members([2, 1, 3]); - * expect([1, 2, 2]).to.have.members([2, 1, 2]); - * - * By default, members are compared using strict (`===`) equality. Add `.deep` - * earlier in the chain to use deep equality instead. See the `deep-eql` - * project page for info on the deep equality algorithm: - * https://github.com/chaijs/deep-eql. - * - * // Target array deeply (but not strictly) has member `{a: 1}` - * expect([{a: 1}]).to.have.deep.members([{a: 1}]); - * expect([{a: 1}]).to.not.have.members([{a: 1}]); - * - * By default, order doesn't matter. Add `.ordered` earlier in the chain to - * require that members appear in the same order. - * - * expect([1, 2, 3]).to.have.ordered.members([1, 2, 3]); - * expect([1, 2, 3]).to.have.members([2, 1, 3]) - * .but.not.ordered.members([2, 1, 3]); - * - * By default, both arrays must be the same size. Add `.include` earlier in - * the chain to require that the target's members be a superset of the - * expected members. Note that duplicates are ignored in the subset when - * `.include` is added. - * - * // Target array is a superset of [1, 2] but not identical - * expect([1, 2, 3]).to.include.members([1, 2]); - * expect([1, 2, 3]).to.not.have.members([1, 2]); - * - * // Duplicates in the subset are ignored - * expect([1, 2, 3]).to.include.members([1, 2, 2, 2]); - * - * `.deep`, `.ordered`, and `.include` can all be combined. However, if - * `.include` and `.ordered` are combined, the ordering begins at the start of - * both arrays. - * - * expect([{a: 1}, {b: 2}, {c: 3}]) - * .to.include.deep.ordered.members([{a: 1}, {b: 2}]) - * .but.not.include.deep.ordered.members([{b: 2}, {c: 3}]); - * - * Add `.not` earlier in the chain to negate `.members`. However, it's - * dangerous to do so. The problem is that it creates uncertain expectations - * by asserting that the target array doesn't have all of the same members as - * the given array `set` but may or may not have some of them. It's often best - * to identify the exact output that's expected, and then write an assertion - * that only accepts that exact output. - * - * expect([1, 2]).to.not.include(3).and.not.include(4); // Recommended - * expect([1, 2]).to.not.have.members([3, 4]); // Not recommended - * - * `.members` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. - * - * expect([1, 2]).to.have.members([1, 2, 3], 'nooo why fail??'); - * expect([1, 2], 'nooo why fail??').to.have.members([1, 2, 3]); - * - * @name members - * @param {Array} set - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - Assertion.addMethod('members', function (subset, msg) { - if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object') - , flagMsg = flag(this, 'message') - , ssfi = flag(this, 'ssfi'); - - new Assertion(obj, flagMsg, ssfi, true).to.be.an('array'); - new Assertion(subset, flagMsg, ssfi, true).to.be.an('array'); - - var contains = flag(this, 'contains'); - var ordered = flag(this, 'ordered'); - - var subject, failMsg, failNegateMsg, lengthCheck; - - if (contains) { - subject = ordered ? 'an ordered superset' : 'a superset'; - failMsg = 'expected #{this} to be ' + subject + ' of #{exp}'; - failNegateMsg = 'expected #{this} to not be ' + subject + ' of #{exp}'; - } else { - subject = ordered ? 'ordered members' : 'members'; - failMsg = 'expected #{this} to have the same ' + subject + ' as #{exp}'; - failNegateMsg = 'expected #{this} to not have the same ' + subject + ' as #{exp}'; - } - - var cmp = flag(this, 'deep') ? _.eql : undefined; - - this.assert( - isSubsetOf(subset, obj, cmp, contains, ordered) - , failMsg - , failNegateMsg - , subset - , obj - , true - ); - }); - - /** - * ### .oneOf(list[, msg]) - * - * Asserts that the target is a member of the given array `list`. However, - * it's often best to assert that the target is equal to its expected value. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.be.oneOf([1, 2, 3]); // Not recommended - * - * Comparisons are performed using strict (`===`) equality. - * - * Add `.not` earlier in the chain to negate `.oneOf`. - * - * expect(1).to.equal(1); // Recommended - * expect(1).to.not.be.oneOf([2, 3, 4]); // Not recommended - * - * `.oneOf` accepts an optional `msg` argument which is a custom error message - * to show when the assertion fails. The message can also be given as the - * second argument to `expect`. - * - * expect(1).to.be.oneOf([2, 3, 4], 'nooo why fail??'); - * expect(1, 'nooo why fail??').to.be.oneOf([2, 3, 4]); - * - * @name oneOf - * @param {Array<*>} list - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function oneOf (list, msg) { - if (msg) flag(this, 'message', msg); - var expected = flag(this, 'object') - , flagMsg = flag(this, 'message') - , ssfi = flag(this, 'ssfi'); - new Assertion(list, flagMsg, ssfi, true).to.be.an('array'); - - this.assert( - list.indexOf(expected) > -1 - , 'expected #{this} to be one of #{exp}' - , 'expected #{this} to not be one of #{exp}' - , list - , expected - ); - } - - Assertion.addMethod('oneOf', oneOf); - - - /** - * ### .change(subject[, prop[, msg]]) - * - * When one argument is provided, `.change` asserts that the given function - * `subject` returns a different value when it's invoked before the target - * function compared to when it's invoked afterward. However, it's often best - * to assert that `subject` is equal to its expected value. - * - * var dots = '' - * , addDot = function () { dots += '.'; } - * , getDots = function () { return dots; }; - * - * // Recommended - * expect(getDots()).to.equal(''); - * addDot(); - * expect(getDots()).to.equal('.'); - * - * // Not recommended - * expect(addDot).to.change(getDots); - * - * When two arguments are provided, `.change` asserts that the value of the - * given object `subject`'s `prop` property is different before invoking the - * target function compared to afterward. - * - * var myObj = {dots: ''} - * , addDot = function () { myObj.dots += '.'; }; - * - * // Recommended - * expect(myObj).to.have.property('dots', ''); - * addDot(); - * expect(myObj).to.have.property('dots', '.'); - * - * // Not recommended - * expect(addDot).to.change(myObj, 'dots'); - * - * Strict (`===`) equality is used to compare before and after values. - * - * Add `.not` earlier in the chain to negate `.change`. - * - * var dots = '' - * , noop = function () {} - * , getDots = function () { return dots; }; - * - * expect(noop).to.not.change(getDots); - * - * var myObj = {dots: ''} - * , noop = function () {}; - * - * expect(noop).to.not.change(myObj, 'dots'); - * - * `.change` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. When not providing two arguments, always - * use the second form. - * - * var myObj = {dots: ''} - * , addDot = function () { myObj.dots += '.'; }; - * - * expect(addDot).to.not.change(myObj, 'dots', 'nooo why fail??'); - * - * var dots = '' - * , addDot = function () { dots += '.'; } - * , getDots = function () { return dots; }; - * - * expect(addDot, 'nooo why fail??').to.not.change(getDots); - * - * `.change` also causes all `.by` assertions that follow in the chain to - * assert how much a numeric subject was increased or decreased by. However, - * it's dangerous to use `.change.by`. The problem is that it creates - * uncertain expectations by asserting that the subject either increases by - * the given delta, or that it decreases by the given delta. It's often best - * to identify the exact output that's expected, and then write an assertion - * that only accepts that exact output. - * - * var myObj = {val: 1} - * , addTwo = function () { myObj.val += 2; } - * , subtractTwo = function () { myObj.val -= 2; }; - * - * expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended - * expect(addTwo).to.change(myObj, 'val').by(2); // Not recommended - * - * expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended - * expect(subtractTwo).to.change(myObj, 'val').by(2); // Not recommended - * - * The alias `.changes` can be used interchangeably with `.change`. - * - * @name change - * @alias changes - * @param {String} subject - * @param {String} prop name _optional_ - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertChanges (subject, prop, msg) { - if (msg) flag(this, 'message', msg); - var fn = flag(this, 'object') - , flagMsg = flag(this, 'message') - , ssfi = flag(this, 'ssfi'); - new Assertion(fn, flagMsg, ssfi, true).is.a('function'); - - var initial; - if (!prop) { - new Assertion(subject, flagMsg, ssfi, true).is.a('function'); - initial = subject(); - } else { - new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop); - initial = subject[prop]; - } - - fn(); - - var final = prop === undefined || prop === null ? subject() : subject[prop]; - var msgObj = prop === undefined || prop === null ? initial : '.' + prop; - - // This gets flagged because of the .by(delta) assertion - flag(this, 'deltaMsgObj', msgObj); - flag(this, 'initialDeltaValue', initial); - flag(this, 'finalDeltaValue', final); - flag(this, 'deltaBehavior', 'change'); - flag(this, 'realDelta', final !== initial); - - this.assert( - initial !== final - , 'expected ' + msgObj + ' to change' - , 'expected ' + msgObj + ' to not change' - ); - } - - Assertion.addMethod('change', assertChanges); - Assertion.addMethod('changes', assertChanges); - - /** - * ### .increase(subject[, prop[, msg]]) - * - * When one argument is provided, `.increase` asserts that the given function - * `subject` returns a greater number when it's invoked after invoking the - * target function compared to when it's invoked beforehand. `.increase` also - * causes all `.by` assertions that follow in the chain to assert how much - * greater of a number is returned. It's often best to assert that the return - * value increased by the expected amount, rather than asserting it increased - * by any amount. - * - * var val = 1 - * , addTwo = function () { val += 2; } - * , getVal = function () { return val; }; - * - * expect(addTwo).to.increase(getVal).by(2); // Recommended - * expect(addTwo).to.increase(getVal); // Not recommended - * - * When two arguments are provided, `.increase` asserts that the value of the - * given object `subject`'s `prop` property is greater after invoking the - * target function compared to beforehand. - * - * var myObj = {val: 1} - * , addTwo = function () { myObj.val += 2; }; - * - * expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended - * expect(addTwo).to.increase(myObj, 'val'); // Not recommended - * - * Add `.not` earlier in the chain to negate `.increase`. However, it's - * dangerous to do so. The problem is that it creates uncertain expectations - * by asserting that the subject either decreases, or that it stays the same. - * It's often best to identify the exact output that's expected, and then - * write an assertion that only accepts that exact output. - * - * When the subject is expected to decrease, it's often best to assert that it - * decreased by the expected amount. - * - * var myObj = {val: 1} - * , subtractTwo = function () { myObj.val -= 2; }; - * - * expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended - * expect(subtractTwo).to.not.increase(myObj, 'val'); // Not recommended - * - * When the subject is expected to stay the same, it's often best to assert - * exactly that. - * - * var myObj = {val: 1} - * , noop = function () {}; - * - * expect(noop).to.not.change(myObj, 'val'); // Recommended - * expect(noop).to.not.increase(myObj, 'val'); // Not recommended - * - * `.increase` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. When not providing two arguments, always - * use the second form. - * - * var myObj = {val: 1} - * , noop = function () {}; - * - * expect(noop).to.increase(myObj, 'val', 'nooo why fail??'); - * - * var val = 1 - * , noop = function () {} - * , getVal = function () { return val; }; - * - * expect(noop, 'nooo why fail??').to.increase(getVal); - * - * The alias `.increases` can be used interchangeably with `.increase`. - * - * @name increase - * @alias increases - * @param {String|Function} subject - * @param {String} prop name _optional_ - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertIncreases (subject, prop, msg) { - if (msg) flag(this, 'message', msg); - var fn = flag(this, 'object') - , flagMsg = flag(this, 'message') - , ssfi = flag(this, 'ssfi'); - new Assertion(fn, flagMsg, ssfi, true).is.a('function'); - - var initial; - if (!prop) { - new Assertion(subject, flagMsg, ssfi, true).is.a('function'); - initial = subject(); - } else { - new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop); - initial = subject[prop]; - } - - // Make sure that the target is a number - new Assertion(initial, flagMsg, ssfi, true).is.a('number'); - - fn(); - - var final = prop === undefined || prop === null ? subject() : subject[prop]; - var msgObj = prop === undefined || prop === null ? initial : '.' + prop; - - flag(this, 'deltaMsgObj', msgObj); - flag(this, 'initialDeltaValue', initial); - flag(this, 'finalDeltaValue', final); - flag(this, 'deltaBehavior', 'increase'); - flag(this, 'realDelta', final - initial); - - this.assert( - final - initial > 0 - , 'expected ' + msgObj + ' to increase' - , 'expected ' + msgObj + ' to not increase' - ); - } - - Assertion.addMethod('increase', assertIncreases); - Assertion.addMethod('increases', assertIncreases); - - /** - * ### .decrease(subject[, prop[, msg]]) - * - * When one argument is provided, `.decrease` asserts that the given function - * `subject` returns a lesser number when it's invoked after invoking the - * target function compared to when it's invoked beforehand. `.decrease` also - * causes all `.by` assertions that follow in the chain to assert how much - * lesser of a number is returned. It's often best to assert that the return - * value decreased by the expected amount, rather than asserting it decreased - * by any amount. - * - * var val = 1 - * , subtractTwo = function () { val -= 2; } - * , getVal = function () { return val; }; - * - * expect(subtractTwo).to.decrease(getVal).by(2); // Recommended - * expect(subtractTwo).to.decrease(getVal); // Not recommended - * - * When two arguments are provided, `.decrease` asserts that the value of the - * given object `subject`'s `prop` property is lesser after invoking the - * target function compared to beforehand. - * - * var myObj = {val: 1} - * , subtractTwo = function () { myObj.val -= 2; }; - * - * expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended - * expect(subtractTwo).to.decrease(myObj, 'val'); // Not recommended - * - * Add `.not` earlier in the chain to negate `.decrease`. However, it's - * dangerous to do so. The problem is that it creates uncertain expectations - * by asserting that the subject either increases, or that it stays the same. - * It's often best to identify the exact output that's expected, and then - * write an assertion that only accepts that exact output. - * - * When the subject is expected to increase, it's often best to assert that it - * increased by the expected amount. - * - * var myObj = {val: 1} - * , addTwo = function () { myObj.val += 2; }; - * - * expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended - * expect(addTwo).to.not.decrease(myObj, 'val'); // Not recommended - * - * When the subject is expected to stay the same, it's often best to assert - * exactly that. - * - * var myObj = {val: 1} - * , noop = function () {}; - * - * expect(noop).to.not.change(myObj, 'val'); // Recommended - * expect(noop).to.not.decrease(myObj, 'val'); // Not recommended - * - * `.decrease` accepts an optional `msg` argument which is a custom error - * message to show when the assertion fails. The message can also be given as - * the second argument to `expect`. When not providing two arguments, always - * use the second form. - * - * var myObj = {val: 1} - * , noop = function () {}; - * - * expect(noop).to.decrease(myObj, 'val', 'nooo why fail??'); - * - * var val = 1 - * , noop = function () {} - * , getVal = function () { return val; }; - * - * expect(noop, 'nooo why fail??').to.decrease(getVal); - * - * The alias `.decreases` can be used interchangeably with `.decrease`. - * - * @name decrease - * @alias decreases - * @param {String|Function} subject - * @param {String} prop name _optional_ - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertDecreases (subject, prop, msg) { - if (msg) flag(this, 'message', msg); - var fn = flag(this, 'object') - , flagMsg = flag(this, 'message') - , ssfi = flag(this, 'ssfi'); - new Assertion(fn, flagMsg, ssfi, true).is.a('function'); - - var initial; - if (!prop) { - new Assertion(subject, flagMsg, ssfi, true).is.a('function'); - initial = subject(); - } else { - new Assertion(subject, flagMsg, ssfi, true).to.have.property(prop); - initial = subject[prop]; - } - - // Make sure that the target is a number - new Assertion(initial, flagMsg, ssfi, true).is.a('number'); - - fn(); - - var final = prop === undefined || prop === null ? subject() : subject[prop]; - var msgObj = prop === undefined || prop === null ? initial : '.' + prop; - - flag(this, 'deltaMsgObj', msgObj); - flag(this, 'initialDeltaValue', initial); - flag(this, 'finalDeltaValue', final); - flag(this, 'deltaBehavior', 'decrease'); - flag(this, 'realDelta', initial - final); - - this.assert( - final - initial < 0 - , 'expected ' + msgObj + ' to decrease' - , 'expected ' + msgObj + ' to not decrease' - ); - } - - Assertion.addMethod('decrease', assertDecreases); - Assertion.addMethod('decreases', assertDecreases); - - /** - * ### .by(delta[, msg]) - * - * When following an `.increase` assertion in the chain, `.by` asserts that - * the subject of the `.increase` assertion increased by the given `delta`. - * - * var myObj = {val: 1} - * , addTwo = function () { myObj.val += 2; }; - * - * expect(addTwo).to.increase(myObj, 'val').by(2); - * - * When following a `.decrease` assertion in the chain, `.by` asserts that the - * subject of the `.decrease` assertion decreased by the given `delta`. - * - * var myObj = {val: 1} - * , subtractTwo = function () { myObj.val -= 2; }; - * - * expect(subtractTwo).to.decrease(myObj, 'val').by(2); - * - * When following a `.change` assertion in the chain, `.by` asserts that the - * subject of the `.change` assertion either increased or decreased by the - * given `delta`. However, it's dangerous to use `.change.by`. The problem is - * that it creates uncertain expectations. It's often best to identify the - * exact output that's expected, and then write an assertion that only accepts - * that exact output. - * - * var myObj = {val: 1} - * , addTwo = function () { myObj.val += 2; } - * , subtractTwo = function () { myObj.val -= 2; }; - * - * expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended - * expect(addTwo).to.change(myObj, 'val').by(2); // Not recommended - * - * expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended - * expect(subtractTwo).to.change(myObj, 'val').by(2); // Not recommended - * - * Add `.not` earlier in the chain to negate `.by`. However, it's often best - * to assert that the subject changed by its expected delta, rather than - * asserting that it didn't change by one of countless unexpected deltas. - * - * var myObj = {val: 1} - * , addTwo = function () { myObj.val += 2; }; - * - * // Recommended - * expect(addTwo).to.increase(myObj, 'val').by(2); - * - * // Not recommended - * expect(addTwo).to.increase(myObj, 'val').but.not.by(3); - * - * `.by` accepts an optional `msg` argument which is a custom error message to - * show when the assertion fails. The message can also be given as the second - * argument to `expect`. - * - * var myObj = {val: 1} - * , addTwo = function () { myObj.val += 2; }; - * - * expect(addTwo).to.increase(myObj, 'val').by(3, 'nooo why fail??'); - * expect(addTwo, 'nooo why fail??').to.increase(myObj, 'val').by(3); - * - * @name by - * @param {Number} delta - * @param {String} msg _optional_ - * @namespace BDD - * @api public - */ - - function assertDelta(delta, msg) { - if (msg) flag(this, 'message', msg); - - var msgObj = flag(this, 'deltaMsgObj'); - var initial = flag(this, 'initialDeltaValue'); - var final = flag(this, 'finalDeltaValue'); - var behavior = flag(this, 'deltaBehavior'); - var realDelta = flag(this, 'realDelta'); - - var expression; - if (behavior === 'change') { - expression = Math.abs(final - initial) === Math.abs(delta); - } else { - expression = realDelta === Math.abs(delta); - } - - this.assert( - expression - , 'expected ' + msgObj + ' to ' + behavior + ' by ' + delta - , 'expected ' + msgObj + ' to not ' + behavior + ' by ' + delta - ); - } - - Assertion.addMethod('by', assertDelta); - - /** - * ### .extensible - * - * Asserts that the target is extensible, which means that new properties can - * be added to it. Primitives are never extensible. - * - * expect({a: 1}).to.be.extensible; - * - * Add `.not` earlier in the chain to negate `.extensible`. - * - * var nonExtensibleObject = Object.preventExtensions({}) - * , sealedObject = Object.seal({}) - * , frozenObject = Object.freeze({}); - * - * expect(nonExtensibleObject).to.not.be.extensible; - * expect(sealedObject).to.not.be.extensible; - * expect(frozenObject).to.not.be.extensible; - * expect(1).to.not.be.extensible; - * - * A custom error message can be given as the second argument to `expect`. - * - * expect(1, 'nooo why fail??').to.be.extensible; - * - * @name extensible - * @namespace BDD - * @api public - */ - - Assertion.addProperty('extensible', function() { - var obj = flag(this, 'object'); - - // In ES5, if the argument to this method is a primitive, then it will cause a TypeError. - // In ES6, a non-object argument will be treated as if it was a non-extensible ordinary object, simply return false. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible - // The following provides ES6 behavior for ES5 environments. - - var isExtensible = obj === Object(obj) && Object.isExtensible(obj); - - this.assert( - isExtensible - , 'expected #{this} to be extensible' - , 'expected #{this} to not be extensible' - ); - }); - - /** - * ### .sealed - * - * Asserts that the target is sealed, which means that new properties can't be - * added to it, and its existing properties can't be reconfigured or deleted. - * However, it's possible that its existing properties can still be reassigned - * to different values. Primitives are always sealed. - * - * var sealedObject = Object.seal({}); - * var frozenObject = Object.freeze({}); - * - * expect(sealedObject).to.be.sealed; - * expect(frozenObject).to.be.sealed; - * expect(1).to.be.sealed; - * - * Add `.not` earlier in the chain to negate `.sealed`. - * - * expect({a: 1}).to.not.be.sealed; - * - * A custom error message can be given as the second argument to `expect`. - * - * expect({a: 1}, 'nooo why fail??').to.be.sealed; - * - * @name sealed - * @namespace BDD - * @api public - */ - - Assertion.addProperty('sealed', function() { - var obj = flag(this, 'object'); - - // In ES5, if the argument to this method is a primitive, then it will cause a TypeError. - // In ES6, a non-object argument will be treated as if it was a sealed ordinary object, simply return true. - // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed - // The following provides ES6 behavior for ES5 environments. - - var isSealed = obj === Object(obj) ? Object.isSealed(obj) : true; - - this.assert( - isSealed - , 'expected #{this} to be sealed' - , 'expected #{this} to not be sealed' - ); - }); - - /** - * ### .frozen - * - * Asserts that the target is frozen, which means that new properties can't be - * added to it, and its existing properties can't be reassigned to different - * values, reconfigured, or deleted. Primitives are always frozen. - * - * var frozenObject = Object.freeze({}); - * - * expect(frozenObject).to.be.frozen; - * expect(1).to.be.frozen; - * - * Add `.not` earlier in the chain to negate `.frozen`. - * - * expect({a: 1}).to.not.be.frozen; - * - * A custom error message can be given as the second argument to `expect`. - * - * expect({a: 1}, 'nooo why fail??').to.be.frozen; - * - * @name frozen - * @namespace BDD - * @api public - */ - - Assertion.addProperty('frozen', function() { - var obj = flag(this, 'object'); - - // In ES5, if the argument to this method is a primitive, then it will cause a TypeError. - // In ES6, a non-object argument will be treated as if it was a frozen ordinary object, simply return true. - // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen - // The following provides ES6 behavior for ES5 environments. - - var isFrozen = obj === Object(obj) ? Object.isFrozen(obj) : true; - - this.assert( - isFrozen - , 'expected #{this} to be frozen' - , 'expected #{this} to not be frozen' - ); - }); - - /** - * ### .finite - * - * Asserts that the target is a number, and isn't `NaN` or positive/negative - * `Infinity`. - * - * expect(1).to.be.finite; - * - * Add `.not` earlier in the chain to negate `.finite`. However, it's - * dangerous to do so. The problem is that it creates uncertain expectations - * by asserting that the subject either isn't a number, or that it's `NaN`, or - * that it's positive `Infinity`, or that it's negative `Infinity`. It's often - * best to identify the exact output that's expected, and then write an - * assertion that only accepts that exact output. - * - * When the target isn't expected to be a number, it's often best to assert - * that it's the expected type, rather than asserting that it isn't one of - * many unexpected types. - * - * expect('foo').to.be.a('string'); // Recommended - * expect('foo').to.not.be.finite; // Not recommended - * - * When the target is expected to be `NaN`, it's often best to assert exactly - * that. - * - * expect(NaN).to.be.NaN; // Recommended - * expect(NaN).to.not.be.finite; // Not recommended - * - * When the target is expected to be positive infinity, it's often best to - * assert exactly that. - * - * expect(Infinity).to.equal(Infinity); // Recommended - * expect(Infinity).to.not.be.finite; // Not recommended - * - * When the target is expected to be negative infinity, it's often best to - * assert exactly that. - * - * expect(-Infinity).to.equal(-Infinity); // Recommended - * expect(-Infinity).to.not.be.finite; // Not recommended - * - * A custom error message can be given as the second argument to `expect`. - * - * expect('foo', 'nooo why fail??').to.be.finite; - * - * @name finite - * @namespace BDD - * @api public - */ - - Assertion.addProperty('finite', function(msg) { - var obj = flag(this, 'object'); - - this.assert( - typeof obj === "number" && isFinite(obj) - , 'expected #{this} to be a finite number' - , 'expected #{this} to not be a finite number' - ); - }); -}; - -},{}],6:[function(require,module,exports){ -/*! - * chai - * Copyright(c) 2011-2014 Jake Luer - * MIT Licensed - */ - - -module.exports = function (chai, util) { - - /*! - * Chai dependencies. - */ - - var Assertion = chai.Assertion - , flag = util.flag; - - /*! - * Module export. - */ - - /** - * ### assert(expression, message) - * - * Write your own test expressions. - * - * assert('foo' !== 'bar', 'foo is not bar'); - * assert(Array.isArray([]), 'empty arrays are arrays'); - * - * @param {Mixed} expression to test for truthiness - * @param {String} message to display on error - * @name assert - * @namespace Assert - * @api public - */ - - var assert = chai.assert = function (express, errmsg) { - var test = new Assertion(null, null, chai.assert, true); - test.assert( - express - , errmsg - , '[ negation message unavailable ]' - ); - }; - - /** - * ### .fail(actual, expected, [message], [operator]) - * - * Throw a failure. Node.js `assert` module-compatible. - * - * @name fail - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @param {String} operator - * @namespace Assert - * @api public - */ - - assert.fail = function (actual, expected, message, operator) { - message = message || 'assert.fail()'; - throw new chai.AssertionError(message, { - actual: actual - , expected: expected - , operator: operator - }, assert.fail); - }; - - /** - * ### .isOk(object, [message]) - * - * Asserts that `object` is truthy. - * - * assert.isOk('everything', 'everything is ok'); - * assert.isOk(false, 'this will fail'); - * - * @name isOk - * @alias ok - * @param {Mixed} object to test - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isOk = function (val, msg) { - new Assertion(val, msg, assert.isOk, true).is.ok; - }; - - /** - * ### .isNotOk(object, [message]) - * - * Asserts that `object` is falsy. - * - * assert.isNotOk('everything', 'this will fail'); - * assert.isNotOk(false, 'this will pass'); - * - * @name isNotOk - * @alias notOk - * @param {Mixed} object to test - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotOk = function (val, msg) { - new Assertion(val, msg, assert.isNotOk, true).is.not.ok; - }; - - /** - * ### .equal(actual, expected, [message]) - * - * Asserts non-strict equality (`==`) of `actual` and `expected`. - * - * assert.equal(3, '3', '== coerces values to strings'); - * - * @name equal - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.equal = function (act, exp, msg) { - var test = new Assertion(act, msg, assert.equal, true); - - test.assert( - exp == flag(test, 'object') - , 'expected #{this} to equal #{exp}' - , 'expected #{this} to not equal #{act}' - , exp - , act - , true - ); - }; - - /** - * ### .notEqual(actual, expected, [message]) - * - * Asserts non-strict inequality (`!=`) of `actual` and `expected`. - * - * assert.notEqual(3, 4, 'these numbers are not equal'); - * - * @name notEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notEqual = function (act, exp, msg) { - var test = new Assertion(act, msg, assert.notEqual, true); - - test.assert( - exp != flag(test, 'object') - , 'expected #{this} to not equal #{exp}' - , 'expected #{this} to equal #{act}' - , exp - , act - , true - ); - }; - - /** - * ### .strictEqual(actual, expected, [message]) - * - * Asserts strict equality (`===`) of `actual` and `expected`. - * - * assert.strictEqual(true, true, 'these booleans are strictly equal'); - * - * @name strictEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.strictEqual = function (act, exp, msg) { - new Assertion(act, msg, assert.strictEqual, true).to.equal(exp); - }; - - /** - * ### .notStrictEqual(actual, expected, [message]) - * - * Asserts strict inequality (`!==`) of `actual` and `expected`. - * - * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); - * - * @name notStrictEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notStrictEqual = function (act, exp, msg) { - new Assertion(act, msg, assert.notStrictEqual, true).to.not.equal(exp); - }; - - /** - * ### .deepEqual(actual, expected, [message]) - * - * Asserts that `actual` is deeply equal to `expected`. - * - * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); - * - * @name deepEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @alias deepStrictEqual - * @namespace Assert - * @api public - */ - - assert.deepEqual = assert.deepStrictEqual = function (act, exp, msg) { - new Assertion(act, msg, assert.deepEqual, true).to.eql(exp); - }; - - /** - * ### .notDeepEqual(actual, expected, [message]) - * - * Assert that `actual` is not deeply equal to `expected`. - * - * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); - * - * @name notDeepEqual - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notDeepEqual = function (act, exp, msg) { - new Assertion(act, msg, assert.notDeepEqual, true).to.not.eql(exp); - }; - - /** - * ### .isAbove(valueToCheck, valueToBeAbove, [message]) - * - * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove`. - * - * assert.isAbove(5, 2, '5 is strictly greater than 2'); - * - * @name isAbove - * @param {Mixed} valueToCheck - * @param {Mixed} valueToBeAbove - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isAbove = function (val, abv, msg) { - new Assertion(val, msg, assert.isAbove, true).to.be.above(abv); - }; - - /** - * ### .isAtLeast(valueToCheck, valueToBeAtLeast, [message]) - * - * Asserts `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast`. - * - * assert.isAtLeast(5, 2, '5 is greater or equal to 2'); - * assert.isAtLeast(3, 3, '3 is greater or equal to 3'); - * - * @name isAtLeast - * @param {Mixed} valueToCheck - * @param {Mixed} valueToBeAtLeast - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isAtLeast = function (val, atlst, msg) { - new Assertion(val, msg, assert.isAtLeast, true).to.be.least(atlst); - }; - - /** - * ### .isBelow(valueToCheck, valueToBeBelow, [message]) - * - * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow`. - * - * assert.isBelow(3, 6, '3 is strictly less than 6'); - * - * @name isBelow - * @param {Mixed} valueToCheck - * @param {Mixed} valueToBeBelow - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isBelow = function (val, blw, msg) { - new Assertion(val, msg, assert.isBelow, true).to.be.below(blw); - }; - - /** - * ### .isAtMost(valueToCheck, valueToBeAtMost, [message]) - * - * Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost`. - * - * assert.isAtMost(3, 6, '3 is less than or equal to 6'); - * assert.isAtMost(4, 4, '4 is less than or equal to 4'); - * - * @name isAtMost - * @param {Mixed} valueToCheck - * @param {Mixed} valueToBeAtMost - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isAtMost = function (val, atmst, msg) { - new Assertion(val, msg, assert.isAtMost, true).to.be.most(atmst); - }; - - /** - * ### .isTrue(value, [message]) - * - * Asserts that `value` is true. - * - * var teaServed = true; - * assert.isTrue(teaServed, 'the tea has been served'); - * - * @name isTrue - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isTrue = function (val, msg) { - new Assertion(val, msg, assert.isTrue, true).is['true']; - }; - - /** - * ### .isNotTrue(value, [message]) - * - * Asserts that `value` is not true. - * - * var tea = 'tasty chai'; - * assert.isNotTrue(tea, 'great, time for tea!'); - * - * @name isNotTrue - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotTrue = function (val, msg) { - new Assertion(val, msg, assert.isNotTrue, true).to.not.equal(true); - }; - - /** - * ### .isFalse(value, [message]) - * - * Asserts that `value` is false. - * - * var teaServed = false; - * assert.isFalse(teaServed, 'no tea yet? hmm...'); - * - * @name isFalse - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isFalse = function (val, msg) { - new Assertion(val, msg, assert.isFalse, true).is['false']; - }; - - /** - * ### .isNotFalse(value, [message]) - * - * Asserts that `value` is not false. - * - * var tea = 'tasty chai'; - * assert.isNotFalse(tea, 'great, time for tea!'); - * - * @name isNotFalse - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotFalse = function (val, msg) { - new Assertion(val, msg, assert.isNotFalse, true).to.not.equal(false); - }; - - /** - * ### .isNull(value, [message]) - * - * Asserts that `value` is null. - * - * assert.isNull(err, 'there was no error'); - * - * @name isNull - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNull = function (val, msg) { - new Assertion(val, msg, assert.isNull, true).to.equal(null); - }; - - /** - * ### .isNotNull(value, [message]) - * - * Asserts that `value` is not null. - * - * var tea = 'tasty chai'; - * assert.isNotNull(tea, 'great, time for tea!'); - * - * @name isNotNull - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotNull = function (val, msg) { - new Assertion(val, msg, assert.isNotNull, true).to.not.equal(null); - }; - - /** - * ### .isNaN - * - * Asserts that value is NaN. - * - * assert.isNaN(NaN, 'NaN is NaN'); - * - * @name isNaN - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNaN = function (val, msg) { - new Assertion(val, msg, assert.isNaN, true).to.be.NaN; - }; - - /** - * ### .isNotNaN - * - * Asserts that value is not NaN. - * - * assert.isNotNaN(4, '4 is not NaN'); - * - * @name isNotNaN - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - assert.isNotNaN = function (val, msg) { - new Assertion(val, msg, assert.isNotNaN, true).not.to.be.NaN; - }; - - /** - * ### .exists - * - * Asserts that the target is neither `null` nor `undefined`. - * - * var foo = 'hi'; - * - * assert.exists(foo, 'foo is neither `null` nor `undefined`'); - * - * @name exists - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.exists = function (val, msg) { - new Assertion(val, msg, assert.exists, true).to.exist; - }; - - /** - * ### .notExists - * - * Asserts that the target is either `null` or `undefined`. - * - * var bar = null - * , baz; - * - * assert.notExists(bar); - * assert.notExists(baz, 'baz is either null or undefined'); - * - * @name notExists - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notExists = function (val, msg) { - new Assertion(val, msg, assert.notExists, true).to.not.exist; - }; - - /** - * ### .isUndefined(value, [message]) - * - * Asserts that `value` is `undefined`. - * - * var tea; - * assert.isUndefined(tea, 'no tea defined'); - * - * @name isUndefined - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isUndefined = function (val, msg) { - new Assertion(val, msg, assert.isUndefined, true).to.equal(undefined); - }; - - /** - * ### .isDefined(value, [message]) - * - * Asserts that `value` is not `undefined`. - * - * var tea = 'cup of chai'; - * assert.isDefined(tea, 'tea has been defined'); - * - * @name isDefined - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isDefined = function (val, msg) { - new Assertion(val, msg, assert.isDefined, true).to.not.equal(undefined); - }; - - /** - * ### .isFunction(value, [message]) - * - * Asserts that `value` is a function. - * - * function serveTea() { return 'cup of tea'; }; - * assert.isFunction(serveTea, 'great, we can have tea now'); - * - * @name isFunction - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isFunction = function (val, msg) { - new Assertion(val, msg, assert.isFunction, true).to.be.a('function'); - }; - - /** - * ### .isNotFunction(value, [message]) - * - * Asserts that `value` is _not_ a function. - * - * var serveTea = [ 'heat', 'pour', 'sip' ]; - * assert.isNotFunction(serveTea, 'great, we have listed the steps'); - * - * @name isNotFunction - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotFunction = function (val, msg) { - new Assertion(val, msg, assert.isNotFunction, true).to.not.be.a('function'); - }; - - /** - * ### .isObject(value, [message]) - * - * Asserts that `value` is an object of type 'Object' (as revealed by `Object.prototype.toString`). - * _The assertion does not match subclassed objects._ - * - * var selection = { name: 'Chai', serve: 'with spices' }; - * assert.isObject(selection, 'tea selection is an object'); - * - * @name isObject - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isObject = function (val, msg) { - new Assertion(val, msg, assert.isObject, true).to.be.a('object'); - }; - - /** - * ### .isNotObject(value, [message]) - * - * Asserts that `value` is _not_ an object of type 'Object' (as revealed by `Object.prototype.toString`). - * - * var selection = 'chai' - * assert.isNotObject(selection, 'tea selection is not an object'); - * assert.isNotObject(null, 'null is not an object'); - * - * @name isNotObject - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotObject = function (val, msg) { - new Assertion(val, msg, assert.isNotObject, true).to.not.be.a('object'); - }; - - /** - * ### .isArray(value, [message]) - * - * Asserts that `value` is an array. - * - * var menu = [ 'green', 'chai', 'oolong' ]; - * assert.isArray(menu, 'what kind of tea do we want?'); - * - * @name isArray - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isArray = function (val, msg) { - new Assertion(val, msg, assert.isArray, true).to.be.an('array'); - }; - - /** - * ### .isNotArray(value, [message]) - * - * Asserts that `value` is _not_ an array. - * - * var menu = 'green|chai|oolong'; - * assert.isNotArray(menu, 'what kind of tea do we want?'); - * - * @name isNotArray - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotArray = function (val, msg) { - new Assertion(val, msg, assert.isNotArray, true).to.not.be.an('array'); - }; - - /** - * ### .isString(value, [message]) - * - * Asserts that `value` is a string. - * - * var teaOrder = 'chai'; - * assert.isString(teaOrder, 'order placed'); - * - * @name isString - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isString = function (val, msg) { - new Assertion(val, msg, assert.isString, true).to.be.a('string'); - }; - - /** - * ### .isNotString(value, [message]) - * - * Asserts that `value` is _not_ a string. - * - * var teaOrder = 4; - * assert.isNotString(teaOrder, 'order placed'); - * - * @name isNotString - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotString = function (val, msg) { - new Assertion(val, msg, assert.isNotString, true).to.not.be.a('string'); - }; - - /** - * ### .isNumber(value, [message]) - * - * Asserts that `value` is a number. - * - * var cups = 2; - * assert.isNumber(cups, 'how many cups'); - * - * @name isNumber - * @param {Number} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNumber = function (val, msg) { - new Assertion(val, msg, assert.isNumber, true).to.be.a('number'); - }; - - /** - * ### .isNotNumber(value, [message]) - * - * Asserts that `value` is _not_ a number. - * - * var cups = '2 cups please'; - * assert.isNotNumber(cups, 'how many cups'); - * - * @name isNotNumber - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotNumber = function (val, msg) { - new Assertion(val, msg, assert.isNotNumber, true).to.not.be.a('number'); - }; - - /** - * ### .isFinite(value, [message]) - * - * Asserts that `value` is a finite number. Unlike `.isNumber`, this will fail for `NaN` and `Infinity`. - * - * var cups = 2; - * assert.isFinite(cups, 'how many cups'); - * - * assert.isFinite(NaN); // throws - * - * @name isFinite - * @param {Number} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isFinite = function (val, msg) { - new Assertion(val, msg, assert.isFinite, true).to.be.finite; - }; - - /** - * ### .isBoolean(value, [message]) - * - * Asserts that `value` is a boolean. - * - * var teaReady = true - * , teaServed = false; - * - * assert.isBoolean(teaReady, 'is the tea ready'); - * assert.isBoolean(teaServed, 'has tea been served'); - * - * @name isBoolean - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isBoolean = function (val, msg) { - new Assertion(val, msg, assert.isBoolean, true).to.be.a('boolean'); - }; - - /** - * ### .isNotBoolean(value, [message]) - * - * Asserts that `value` is _not_ a boolean. - * - * var teaReady = 'yep' - * , teaServed = 'nope'; - * - * assert.isNotBoolean(teaReady, 'is the tea ready'); - * assert.isNotBoolean(teaServed, 'has tea been served'); - * - * @name isNotBoolean - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.isNotBoolean = function (val, msg) { - new Assertion(val, msg, assert.isNotBoolean, true).to.not.be.a('boolean'); - }; - - /** - * ### .typeOf(value, name, [message]) - * - * Asserts that `value`'s type is `name`, as determined by - * `Object.prototype.toString`. - * - * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); - * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); - * assert.typeOf('tea', 'string', 'we have a string'); - * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); - * assert.typeOf(null, 'null', 'we have a null'); - * assert.typeOf(undefined, 'undefined', 'we have an undefined'); - * - * @name typeOf - * @param {Mixed} value - * @param {String} name - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.typeOf = function (val, type, msg) { - new Assertion(val, msg, assert.typeOf, true).to.be.a(type); - }; - - /** - * ### .notTypeOf(value, name, [message]) - * - * Asserts that `value`'s type is _not_ `name`, as determined by - * `Object.prototype.toString`. - * - * assert.notTypeOf('tea', 'number', 'strings are not numbers'); - * - * @name notTypeOf - * @param {Mixed} value - * @param {String} typeof name - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notTypeOf = function (val, type, msg) { - new Assertion(val, msg, assert.notTypeOf, true).to.not.be.a(type); - }; - - /** - * ### .instanceOf(object, constructor, [message]) - * - * Asserts that `value` is an instance of `constructor`. - * - * var Tea = function (name) { this.name = name; } - * , chai = new Tea('chai'); - * - * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); - * - * @name instanceOf - * @param {Object} object - * @param {Constructor} constructor - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.instanceOf = function (val, type, msg) { - new Assertion(val, msg, assert.instanceOf, true).to.be.instanceOf(type); - }; - - /** - * ### .notInstanceOf(object, constructor, [message]) - * - * Asserts `value` is not an instance of `constructor`. - * - * var Tea = function (name) { this.name = name; } - * , chai = new String('chai'); - * - * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); - * - * @name notInstanceOf - * @param {Object} object - * @param {Constructor} constructor - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notInstanceOf = function (val, type, msg) { - new Assertion(val, msg, assert.notInstanceOf, true) - .to.not.be.instanceOf(type); - }; - - /** - * ### .include(haystack, needle, [message]) - * - * Asserts that `haystack` includes `needle`. Can be used to assert the - * inclusion of a value in an array, a substring in a string, or a subset of - * properties in an object. - * - * assert.include([1,2,3], 2, 'array contains value'); - * assert.include('foobar', 'foo', 'string contains substring'); - * assert.include({ foo: 'bar', hello: 'universe' }, { foo: 'bar' }, 'object contains property'); - * - * Strict equality (===) is used. When asserting the inclusion of a value in - * an array, the array is searched for an element that's strictly equal to the - * given value. When asserting a subset of properties in an object, the object - * is searched for the given property keys, checking that each one is present - * and stricty equal to the given property value. For instance: - * - * var obj1 = {a: 1} - * , obj2 = {b: 2}; - * assert.include([obj1, obj2], obj1); - * assert.include({foo: obj1, bar: obj2}, {foo: obj1}); - * assert.include({foo: obj1, bar: obj2}, {foo: obj1, bar: obj2}); - * - * @name include - * @param {Array|String} haystack - * @param {Mixed} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.include = function (exp, inc, msg) { - new Assertion(exp, msg, assert.include, true).include(inc); - }; - - /** - * ### .notInclude(haystack, needle, [message]) - * - * Asserts that `haystack` does not include `needle`. Can be used to assert - * the absence of a value in an array, a substring in a string, or a subset of - * properties in an object. - * - * assert.notInclude([1,2,3], 4, 'array doesn't contain value'); - * assert.notInclude('foobar', 'baz', 'string doesn't contain substring'); - * assert.notInclude({ foo: 'bar', hello: 'universe' }, { foo: 'baz' }, 'object doesn't contain property'); - * - * Strict equality (===) is used. When asserting the absence of a value in an - * array, the array is searched to confirm the absence of an element that's - * strictly equal to the given value. When asserting a subset of properties in - * an object, the object is searched to confirm that at least one of the given - * property keys is either not present or not strictly equal to the given - * property value. For instance: - * - * var obj1 = {a: 1} - * , obj2 = {b: 2}; - * assert.notInclude([obj1, obj2], {a: 1}); - * assert.notInclude({foo: obj1, bar: obj2}, {foo: {a: 1}}); - * assert.notInclude({foo: obj1, bar: obj2}, {foo: obj1, bar: {b: 2}}); - * - * @name notInclude - * @param {Array|String} haystack - * @param {Mixed} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notInclude = function (exp, inc, msg) { - new Assertion(exp, msg, assert.notInclude, true).not.include(inc); - }; - - /** - * ### .deepInclude(haystack, needle, [message]) - * - * Asserts that `haystack` includes `needle`. Can be used to assert the - * inclusion of a value in an array or a subset of properties in an object. - * Deep equality is used. - * - * var obj1 = {a: 1} - * , obj2 = {b: 2}; - * assert.deepInclude([obj1, obj2], {a: 1}); - * assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}}); - * assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 2}}); - * - * @name deepInclude - * @param {Array|String} haystack - * @param {Mixed} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.deepInclude = function (exp, inc, msg) { - new Assertion(exp, msg, assert.deepInclude, true).deep.include(inc); - }; - - /** - * ### .notDeepInclude(haystack, needle, [message]) - * - * Asserts that `haystack` does not include `needle`. Can be used to assert - * the absence of a value in an array or a subset of properties in an object. - * Deep equality is used. - * - * var obj1 = {a: 1} - * , obj2 = {b: 2}; - * assert.notDeepInclude([obj1, obj2], {a: 9}); - * assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 9}}); - * assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 9}}); - * - * @name notDeepInclude - * @param {Array|String} haystack - * @param {Mixed} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notDeepInclude = function (exp, inc, msg) { - new Assertion(exp, msg, assert.notDeepInclude, true).not.deep.include(inc); - }; - - /** - * ### .nestedInclude(haystack, needle, [message]) - * - * Asserts that 'haystack' includes 'needle'. - * Can be used to assert the inclusion of a subset of properties in an - * object. - * Enables the use of dot- and bracket-notation for referencing nested - * properties. - * '[]' and '.' in property names can be escaped using double backslashes. - * - * assert.nestedInclude({'.a': {'b': 'x'}}, {'\\.a.[b]': 'x'}); - * assert.nestedInclude({'a': {'[b]': 'x'}}, {'a.\\[b\\]': 'x'}); - * - * @name nestedInclude - * @param {Object} haystack - * @param {Object} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.nestedInclude = function (exp, inc, msg) { - new Assertion(exp, msg, assert.nestedInclude, true).nested.include(inc); - }; - - /** - * ### .notNestedInclude(haystack, needle, [message]) - * - * Asserts that 'haystack' does not include 'needle'. - * Can be used to assert the absence of a subset of properties in an - * object. - * Enables the use of dot- and bracket-notation for referencing nested - * properties. - * '[]' and '.' in property names can be escaped using double backslashes. - * - * assert.notNestedInclude({'.a': {'b': 'x'}}, {'\\.a.b': 'y'}); - * assert.notNestedInclude({'a': {'[b]': 'x'}}, {'a.\\[b\\]': 'y'}); - * - * @name notNestedInclude - * @param {Object} haystack - * @param {Object} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notNestedInclude = function (exp, inc, msg) { - new Assertion(exp, msg, assert.notNestedInclude, true) - .not.nested.include(inc); - }; - - /** - * ### .deepNestedInclude(haystack, needle, [message]) - * - * Asserts that 'haystack' includes 'needle'. - * Can be used to assert the inclusion of a subset of properties in an - * object while checking for deep equality. - * Enables the use of dot- and bracket-notation for referencing nested - * properties. - * '[]' and '.' in property names can be escaped using double backslashes. - * - * assert.deepNestedInclude({a: {b: [{x: 1}]}}, {'a.b[0]': {x: 1}}); - * assert.deepNestedInclude({'.a': {'[b]': {x: 1}}}, {'\\.a.\\[b\\]': {x: 1}}); - * - * @name deepNestedInclude - * @param {Object} haystack - * @param {Object} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.deepNestedInclude = function(exp, inc, msg) { - new Assertion(exp, msg, assert.deepNestedInclude, true) - .deep.nested.include(inc); - }; - - /** - * ### .notDeepNestedInclude(haystack, needle, [message]) - * - * Asserts that 'haystack' does not include 'needle'. - * Can be used to assert the absence of a subset of properties in an - * object while checking for deep equality. - * Enables the use of dot- and bracket-notation for referencing nested - * properties. - * '[]' and '.' in property names can be escaped using double backslashes. - * - * assert.notDeepNestedInclude({a: {b: [{x: 1}]}}, {'a.b[0]': {y: 1}}) - * assert.notDeepNestedInclude({'.a': {'[b]': {x: 1}}}, {'\\.a.\\[b\\]': {y: 2}}); - * - * @name notDeepNestedInclude - * @param {Object} haystack - * @param {Object} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notDeepNestedInclude = function(exp, inc, msg) { - new Assertion(exp, msg, assert.notDeepNestedInclude, true) - .not.deep.nested.include(inc); - }; - - /** - * ### .ownInclude(haystack, needle, [message]) - * - * Asserts that 'haystack' includes 'needle'. - * Can be used to assert the inclusion of a subset of properties in an - * object while ignoring inherited properties. - * - * assert.ownInclude({ a: 1 }, { a: 1 }); - * - * @name ownInclude - * @param {Object} haystack - * @param {Object} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.ownInclude = function(exp, inc, msg) { - new Assertion(exp, msg, assert.ownInclude, true).own.include(inc); - }; - - /** - * ### .notOwnInclude(haystack, needle, [message]) - * - * Asserts that 'haystack' includes 'needle'. - * Can be used to assert the absence of a subset of properties in an - * object while ignoring inherited properties. - * - * Object.prototype.b = 2; - * - * assert.notOwnInclude({ a: 1 }, { b: 2 }); - * - * @name notOwnInclude - * @param {Object} haystack - * @param {Object} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notOwnInclude = function(exp, inc, msg) { - new Assertion(exp, msg, assert.notOwnInclude, true).not.own.include(inc); - }; - - /** - * ### .deepOwnInclude(haystack, needle, [message]) - * - * Asserts that 'haystack' includes 'needle'. - * Can be used to assert the inclusion of a subset of properties in an - * object while ignoring inherited properties and checking for deep equality. - * - * assert.deepOwnInclude({a: {b: 2}}, {a: {b: 2}}); - * - * @name deepOwnInclude - * @param {Object} haystack - * @param {Object} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.deepOwnInclude = function(exp, inc, msg) { - new Assertion(exp, msg, assert.deepOwnInclude, true) - .deep.own.include(inc); - }; - - /** - * ### .notDeepOwnInclude(haystack, needle, [message]) - * - * Asserts that 'haystack' includes 'needle'. - * Can be used to assert the absence of a subset of properties in an - * object while ignoring inherited properties and checking for deep equality. - * - * assert.notDeepOwnInclude({a: {b: 2}}, {a: {c: 3}}); - * - * @name notDeepOwnInclude - * @param {Object} haystack - * @param {Object} needle - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notDeepOwnInclude = function(exp, inc, msg) { - new Assertion(exp, msg, assert.notDeepOwnInclude, true) - .not.deep.own.include(inc); - }; - - /** - * ### .match(value, regexp, [message]) - * - * Asserts that `value` matches the regular expression `regexp`. - * - * assert.match('foobar', /^foo/, 'regexp matches'); - * - * @name match - * @param {Mixed} value - * @param {RegExp} regexp - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.match = function (exp, re, msg) { - new Assertion(exp, msg, assert.match, true).to.match(re); - }; - - /** - * ### .notMatch(value, regexp, [message]) - * - * Asserts that `value` does not match the regular expression `regexp`. - * - * assert.notMatch('foobar', /^foo/, 'regexp does not match'); - * - * @name notMatch - * @param {Mixed} value - * @param {RegExp} regexp - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notMatch = function (exp, re, msg) { - new Assertion(exp, msg, assert.notMatch, true).to.not.match(re); - }; - - /** - * ### .property(object, property, [message]) - * - * Asserts that `object` has a direct or inherited property named by - * `property`. - * - * assert.property({ tea: { green: 'matcha' }}, 'tea'); - * assert.property({ tea: { green: 'matcha' }}, 'toString'); - * - * @name property - * @param {Object} object - * @param {String} property - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.property = function (obj, prop, msg) { - new Assertion(obj, msg, assert.property, true).to.have.property(prop); - }; - - /** - * ### .notProperty(object, property, [message]) - * - * Asserts that `object` does _not_ have a direct or inherited property named - * by `property`. - * - * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); - * - * @name notProperty - * @param {Object} object - * @param {String} property - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notProperty = function (obj, prop, msg) { - new Assertion(obj, msg, assert.notProperty, true) - .to.not.have.property(prop); - }; - - /** - * ### .propertyVal(object, property, value, [message]) - * - * Asserts that `object` has a direct or inherited property named by - * `property` with a value given by `value`. Uses a strict equality check - * (===). - * - * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); - * - * @name propertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.propertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg, assert.propertyVal, true) - .to.have.property(prop, val); - }; - - /** - * ### .notPropertyVal(object, property, value, [message]) - * - * Asserts that `object` does _not_ have a direct or inherited property named - * by `property` with value given by `value`. Uses a strict equality check - * (===). - * - * assert.notPropertyVal({ tea: 'is good' }, 'tea', 'is bad'); - * assert.notPropertyVal({ tea: 'is good' }, 'coffee', 'is good'); - * - * @name notPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notPropertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg, assert.notPropertyVal, true) - .to.not.have.property(prop, val); - }; - - /** - * ### .deepPropertyVal(object, property, value, [message]) - * - * Asserts that `object` has a direct or inherited property named by - * `property` with a value given by `value`. Uses a deep equality check. - * - * assert.deepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' }); - * - * @name deepPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.deepPropertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg, assert.deepPropertyVal, true) - .to.have.deep.property(prop, val); - }; - - /** - * ### .notDeepPropertyVal(object, property, value, [message]) - * - * Asserts that `object` does _not_ have a direct or inherited property named - * by `property` with value given by `value`. Uses a deep equality check. - * - * assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' }); - * assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' }); - * assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' }); - * - * @name notDeepPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notDeepPropertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg, assert.notDeepPropertyVal, true) - .to.not.have.deep.property(prop, val); - }; - - /** - * ### .ownProperty(object, property, [message]) - * - * Asserts that `object` has a direct property named by `property`. Inherited - * properties aren't checked. - * - * assert.ownProperty({ tea: { green: 'matcha' }}, 'tea'); - * - * @name ownProperty - * @param {Object} object - * @param {String} property - * @param {String} message - * @api public - */ - - assert.ownProperty = function (obj, prop, msg) { - new Assertion(obj, msg, assert.ownProperty, true) - .to.have.own.property(prop); - }; - - /** - * ### .notOwnProperty(object, property, [message]) - * - * Asserts that `object` does _not_ have a direct property named by - * `property`. Inherited properties aren't checked. - * - * assert.notOwnProperty({ tea: { green: 'matcha' }}, 'coffee'); - * assert.notOwnProperty({}, 'toString'); - * - * @name notOwnProperty - * @param {Object} object - * @param {String} property - * @param {String} message - * @api public - */ - - assert.notOwnProperty = function (obj, prop, msg) { - new Assertion(obj, msg, assert.notOwnProperty, true) - .to.not.have.own.property(prop); - }; - - /** - * ### .ownPropertyVal(object, property, value, [message]) - * - * Asserts that `object` has a direct property named by `property` and a value - * equal to the provided `value`. Uses a strict equality check (===). - * Inherited properties aren't checked. - * - * assert.ownPropertyVal({ coffee: 'is good'}, 'coffee', 'is good'); - * - * @name ownPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.ownPropertyVal = function (obj, prop, value, msg) { - new Assertion(obj, msg, assert.ownPropertyVal, true) - .to.have.own.property(prop, value); - }; - - /** - * ### .notOwnPropertyVal(object, property, value, [message]) - * - * Asserts that `object` does _not_ have a direct property named by `property` - * with a value equal to the provided `value`. Uses a strict equality check - * (===). Inherited properties aren't checked. - * - * assert.notOwnPropertyVal({ tea: 'is better'}, 'tea', 'is worse'); - * assert.notOwnPropertyVal({}, 'toString', Object.prototype.toString); - * - * @name notOwnPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.notOwnPropertyVal = function (obj, prop, value, msg) { - new Assertion(obj, msg, assert.notOwnPropertyVal, true) - .to.not.have.own.property(prop, value); - }; - - /** - * ### .deepOwnPropertyVal(object, property, value, [message]) - * - * Asserts that `object` has a direct property named by `property` and a value - * equal to the provided `value`. Uses a deep equality check. Inherited - * properties aren't checked. - * - * assert.deepOwnPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' }); - * - * @name deepOwnPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.deepOwnPropertyVal = function (obj, prop, value, msg) { - new Assertion(obj, msg, assert.deepOwnPropertyVal, true) - .to.have.deep.own.property(prop, value); - }; - - /** - * ### .notDeepOwnPropertyVal(object, property, value, [message]) - * - * Asserts that `object` does _not_ have a direct property named by `property` - * with a value equal to the provided `value`. Uses a deep equality check. - * Inherited properties aren't checked. - * - * assert.notDeepOwnPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' }); - * assert.notDeepOwnPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' }); - * assert.notDeepOwnPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' }); - * assert.notDeepOwnPropertyVal({}, 'toString', Object.prototype.toString); - * - * @name notDeepOwnPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @api public - */ - - assert.notDeepOwnPropertyVal = function (obj, prop, value, msg) { - new Assertion(obj, msg, assert.notDeepOwnPropertyVal, true) - .to.not.have.deep.own.property(prop, value); - }; - - /** - * ### .nestedProperty(object, property, [message]) - * - * Asserts that `object` has a direct or inherited property named by - * `property`, which can be a string using dot- and bracket-notation for - * nested reference. - * - * assert.nestedProperty({ tea: { green: 'matcha' }}, 'tea.green'); - * - * @name nestedProperty - * @param {Object} object - * @param {String} property - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.nestedProperty = function (obj, prop, msg) { - new Assertion(obj, msg, assert.nestedProperty, true) - .to.have.nested.property(prop); - }; - - /** - * ### .notNestedProperty(object, property, [message]) - * - * Asserts that `object` does _not_ have a property named by `property`, which - * can be a string using dot- and bracket-notation for nested reference. The - * property cannot exist on the object nor anywhere in its prototype chain. - * - * assert.notNestedProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); - * - * @name notNestedProperty - * @param {Object} object - * @param {String} property - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notNestedProperty = function (obj, prop, msg) { - new Assertion(obj, msg, assert.notNestedProperty, true) - .to.not.have.nested.property(prop); - }; - - /** - * ### .nestedPropertyVal(object, property, value, [message]) - * - * Asserts that `object` has a property named by `property` with value given - * by `value`. `property` can use dot- and bracket-notation for nested - * reference. Uses a strict equality check (===). - * - * assert.nestedPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); - * - * @name nestedPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.nestedPropertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg, assert.nestedPropertyVal, true) - .to.have.nested.property(prop, val); - }; - - /** - * ### .notNestedPropertyVal(object, property, value, [message]) - * - * Asserts that `object` does _not_ have a property named by `property` with - * value given by `value`. `property` can use dot- and bracket-notation for - * nested reference. Uses a strict equality check (===). - * - * assert.notNestedPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); - * assert.notNestedPropertyVal({ tea: { green: 'matcha' }}, 'coffee.green', 'matcha'); - * - * @name notNestedPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notNestedPropertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg, assert.notNestedPropertyVal, true) - .to.not.have.nested.property(prop, val); - }; - - /** - * ### .deepNestedPropertyVal(object, property, value, [message]) - * - * Asserts that `object` has a property named by `property` with a value given - * by `value`. `property` can use dot- and bracket-notation for nested - * reference. Uses a deep equality check. - * - * assert.deepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yum' }); - * - * @name deepNestedPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.deepNestedPropertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg, assert.deepNestedPropertyVal, true) - .to.have.deep.nested.property(prop, val); - }; - - /** - * ### .notDeepNestedPropertyVal(object, property, value, [message]) - * - * Asserts that `object` does _not_ have a property named by `property` with - * value given by `value`. `property` can use dot- and bracket-notation for - * nested reference. Uses a deep equality check. - * - * assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { oolong: 'yum' }); - * assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yuck' }); - * assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.black', { matcha: 'yum' }); - * - * @name notDeepNestedPropertyVal - * @param {Object} object - * @param {String} property - * @param {Mixed} value - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notDeepNestedPropertyVal = function (obj, prop, val, msg) { - new Assertion(obj, msg, assert.notDeepNestedPropertyVal, true) - .to.not.have.deep.nested.property(prop, val); - } - - /** - * ### .lengthOf(object, length, [message]) - * - * Asserts that `object` has a `length` property with the expected value. - * - * assert.lengthOf([1,2,3], 3, 'array has length of 3'); - * assert.lengthOf('foobar', 6, 'string has length of 6'); - * - * @name lengthOf - * @param {Mixed} object - * @param {Number} length - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.lengthOf = function (exp, len, msg) { - new Assertion(exp, msg, assert.lengthOf, true).to.have.lengthOf(len); - }; - - /** - * ### .hasAnyKeys(object, [keys], [message]) - * - * Asserts that `object` has at least one of the `keys` provided. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.hasAnyKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'iDontExist', 'baz']); - * assert.hasAnyKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, iDontExist: 99, baz: 1337}); - * assert.hasAnyKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']); - * assert.hasAnyKeys(new Set([{foo: 'bar'}, 'anotherKey']), [{foo: 'bar'}, 'anotherKey']); - * - * @name hasAnyKeys - * @param {Mixed} object - * @param {Array|Object} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.hasAnyKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.hasAnyKeys, true).to.have.any.keys(keys); - } - - /** - * ### .hasAllKeys(object, [keys], [message]) - * - * Asserts that `object` has all and only all of the `keys` provided. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.hasAllKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'bar', 'baz']); - * assert.hasAllKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, bar: 99, baz: 1337]); - * assert.hasAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']); - * assert.hasAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}, 'anotherKey']); - * - * @name hasAllKeys - * @param {Mixed} object - * @param {String[]} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.hasAllKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.hasAllKeys, true).to.have.all.keys(keys); - } - - /** - * ### .containsAllKeys(object, [keys], [message]) - * - * Asserts that `object` has all of the `keys` provided but may have more keys not listed. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'baz']); - * assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'bar', 'baz']); - * assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, baz: 1337}); - * assert.containsAllKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, bar: 99, baz: 1337}); - * assert.containsAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}]); - * assert.containsAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']); - * assert.containsAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}]); - * assert.containsAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}, 'anotherKey']); - * - * @name containsAllKeys - * @param {Mixed} object - * @param {String[]} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.containsAllKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.containsAllKeys, true) - .to.contain.all.keys(keys); - } - - /** - * ### .doesNotHaveAnyKeys(object, [keys], [message]) - * - * Asserts that `object` has none of the `keys` provided. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.doesNotHaveAnyKeys({foo: 1, bar: 2, baz: 3}, ['one', 'two', 'example']); - * assert.doesNotHaveAnyKeys({foo: 1, bar: 2, baz: 3}, {one: 1, two: 2, example: 'foo'}); - * assert.doesNotHaveAnyKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{one: 'two'}, 'example']); - * assert.doesNotHaveAnyKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{one: 'two'}, 'example']); - * - * @name doesNotHaveAnyKeys - * @param {Mixed} object - * @param {String[]} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.doesNotHaveAnyKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.doesNotHaveAnyKeys, true) - .to.not.have.any.keys(keys); - } - - /** - * ### .doesNotHaveAllKeys(object, [keys], [message]) - * - * Asserts that `object` does not have at least one of the `keys` provided. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.doesNotHaveAllKeys({foo: 1, bar: 2, baz: 3}, ['one', 'two', 'example']); - * assert.doesNotHaveAllKeys({foo: 1, bar: 2, baz: 3}, {one: 1, two: 2, example: 'foo'}); - * assert.doesNotHaveAllKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{one: 'two'}, 'example']); - * assert.doesNotHaveAllKeys(new Set([{foo: 'bar'}, 'anotherKey'], [{one: 'two'}, 'example']); - * - * @name doesNotHaveAllKeys - * @param {Mixed} object - * @param {String[]} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.doesNotHaveAllKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.doesNotHaveAllKeys, true) - .to.not.have.all.keys(keys); - } - - /** - * ### .hasAnyDeepKeys(object, [keys], [message]) - * - * Asserts that `object` has at least one of the `keys` provided. - * Since Sets and Maps can have objects as keys you can use this assertion to perform - * a deep comparison. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {one: 'one'}); - * assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), [{one: 'one'}, {two: 'two'}]); - * assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]); - * assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {one: 'one'}); - * assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {three: 'three'}]); - * assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]); - * - * @name doesNotHaveAllKeys - * @param {Mixed} object - * @param {Array|Object} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.hasAnyDeepKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.hasAnyDeepKeys, true) - .to.have.any.deep.keys(keys); - } - - /** - * ### .hasAllDeepKeys(object, [keys], [message]) - * - * Asserts that `object` has all and only all of the `keys` provided. - * Since Sets and Maps can have objects as keys you can use this assertion to perform - * a deep comparison. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.hasAllDeepKeys(new Map([[{one: 'one'}, 'valueOne']]), {one: 'one'}); - * assert.hasAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]); - * assert.hasAllDeepKeys(new Set([{one: 'one'}]), {one: 'one'}); - * assert.hasAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]); - * - * @name hasAllDeepKeys - * @param {Mixed} object - * @param {Array|Object} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.hasAllDeepKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.hasAllDeepKeys, true) - .to.have.all.deep.keys(keys); - } - - /** - * ### .containsAllDeepKeys(object, [keys], [message]) - * - * Asserts that `object` contains all of the `keys` provided. - * Since Sets and Maps can have objects as keys you can use this assertion to perform - * a deep comparison. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.containsAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {one: 'one'}); - * assert.containsAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]); - * assert.containsAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {one: 'one'}); - * assert.containsAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]); - * - * @name containsAllDeepKeys - * @param {Mixed} object - * @param {Array|Object} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.containsAllDeepKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.containsAllDeepKeys, true) - .to.contain.all.deep.keys(keys); - } - - /** - * ### .doesNotHaveAnyDeepKeys(object, [keys], [message]) - * - * Asserts that `object` has none of the `keys` provided. - * Since Sets and Maps can have objects as keys you can use this assertion to perform - * a deep comparison. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.doesNotHaveAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {thisDoesNot: 'exist'}); - * assert.doesNotHaveAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{twenty: 'twenty'}, {fifty: 'fifty'}]); - * assert.doesNotHaveAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {twenty: 'twenty'}); - * assert.doesNotHaveAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{twenty: 'twenty'}, {fifty: 'fifty'}]); - * - * @name doesNotHaveAnyDeepKeys - * @param {Mixed} object - * @param {Array|Object} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.doesNotHaveAnyDeepKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.doesNotHaveAnyDeepKeys, true) - .to.not.have.any.deep.keys(keys); - } - - /** - * ### .doesNotHaveAllDeepKeys(object, [keys], [message]) - * - * Asserts that `object` does not have at least one of the `keys` provided. - * Since Sets and Maps can have objects as keys you can use this assertion to perform - * a deep comparison. - * You can also provide a single object instead of a `keys` array and its keys - * will be used as the expected set of keys. - * - * assert.doesNotHaveAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {thisDoesNot: 'exist'}); - * assert.doesNotHaveAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{twenty: 'twenty'}, {one: 'one'}]); - * assert.doesNotHaveAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {twenty: 'twenty'}); - * assert.doesNotHaveAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {fifty: 'fifty'}]); - * - * @name doesNotHaveAllDeepKeys - * @param {Mixed} object - * @param {Array|Object} keys - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.doesNotHaveAllDeepKeys = function (obj, keys, msg) { - new Assertion(obj, msg, assert.doesNotHaveAllDeepKeys, true) - .to.not.have.all.deep.keys(keys); - } - - /** - * ### .throws(fn, [errorLike/string/regexp], [string/regexp], [message]) - * - * If `errorLike` is an `Error` constructor, asserts that `fn` will throw an error that is an - * instance of `errorLike`. - * If `errorLike` is an `Error` instance, asserts that the error thrown is the same - * instance as `errorLike`. - * If `errMsgMatcher` is provided, it also asserts that the error thrown will have a - * message matching `errMsgMatcher`. - * - * assert.throws(fn, 'function throws a reference error'); - * assert.throws(fn, /function throws a reference error/); - * assert.throws(fn, ReferenceError); - * assert.throws(fn, errorInstance); - * assert.throws(fn, ReferenceError, 'Error thrown must be a ReferenceError and have this msg'); - * assert.throws(fn, errorInstance, 'Error thrown must be the same errorInstance and have this msg'); - * assert.throws(fn, ReferenceError, /Error thrown must be a ReferenceError and match this/); - * assert.throws(fn, errorInstance, /Error thrown must be the same errorInstance and match this/); - * - * @name throws - * @alias throw - * @alias Throw - * @param {Function} fn - * @param {ErrorConstructor|Error} errorLike - * @param {RegExp|String} errMsgMatcher - * @param {String} message - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types - * @namespace Assert - * @api public - */ - - assert.throws = function (fn, errorLike, errMsgMatcher, msg) { - if ('string' === typeof errorLike || errorLike instanceof RegExp) { - errMsgMatcher = errorLike; - errorLike = null; - } - - var assertErr = new Assertion(fn, msg, assert.throws, true) - .to.throw(errorLike, errMsgMatcher); - return flag(assertErr, 'object'); - }; - - /** - * ### .doesNotThrow(fn, [errorLike/string/regexp], [string/regexp], [message]) - * - * If `errorLike` is an `Error` constructor, asserts that `fn` will _not_ throw an error that is an - * instance of `errorLike`. - * If `errorLike` is an `Error` instance, asserts that the error thrown is _not_ the same - * instance as `errorLike`. - * If `errMsgMatcher` is provided, it also asserts that the error thrown will _not_ have a - * message matching `errMsgMatcher`. - * - * assert.doesNotThrow(fn, 'Any Error thrown must not have this message'); - * assert.doesNotThrow(fn, /Any Error thrown must not match this/); - * assert.doesNotThrow(fn, Error); - * assert.doesNotThrow(fn, errorInstance); - * assert.doesNotThrow(fn, Error, 'Error must not have this message'); - * assert.doesNotThrow(fn, errorInstance, 'Error must not have this message'); - * assert.doesNotThrow(fn, Error, /Error must not match this/); - * assert.doesNotThrow(fn, errorInstance, /Error must not match this/); - * - * @name doesNotThrow - * @param {Function} fn - * @param {ErrorConstructor} errorLike - * @param {RegExp|String} errMsgMatcher - * @param {String} message - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types - * @namespace Assert - * @api public - */ - - assert.doesNotThrow = function (fn, errorLike, errMsgMatcher, msg) { - if ('string' === typeof errorLike || errorLike instanceof RegExp) { - errMsgMatcher = errorLike; - errorLike = null; - } - - new Assertion(fn, msg, assert.doesNotThrow, true) - .to.not.throw(errorLike, errMsgMatcher); - }; - - /** - * ### .operator(val1, operator, val2, [message]) - * - * Compares two values using `operator`. - * - * assert.operator(1, '<', 2, 'everything is ok'); - * assert.operator(1, '>', 2, 'this will fail'); - * - * @name operator - * @param {Mixed} val1 - * @param {String} operator - * @param {Mixed} val2 - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.operator = function (val, operator, val2, msg) { - var ok; - switch(operator) { - case '==': - ok = val == val2; - break; - case '===': - ok = val === val2; - break; - case '>': - ok = val > val2; - break; - case '>=': - ok = val >= val2; - break; - case '<': - ok = val < val2; - break; - case '<=': - ok = val <= val2; - break; - case '!=': - ok = val != val2; - break; - case '!==': - ok = val !== val2; - break; - default: - msg = msg ? msg + ': ' : msg; - throw new chai.AssertionError( - msg + 'Invalid operator "' + operator + '"', - undefined, - assert.operator - ); - } - var test = new Assertion(ok, msg, assert.operator, true); - test.assert( - true === flag(test, 'object') - , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) - , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); - }; - - /** - * ### .closeTo(actual, expected, delta, [message]) - * - * Asserts that the target is equal `expected`, to within a +/- `delta` range. - * - * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); - * - * @name closeTo - * @param {Number} actual - * @param {Number} expected - * @param {Number} delta - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.closeTo = function (act, exp, delta, msg) { - new Assertion(act, msg, assert.closeTo, true).to.be.closeTo(exp, delta); - }; - - /** - * ### .approximately(actual, expected, delta, [message]) - * - * Asserts that the target is equal `expected`, to within a +/- `delta` range. - * - * assert.approximately(1.5, 1, 0.5, 'numbers are close'); - * - * @name approximately - * @param {Number} actual - * @param {Number} expected - * @param {Number} delta - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.approximately = function (act, exp, delta, msg) { - new Assertion(act, msg, assert.approximately, true) - .to.be.approximately(exp, delta); - }; - - /** - * ### .sameMembers(set1, set2, [message]) - * - * Asserts that `set1` and `set2` have the same members in any order. Uses a - * strict equality check (===). - * - * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); - * - * @name sameMembers - * @param {Array} set1 - * @param {Array} set2 - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.sameMembers = function (set1, set2, msg) { - new Assertion(set1, msg, assert.sameMembers, true) - .to.have.same.members(set2); - } - - /** - * ### .notSameMembers(set1, set2, [message]) - * - * Asserts that `set1` and `set2` don't have the same members in any order. - * Uses a strict equality check (===). - * - * assert.notSameMembers([ 1, 2, 3 ], [ 5, 1, 3 ], 'not same members'); - * - * @name notSameMembers - * @param {Array} set1 - * @param {Array} set2 - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notSameMembers = function (set1, set2, msg) { - new Assertion(set1, msg, assert.notSameMembers, true) - .to.not.have.same.members(set2); - } - - /** - * ### .sameDeepMembers(set1, set2, [message]) - * - * Asserts that `set1` and `set2` have the same members in any order. Uses a - * deep equality check. - * - * assert.sameDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [{ b: 2 }, { a: 1 }, { c: 3 }], 'same deep members'); - * - * @name sameDeepMembers - * @param {Array} set1 - * @param {Array} set2 - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.sameDeepMembers = function (set1, set2, msg) { - new Assertion(set1, msg, assert.sameDeepMembers, true) - .to.have.same.deep.members(set2); - } - - /** - * ### .notSameDeepMembers(set1, set2, [message]) - * - * Asserts that `set1` and `set2` don't have the same members in any order. - * Uses a deep equality check. - * - * assert.notSameDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [{ b: 2 }, { a: 1 }, { f: 5 }], 'not same deep members'); - * - * @name notSameDeepMembers - * @param {Array} set1 - * @param {Array} set2 - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notSameDeepMembers = function (set1, set2, msg) { - new Assertion(set1, msg, assert.notSameDeepMembers, true) - .to.not.have.same.deep.members(set2); - } - - /** - * ### .sameOrderedMembers(set1, set2, [message]) - * - * Asserts that `set1` and `set2` have the same members in the same order. - * Uses a strict equality check (===). - * - * assert.sameOrderedMembers([ 1, 2, 3 ], [ 1, 2, 3 ], 'same ordered members'); - * - * @name sameOrderedMembers - * @param {Array} set1 - * @param {Array} set2 - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.sameOrderedMembers = function (set1, set2, msg) { - new Assertion(set1, msg, assert.sameOrderedMembers, true) - .to.have.same.ordered.members(set2); - } - - /** - * ### .notSameOrderedMembers(set1, set2, [message]) - * - * Asserts that `set1` and `set2` don't have the same members in the same - * order. Uses a strict equality check (===). - * - * assert.notSameOrderedMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'not same ordered members'); - * - * @name notSameOrderedMembers - * @param {Array} set1 - * @param {Array} set2 - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notSameOrderedMembers = function (set1, set2, msg) { - new Assertion(set1, msg, assert.notSameOrderedMembers, true) - .to.not.have.same.ordered.members(set2); - } - - /** - * ### .sameDeepOrderedMembers(set1, set2, [message]) - * - * Asserts that `set1` and `set2` have the same members in the same order. - * Uses a deep equality check. - * - * assert.sameDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { b: 2 }, { c: 3 } ], 'same deep ordered members'); - * - * @name sameDeepOrderedMembers - * @param {Array} set1 - * @param {Array} set2 - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.sameDeepOrderedMembers = function (set1, set2, msg) { - new Assertion(set1, msg, assert.sameDeepOrderedMembers, true) - .to.have.same.deep.ordered.members(set2); - } - - /** - * ### .notSameDeepOrderedMembers(set1, set2, [message]) - * - * Asserts that `set1` and `set2` don't have the same members in the same - * order. Uses a deep equality check. - * - * assert.notSameDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { b: 2 }, { z: 5 } ], 'not same deep ordered members'); - * assert.notSameDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { a: 1 }, { c: 3 } ], 'not same deep ordered members'); - * - * @name notSameDeepOrderedMembers - * @param {Array} set1 - * @param {Array} set2 - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notSameDeepOrderedMembers = function (set1, set2, msg) { - new Assertion(set1, msg, assert.notSameDeepOrderedMembers, true) - .to.not.have.same.deep.ordered.members(set2); - } - - /** - * ### .includeMembers(superset, subset, [message]) - * - * Asserts that `subset` is included in `superset` in any order. Uses a - * strict equality check (===). Duplicates are ignored. - * - * assert.includeMembers([ 1, 2, 3 ], [ 2, 1, 2 ], 'include members'); - * - * @name includeMembers - * @param {Array} superset - * @param {Array} subset - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.includeMembers = function (superset, subset, msg) { - new Assertion(superset, msg, assert.includeMembers, true) - .to.include.members(subset); - } - - /** - * ### .notIncludeMembers(superset, subset, [message]) - * - * Asserts that `subset` isn't included in `superset` in any order. Uses a - * strict equality check (===). Duplicates are ignored. - * - * assert.notIncludeMembers([ 1, 2, 3 ], [ 5, 1 ], 'not include members'); - * - * @name notIncludeMembers - * @param {Array} superset - * @param {Array} subset - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notIncludeMembers = function (superset, subset, msg) { - new Assertion(superset, msg, assert.notIncludeMembers, true) - .to.not.include.members(subset); - } - - /** - * ### .includeDeepMembers(superset, subset, [message]) - * - * Asserts that `subset` is included in `superset` in any order. Uses a deep - * equality check. Duplicates are ignored. - * - * assert.includeDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { a: 1 }, { b: 2 } ], 'include deep members'); - * - * @name includeDeepMembers - * @param {Array} superset - * @param {Array} subset - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.includeDeepMembers = function (superset, subset, msg) { - new Assertion(superset, msg, assert.includeDeepMembers, true) - .to.include.deep.members(subset); - } - - /** - * ### .notIncludeDeepMembers(superset, subset, [message]) - * - * Asserts that `subset` isn't included in `superset` in any order. Uses a - * deep equality check. Duplicates are ignored. - * - * assert.notIncludeDeepMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { f: 5 } ], 'not include deep members'); - * - * @name notIncludeDeepMembers - * @param {Array} superset - * @param {Array} subset - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notIncludeDeepMembers = function (superset, subset, msg) { - new Assertion(superset, msg, assert.notIncludeDeepMembers, true) - .to.not.include.deep.members(subset); - } - - /** - * ### .includeOrderedMembers(superset, subset, [message]) - * - * Asserts that `subset` is included in `superset` in the same order - * beginning with the first element in `superset`. Uses a strict equality - * check (===). - * - * assert.includeOrderedMembers([ 1, 2, 3 ], [ 1, 2 ], 'include ordered members'); - * - * @name includeOrderedMembers - * @param {Array} superset - * @param {Array} subset - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.includeOrderedMembers = function (superset, subset, msg) { - new Assertion(superset, msg, assert.includeOrderedMembers, true) - .to.include.ordered.members(subset); - } - - /** - * ### .notIncludeOrderedMembers(superset, subset, [message]) - * - * Asserts that `subset` isn't included in `superset` in the same order - * beginning with the first element in `superset`. Uses a strict equality - * check (===). - * - * assert.notIncludeOrderedMembers([ 1, 2, 3 ], [ 2, 1 ], 'not include ordered members'); - * assert.notIncludeOrderedMembers([ 1, 2, 3 ], [ 2, 3 ], 'not include ordered members'); - * - * @name notIncludeOrderedMembers - * @param {Array} superset - * @param {Array} subset - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notIncludeOrderedMembers = function (superset, subset, msg) { - new Assertion(superset, msg, assert.notIncludeOrderedMembers, true) - .to.not.include.ordered.members(subset); - } - - /** - * ### .includeDeepOrderedMembers(superset, subset, [message]) - * - * Asserts that `subset` is included in `superset` in the same order - * beginning with the first element in `superset`. Uses a deep equality - * check. - * - * assert.includeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { b: 2 } ], 'include deep ordered members'); - * - * @name includeDeepOrderedMembers - * @param {Array} superset - * @param {Array} subset - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.includeDeepOrderedMembers = function (superset, subset, msg) { - new Assertion(superset, msg, assert.includeDeepOrderedMembers, true) - .to.include.deep.ordered.members(subset); - } - - /** - * ### .notIncludeDeepOrderedMembers(superset, subset, [message]) - * - * Asserts that `subset` isn't included in `superset` in the same order - * beginning with the first element in `superset`. Uses a deep equality - * check. - * - * assert.notIncludeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { a: 1 }, { f: 5 } ], 'not include deep ordered members'); - * assert.notIncludeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { a: 1 } ], 'not include deep ordered members'); - * assert.notIncludeDeepOrderedMembers([ { a: 1 }, { b: 2 }, { c: 3 } ], [ { b: 2 }, { c: 3 } ], 'not include deep ordered members'); - * - * @name notIncludeDeepOrderedMembers - * @param {Array} superset - * @param {Array} subset - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.notIncludeDeepOrderedMembers = function (superset, subset, msg) { - new Assertion(superset, msg, assert.notIncludeDeepOrderedMembers, true) - .to.not.include.deep.ordered.members(subset); - } - - /** - * ### .oneOf(inList, list, [message]) - * - * Asserts that non-object, non-array value `inList` appears in the flat array `list`. - * - * assert.oneOf(1, [ 2, 1 ], 'Not found in list'); - * - * @name oneOf - * @param {*} inList - * @param {Array<*>} list - * @param {String} message - * @namespace Assert - * @api public - */ - - assert.oneOf = function (inList, list, msg) { - new Assertion(inList, msg, assert.oneOf, true).to.be.oneOf(list); - } - - /** - * ### .changes(function, object, property, [message]) - * - * Asserts that a function changes the value of a property. - * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 22 }; - * assert.changes(fn, obj, 'val'); - * - * @name changes - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.changes = function (fn, obj, prop, msg) { - if (arguments.length === 3 && typeof obj === 'function') { - msg = prop; - prop = null; - } - - new Assertion(fn, msg, assert.changes, true).to.change(obj, prop); - } - - /** - * ### .changesBy(function, object, property, delta, [message]) - * - * Asserts that a function changes the value of a property by an amount (delta). - * - * var obj = { val: 10 }; - * var fn = function() { obj.val += 2 }; - * assert.changesBy(fn, obj, 'val', 2); - * - * @name changesBy - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {Number} change amount (delta) - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.changesBy = function (fn, obj, prop, delta, msg) { - if (arguments.length === 4 && typeof obj === 'function') { - var tmpMsg = delta; - delta = prop; - msg = tmpMsg; - } else if (arguments.length === 3) { - delta = prop; - prop = null; - } - - new Assertion(fn, msg, assert.changesBy, true) - .to.change(obj, prop).by(delta); - } - - /** - * ### .doesNotChange(function, object, property, [message]) - * - * Asserts that a function does not change the value of a property. - * - * var obj = { val: 10 }; - * var fn = function() { console.log('foo'); }; - * assert.doesNotChange(fn, obj, 'val'); - * - * @name doesNotChange - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.doesNotChange = function (fn, obj, prop, msg) { - if (arguments.length === 3 && typeof obj === 'function') { - msg = prop; - prop = null; - } - - return new Assertion(fn, msg, assert.doesNotChange, true) - .to.not.change(obj, prop); - } - - /** - * ### .changesButNotBy(function, object, property, delta, [message]) - * - * Asserts that a function does not change the value of a property or of a function's return value by an amount (delta) - * - * var obj = { val: 10 }; - * var fn = function() { obj.val += 10 }; - * assert.changesButNotBy(fn, obj, 'val', 5); - * - * @name changesButNotBy - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {Number} change amount (delta) - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.changesButNotBy = function (fn, obj, prop, delta, msg) { - if (arguments.length === 4 && typeof obj === 'function') { - var tmpMsg = delta; - delta = prop; - msg = tmpMsg; - } else if (arguments.length === 3) { - delta = prop; - prop = null; - } - - new Assertion(fn, msg, assert.changesButNotBy, true) - .to.change(obj, prop).but.not.by(delta); - } - - /** - * ### .increases(function, object, property, [message]) - * - * Asserts that a function increases a numeric object property. - * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 13 }; - * assert.increases(fn, obj, 'val'); - * - * @name increases - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.increases = function (fn, obj, prop, msg) { - if (arguments.length === 3 && typeof obj === 'function') { - msg = prop; - prop = null; - } - - return new Assertion(fn, msg, assert.increases, true) - .to.increase(obj, prop); - } - - /** - * ### .increasesBy(function, object, property, delta, [message]) - * - * Asserts that a function increases a numeric object property or a function's return value by an amount (delta). - * - * var obj = { val: 10 }; - * var fn = function() { obj.val += 10 }; - * assert.increasesBy(fn, obj, 'val', 10); - * - * @name increasesBy - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {Number} change amount (delta) - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.increasesBy = function (fn, obj, prop, delta, msg) { - if (arguments.length === 4 && typeof obj === 'function') { - var tmpMsg = delta; - delta = prop; - msg = tmpMsg; - } else if (arguments.length === 3) { - delta = prop; - prop = null; - } - - new Assertion(fn, msg, assert.increasesBy, true) - .to.increase(obj, prop).by(delta); - } - - /** - * ### .doesNotIncrease(function, object, property, [message]) - * - * Asserts that a function does not increase a numeric object property. - * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 8 }; - * assert.doesNotIncrease(fn, obj, 'val'); - * - * @name doesNotIncrease - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.doesNotIncrease = function (fn, obj, prop, msg) { - if (arguments.length === 3 && typeof obj === 'function') { - msg = prop; - prop = null; - } - - return new Assertion(fn, msg, assert.doesNotIncrease, true) - .to.not.increase(obj, prop); - } - - /** - * ### .increasesButNotBy(function, object, property, [message]) - * - * Asserts that a function does not increase a numeric object property or function's return value by an amount (delta). - * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 15 }; - * assert.increasesButNotBy(fn, obj, 'val', 10); - * - * @name increasesButNotBy - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {Number} change amount (delta) - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.increasesButNotBy = function (fn, obj, prop, delta, msg) { - if (arguments.length === 4 && typeof obj === 'function') { - var tmpMsg = delta; - delta = prop; - msg = tmpMsg; - } else if (arguments.length === 3) { - delta = prop; - prop = null; - } - - new Assertion(fn, msg, assert.increasesButNotBy, true) - .to.increase(obj, prop).but.not.by(delta); - } - - /** - * ### .decreases(function, object, property, [message]) - * - * Asserts that a function decreases a numeric object property. - * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 5 }; - * assert.decreases(fn, obj, 'val'); - * - * @name decreases - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.decreases = function (fn, obj, prop, msg) { - if (arguments.length === 3 && typeof obj === 'function') { - msg = prop; - prop = null; - } - - return new Assertion(fn, msg, assert.decreases, true) - .to.decrease(obj, prop); - } - - /** - * ### .decreasesBy(function, object, property, delta, [message]) - * - * Asserts that a function decreases a numeric object property or a function's return value by an amount (delta) - * - * var obj = { val: 10 }; - * var fn = function() { obj.val -= 5 }; - * assert.decreasesBy(fn, obj, 'val', 5); - * - * @name decreasesBy - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {Number} change amount (delta) - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.decreasesBy = function (fn, obj, prop, delta, msg) { - if (arguments.length === 4 && typeof obj === 'function') { - var tmpMsg = delta; - delta = prop; - msg = tmpMsg; - } else if (arguments.length === 3) { - delta = prop; - prop = null; - } - - new Assertion(fn, msg, assert.decreasesBy, true) - .to.decrease(obj, prop).by(delta); - } - - /** - * ### .doesNotDecrease(function, object, property, [message]) - * - * Asserts that a function does not decreases a numeric object property. - * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 15 }; - * assert.doesNotDecrease(fn, obj, 'val'); - * - * @name doesNotDecrease - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.doesNotDecrease = function (fn, obj, prop, msg) { - if (arguments.length === 3 && typeof obj === 'function') { - msg = prop; - prop = null; - } - - return new Assertion(fn, msg, assert.doesNotDecrease, true) - .to.not.decrease(obj, prop); - } - - /** - * ### .doesNotDecreaseBy(function, object, property, delta, [message]) - * - * Asserts that a function does not decreases a numeric object property or a function's return value by an amount (delta) - * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 5 }; - * assert.doesNotDecreaseBy(fn, obj, 'val', 1); - * - * @name doesNotDecrease - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {Number} change amount (delta) - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.doesNotDecreaseBy = function (fn, obj, prop, delta, msg) { - if (arguments.length === 4 && typeof obj === 'function') { - var tmpMsg = delta; - delta = prop; - msg = tmpMsg; - } else if (arguments.length === 3) { - delta = prop; - prop = null; - } - - return new Assertion(fn, msg, assert.doesNotDecreaseBy, true) - .to.not.decrease(obj, prop).by(delta); - } - - /** - * ### .decreasesButNotBy(function, object, property, delta, [message]) - * - * Asserts that a function does not decreases a numeric object property or a function's return value by an amount (delta) - * - * var obj = { val: 10 }; - * var fn = function() { obj.val = 5 }; - * assert.decreasesButNotBy(fn, obj, 'val', 1); - * - * @name decreasesButNotBy - * @param {Function} modifier function - * @param {Object} object or getter function - * @param {String} property name _optional_ - * @param {Number} change amount (delta) - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.decreasesButNotBy = function (fn, obj, prop, delta, msg) { - if (arguments.length === 4 && typeof obj === 'function') { - var tmpMsg = delta; - delta = prop; - msg = tmpMsg; - } else if (arguments.length === 3) { - delta = prop; - prop = null; - } - - new Assertion(fn, msg, assert.decreasesButNotBy, true) - .to.decrease(obj, prop).but.not.by(delta); - } - - /*! - * ### .ifError(object) - * - * Asserts if value is not a false value, and throws if it is a true value. - * This is added to allow for chai to be a drop-in replacement for Node's - * assert class. - * - * var err = new Error('I am a custom error'); - * assert.ifError(err); // Rethrows err! - * - * @name ifError - * @param {Object} object - * @namespace Assert - * @api public - */ - - assert.ifError = function (val) { - if (val) { - throw(val); - } - }; - - /** - * ### .isExtensible(object) - * - * Asserts that `object` is extensible (can have new properties added to it). - * - * assert.isExtensible({}); - * - * @name isExtensible - * @alias extensible - * @param {Object} object - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.isExtensible = function (obj, msg) { - new Assertion(obj, msg, assert.isExtensible, true).to.be.extensible; - }; - - /** - * ### .isNotExtensible(object) - * - * Asserts that `object` is _not_ extensible. - * - * var nonExtensibleObject = Object.preventExtensions({}); - * var sealedObject = Object.seal({}); - * var frozenObject = Object.freeze({}); - * - * assert.isNotExtensible(nonExtensibleObject); - * assert.isNotExtensible(sealedObject); - * assert.isNotExtensible(frozenObject); - * - * @name isNotExtensible - * @alias notExtensible - * @param {Object} object - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.isNotExtensible = function (obj, msg) { - new Assertion(obj, msg, assert.isNotExtensible, true).to.not.be.extensible; - }; - - /** - * ### .isSealed(object) - * - * Asserts that `object` is sealed (cannot have new properties added to it - * and its existing properties cannot be removed). - * - * var sealedObject = Object.seal({}); - * var frozenObject = Object.seal({}); - * - * assert.isSealed(sealedObject); - * assert.isSealed(frozenObject); - * - * @name isSealed - * @alias sealed - * @param {Object} object - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.isSealed = function (obj, msg) { - new Assertion(obj, msg, assert.isSealed, true).to.be.sealed; - }; - - /** - * ### .isNotSealed(object) - * - * Asserts that `object` is _not_ sealed. - * - * assert.isNotSealed({}); - * - * @name isNotSealed - * @alias notSealed - * @param {Object} object - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.isNotSealed = function (obj, msg) { - new Assertion(obj, msg, assert.isNotSealed, true).to.not.be.sealed; - }; - - /** - * ### .isFrozen(object) - * - * Asserts that `object` is frozen (cannot have new properties added to it - * and its existing properties cannot be modified). - * - * var frozenObject = Object.freeze({}); - * assert.frozen(frozenObject); - * - * @name isFrozen - * @alias frozen - * @param {Object} object - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.isFrozen = function (obj, msg) { - new Assertion(obj, msg, assert.isFrozen, true).to.be.frozen; - }; - - /** - * ### .isNotFrozen(object) - * - * Asserts that `object` is _not_ frozen. - * - * assert.isNotFrozen({}); - * - * @name isNotFrozen - * @alias notFrozen - * @param {Object} object - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.isNotFrozen = function (obj, msg) { - new Assertion(obj, msg, assert.isNotFrozen, true).to.not.be.frozen; - }; - - /** - * ### .isEmpty(target) - * - * Asserts that the target does not contain any values. - * For arrays and strings, it checks the `length` property. - * For `Map` and `Set` instances, it checks the `size` property. - * For non-function objects, it gets the count of own - * enumerable string keys. - * - * assert.isEmpty([]); - * assert.isEmpty(''); - * assert.isEmpty(new Map); - * assert.isEmpty({}); - * - * @name isEmpty - * @alias empty - * @param {Object|Array|String|Map|Set} target - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.isEmpty = function(val, msg) { - new Assertion(val, msg, assert.isEmpty, true).to.be.empty; - }; - - /** - * ### .isNotEmpty(target) - * - * Asserts that the target contains values. - * For arrays and strings, it checks the `length` property. - * For `Map` and `Set` instances, it checks the `size` property. - * For non-function objects, it gets the count of own - * enumerable string keys. - * - * assert.isNotEmpty([1, 2]); - * assert.isNotEmpty('34'); - * assert.isNotEmpty(new Set([5, 6])); - * assert.isNotEmpty({ key: 7 }); - * - * @name isNotEmpty - * @alias notEmpty - * @param {Object|Array|String|Map|Set} target - * @param {String} message _optional_ - * @namespace Assert - * @api public - */ - - assert.isNotEmpty = function(val, msg) { - new Assertion(val, msg, assert.isNotEmpty, true).to.not.be.empty; - }; - - /*! - * Aliases. - */ - - (function alias(name, as){ - assert[as] = assert[name]; - return alias; - }) - ('isOk', 'ok') - ('isNotOk', 'notOk') - ('throws', 'throw') - ('throws', 'Throw') - ('isExtensible', 'extensible') - ('isNotExtensible', 'notExtensible') - ('isSealed', 'sealed') - ('isNotSealed', 'notSealed') - ('isFrozen', 'frozen') - ('isNotFrozen', 'notFrozen') - ('isEmpty', 'empty') - ('isNotEmpty', 'notEmpty'); -}; - -},{}],7:[function(require,module,exports){ -/*! - * chai - * Copyright(c) 2011-2014 Jake Luer - * MIT Licensed - */ - -module.exports = function (chai, util) { - chai.expect = function (val, message) { - return new chai.Assertion(val, message); - }; - - /** - * ### .fail(actual, expected, [message], [operator]) - * - * Throw a failure. - * - * @name fail - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @param {String} operator - * @namespace BDD - * @api public - */ - - chai.expect.fail = function (actual, expected, message, operator) { - message = message || 'expect.fail()'; - throw new chai.AssertionError(message, { - actual: actual - , expected: expected - , operator: operator - }, chai.expect.fail); - }; -}; - -},{}],8:[function(require,module,exports){ -/*! - * chai - * Copyright(c) 2011-2014 Jake Luer - * MIT Licensed - */ - -module.exports = function (chai, util) { - var Assertion = chai.Assertion; - - function loadShould () { - // explicitly define this method as function as to have it's name to include as `ssfi` - function shouldGetter() { - if (this instanceof String - || this instanceof Number - || this instanceof Boolean - || typeof Symbol === 'function' && this instanceof Symbol) { - return new Assertion(this.valueOf(), null, shouldGetter); - } - return new Assertion(this, null, shouldGetter); - } - function shouldSetter(value) { - // See https://github.com/chaijs/chai/issues/86: this makes - // `whatever.should = someValue` actually set `someValue`, which is - // especially useful for `global.should = require('chai').should()`. - // - // Note that we have to use [[DefineProperty]] instead of [[Put]] - // since otherwise we would trigger this very setter! - Object.defineProperty(this, 'should', { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } - // modify Object.prototype to have `should` - Object.defineProperty(Object.prototype, 'should', { - set: shouldSetter - , get: shouldGetter - , configurable: true - }); - - var should = {}; - - /** - * ### .fail(actual, expected, [message], [operator]) - * - * Throw a failure. - * - * @name fail - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @param {String} operator - * @namespace BDD - * @api public - */ - - should.fail = function (actual, expected, message, operator) { - message = message || 'should.fail()'; - throw new chai.AssertionError(message, { - actual: actual - , expected: expected - , operator: operator - }, should.fail); - }; - - /** - * ### .equal(actual, expected, [message]) - * - * Asserts non-strict equality (`==`) of `actual` and `expected`. - * - * should.equal(3, '3', '== coerces values to strings'); - * - * @name equal - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @namespace Should - * @api public - */ - - should.equal = function (val1, val2, msg) { - new Assertion(val1, msg).to.equal(val2); - }; - - /** - * ### .throw(function, [constructor/string/regexp], [string/regexp], [message]) - * - * Asserts that `function` will throw an error that is an instance of - * `constructor`, or alternately that it will throw an error with message - * matching `regexp`. - * - * should.throw(fn, 'function throws a reference error'); - * should.throw(fn, /function throws a reference error/); - * should.throw(fn, ReferenceError); - * should.throw(fn, ReferenceError, 'function throws a reference error'); - * should.throw(fn, ReferenceError, /function throws a reference error/); - * - * @name throw - * @alias Throw - * @param {Function} function - * @param {ErrorConstructor} constructor - * @param {RegExp} regexp - * @param {String} message - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types - * @namespace Should - * @api public - */ - - should.Throw = function (fn, errt, errs, msg) { - new Assertion(fn, msg).to.Throw(errt, errs); - }; - - /** - * ### .exist - * - * Asserts that the target is neither `null` nor `undefined`. - * - * var foo = 'hi'; - * - * should.exist(foo, 'foo exists'); - * - * @name exist - * @namespace Should - * @api public - */ - - should.exist = function (val, msg) { - new Assertion(val, msg).to.exist; - } - - // negation - should.not = {} - - /** - * ### .not.equal(actual, expected, [message]) - * - * Asserts non-strict inequality (`!=`) of `actual` and `expected`. - * - * should.not.equal(3, 4, 'these numbers are not equal'); - * - * @name not.equal - * @param {Mixed} actual - * @param {Mixed} expected - * @param {String} message - * @namespace Should - * @api public - */ - - should.not.equal = function (val1, val2, msg) { - new Assertion(val1, msg).to.not.equal(val2); - }; - - /** - * ### .throw(function, [constructor/regexp], [message]) - * - * Asserts that `function` will _not_ throw an error that is an instance of - * `constructor`, or alternately that it will not throw an error with message - * matching `regexp`. - * - * should.not.throw(fn, Error, 'function does not throw'); - * - * @name not.throw - * @alias not.Throw - * @param {Function} function - * @param {ErrorConstructor} constructor - * @param {RegExp} regexp - * @param {String} message - * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types - * @namespace Should - * @api public - */ - - should.not.Throw = function (fn, errt, errs, msg) { - new Assertion(fn, msg).to.not.Throw(errt, errs); - }; - - /** - * ### .not.exist - * - * Asserts that the target is neither `null` nor `undefined`. - * - * var bar = null; - * - * should.not.exist(bar, 'bar does not exist'); - * - * @name not.exist - * @namespace Should - * @api public - */ - - should.not.exist = function (val, msg) { - new Assertion(val, msg).to.not.exist; - } - - should['throw'] = should['Throw']; - should.not['throw'] = should.not['Throw']; - - return should; - }; - - chai.should = loadShould; - chai.Should = loadShould; -}; - -},{}],9:[function(require,module,exports){ -/*! - * Chai - addChainingMethod utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/*! - * Module dependencies - */ - -var addLengthGuard = require('./addLengthGuard'); -var chai = require('../../chai'); -var flag = require('./flag'); -var proxify = require('./proxify'); -var transferFlags = require('./transferFlags'); - -/*! - * Module variables - */ - -// Check whether `Object.setPrototypeOf` is supported -var canSetPrototype = typeof Object.setPrototypeOf === 'function'; - -// Without `Object.setPrototypeOf` support, this module will need to add properties to a function. -// However, some of functions' own props are not configurable and should be skipped. -var testFn = function() {}; -var excludeNames = Object.getOwnPropertyNames(testFn).filter(function(name) { - var propDesc = Object.getOwnPropertyDescriptor(testFn, name); - - // Note: PhantomJS 1.x includes `callee` as one of `testFn`'s own properties, - // but then returns `undefined` as the property descriptor for `callee`. As a - // workaround, we perform an otherwise unnecessary type-check for `propDesc`, - // and then filter it out if it's not an object as it should be. - if (typeof propDesc !== 'object') - return true; - - return !propDesc.configurable; -}); - -// Cache `Function` properties -var call = Function.prototype.call, - apply = Function.prototype.apply; - -/** - * ### .addChainableMethod(ctx, name, method, chainingBehavior) - * - * Adds a method to an object, such that the method can also be chained. - * - * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { - * var obj = utils.flag(this, 'object'); - * new chai.Assertion(obj).to.be.equal(str); - * }); - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); - * - * The result can then be used as both a method assertion, executing both `method` and - * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. - * - * expect(fooStr).to.be.foo('bar'); - * expect(fooStr).to.be.foo.equal('foo'); - * - * @param {Object} ctx object to which the method is added - * @param {String} name of method to add - * @param {Function} method function to be used for `name`, when called - * @param {Function} chainingBehavior function to be called every time the property is accessed - * @namespace Utils - * @name addChainableMethod - * @api public - */ - -module.exports = function addChainableMethod(ctx, name, method, chainingBehavior) { - if (typeof chainingBehavior !== 'function') { - chainingBehavior = function () { }; - } - - var chainableBehavior = { - method: method - , chainingBehavior: chainingBehavior - }; - - // save the methods so we can overwrite them later, if we need to. - if (!ctx.__methods) { - ctx.__methods = {}; - } - ctx.__methods[name] = chainableBehavior; - - Object.defineProperty(ctx, name, - { get: function chainableMethodGetter() { - chainableBehavior.chainingBehavior.call(this); - - var chainableMethodWrapper = function () { - // Setting the `ssfi` flag to `chainableMethodWrapper` causes this - // function to be the starting point for removing implementation - // frames from the stack trace of a failed assertion. - // - // However, we only want to use this function as the starting point if - // the `lockSsfi` flag isn't set. - // - // If the `lockSsfi` flag is set, then this assertion is being - // invoked from inside of another assertion. In this case, the `ssfi` - // flag has already been set by the outer assertion. - // - // Note that overwriting a chainable method merely replaces the saved - // methods in `ctx.__methods` instead of completely replacing the - // overwritten assertion. Therefore, an overwriting assertion won't - // set the `ssfi` or `lockSsfi` flags. - if (!flag(this, 'lockSsfi')) { - flag(this, 'ssfi', chainableMethodWrapper); - } - - var result = chainableBehavior.method.apply(this, arguments); - if (result !== undefined) { - return result; - } - - var newAssertion = new chai.Assertion(); - transferFlags(this, newAssertion); - return newAssertion; - }; - - addLengthGuard(chainableMethodWrapper, name, true); - - // Use `Object.setPrototypeOf` if available - if (canSetPrototype) { - // Inherit all properties from the object by replacing the `Function` prototype - var prototype = Object.create(this); - // Restore the `call` and `apply` methods from `Function` - prototype.call = call; - prototype.apply = apply; - Object.setPrototypeOf(chainableMethodWrapper, prototype); - } - // Otherwise, redefine all properties (slow!) - else { - var asserterNames = Object.getOwnPropertyNames(ctx); - asserterNames.forEach(function (asserterName) { - if (excludeNames.indexOf(asserterName) !== -1) { - return; - } - - var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); - Object.defineProperty(chainableMethodWrapper, asserterName, pd); - }); - } - - transferFlags(this, chainableMethodWrapper); - return proxify(chainableMethodWrapper); - } - , configurable: true - }); -}; - -},{"../../chai":2,"./addLengthGuard":10,"./flag":15,"./proxify":30,"./transferFlags":32}],10:[function(require,module,exports){ -var config = require('../config'); - -var fnLengthDesc = Object.getOwnPropertyDescriptor(function () {}, 'length'); - -/*! - * Chai - addLengthGuard utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/** - * ### .addLengthGuard(fn, assertionName, isChainable) - * - * Define `length` as a getter on the given uninvoked method assertion. The - * getter acts as a guard against chaining `length` directly off of an uninvoked - * method assertion, which is a problem because it references `function`'s - * built-in `length` property instead of Chai's `length` assertion. When the - * getter catches the user making this mistake, it throws an error with a - * helpful message. - * - * There are two ways in which this mistake can be made. The first way is by - * chaining the `length` assertion directly off of an uninvoked chainable - * method. In this case, Chai suggests that the user use `lengthOf` instead. The - * second way is by chaining the `length` assertion directly off of an uninvoked - * non-chainable method. Non-chainable methods must be invoked prior to - * chaining. In this case, Chai suggests that the user consult the docs for the - * given assertion. - * - * If the `length` property of functions is unconfigurable, then return `fn` - * without modification. - * - * Note that in ES6, the function's `length` property is configurable, so once - * support for legacy environments is dropped, Chai's `length` property can - * replace the built-in function's `length` property, and this length guard will - * no longer be necessary. In the mean time, maintaining consistency across all - * environments is the priority. - * - * @param {Function} fn - * @param {String} assertionName - * @param {Boolean} isChainable - * @namespace Utils - * @name addLengthGuard - */ - -module.exports = function addLengthGuard (fn, assertionName, isChainable) { - if (!fnLengthDesc.configurable) return fn; - - Object.defineProperty(fn, 'length', { - get: function () { - if (isChainable) { - throw Error('Invalid Chai property: ' + assertionName + '.length. Due' + - ' to a compatibility issue, "length" cannot directly follow "' + - assertionName + '". Use "' + assertionName + '.lengthOf" instead.'); - } - - throw Error('Invalid Chai property: ' + assertionName + '.length. See' + - ' docs for proper usage of "' + assertionName + '".'); - } - }); - - return fn; -}; - -},{"../config":4}],11:[function(require,module,exports){ -/*! - * Chai - addMethod utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -var addLengthGuard = require('./addLengthGuard'); -var chai = require('../../chai'); -var flag = require('./flag'); -var proxify = require('./proxify'); -var transferFlags = require('./transferFlags'); - -/** - * ### .addMethod(ctx, name, method) - * - * Adds a method to the prototype of an object. - * - * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { - * var obj = utils.flag(this, 'object'); - * new chai.Assertion(obj).to.be.equal(str); - * }); - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.addMethod('foo', fn); - * - * Then can be used as any other assertion. - * - * expect(fooStr).to.be.foo('bar'); - * - * @param {Object} ctx object to which the method is added - * @param {String} name of method to add - * @param {Function} method function to be used for name - * @namespace Utils - * @name addMethod - * @api public - */ - -module.exports = function addMethod(ctx, name, method) { - var methodWrapper = function () { - // Setting the `ssfi` flag to `methodWrapper` causes this function to be the - // starting point for removing implementation frames from the stack trace of - // a failed assertion. - // - // However, we only want to use this function as the starting point if the - // `lockSsfi` flag isn't set. - // - // If the `lockSsfi` flag is set, then either this assertion has been - // overwritten by another assertion, or this assertion is being invoked from - // inside of another assertion. In the first case, the `ssfi` flag has - // already been set by the overwriting assertion. In the second case, the - // `ssfi` flag has already been set by the outer assertion. - if (!flag(this, 'lockSsfi')) { - flag(this, 'ssfi', methodWrapper); - } - - var result = method.apply(this, arguments); - if (result !== undefined) - return result; - - var newAssertion = new chai.Assertion(); - transferFlags(this, newAssertion); - return newAssertion; - }; - - addLengthGuard(methodWrapper, name, false); - ctx[name] = proxify(methodWrapper, name); -}; - -},{"../../chai":2,"./addLengthGuard":10,"./flag":15,"./proxify":30,"./transferFlags":32}],12:[function(require,module,exports){ -/*! - * Chai - addProperty utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -var chai = require('../../chai'); -var flag = require('./flag'); -var isProxyEnabled = require('./isProxyEnabled'); -var transferFlags = require('./transferFlags'); - -/** - * ### .addProperty(ctx, name, getter) - * - * Adds a property to the prototype of an object. - * - * utils.addProperty(chai.Assertion.prototype, 'foo', function () { - * var obj = utils.flag(this, 'object'); - * new chai.Assertion(obj).to.be.instanceof(Foo); - * }); - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.addProperty('foo', fn); - * - * Then can be used as any other assertion. - * - * expect(myFoo).to.be.foo; - * - * @param {Object} ctx object to which the property is added - * @param {String} name of property to add - * @param {Function} getter function to be used for name - * @namespace Utils - * @name addProperty - * @api public - */ - -module.exports = function addProperty(ctx, name, getter) { - getter = getter === undefined ? function () {} : getter; - - Object.defineProperty(ctx, name, - { get: function propertyGetter() { - // Setting the `ssfi` flag to `propertyGetter` causes this function to - // be the starting point for removing implementation frames from the - // stack trace of a failed assertion. - // - // However, we only want to use this function as the starting point if - // the `lockSsfi` flag isn't set and proxy protection is disabled. - // - // If the `lockSsfi` flag is set, then either this assertion has been - // overwritten by another assertion, or this assertion is being invoked - // from inside of another assertion. In the first case, the `ssfi` flag - // has already been set by the overwriting assertion. In the second - // case, the `ssfi` flag has already been set by the outer assertion. - // - // If proxy protection is enabled, then the `ssfi` flag has already been - // set by the proxy getter. - if (!isProxyEnabled() && !flag(this, 'lockSsfi')) { - flag(this, 'ssfi', propertyGetter); - } - - var result = getter.call(this); - if (result !== undefined) - return result; - - var newAssertion = new chai.Assertion(); - transferFlags(this, newAssertion); - return newAssertion; - } - , configurable: true - }); -}; - -},{"../../chai":2,"./flag":15,"./isProxyEnabled":25,"./transferFlags":32}],13:[function(require,module,exports){ -/*! - * Chai - compareByInspect utility - * Copyright(c) 2011-2016 Jake Luer - * MIT Licensed - */ - -/*! - * Module dependancies - */ - -var inspect = require('./inspect'); - -/** - * ### .compareByInspect(mixed, mixed) - * - * To be used as a compareFunction with Array.prototype.sort. Compares elements - * using inspect instead of default behavior of using toString so that Symbols - * and objects with irregular/missing toString can still be sorted without a - * TypeError. - * - * @param {Mixed} first element to compare - * @param {Mixed} second element to compare - * @returns {Number} -1 if 'a' should come before 'b'; otherwise 1 - * @name compareByInspect - * @namespace Utils - * @api public - */ - -module.exports = function compareByInspect(a, b) { - return inspect(a) < inspect(b) ? -1 : 1; -}; - -},{"./inspect":23}],14:[function(require,module,exports){ -/*! - * Chai - expectTypes utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/** - * ### .expectTypes(obj, types) - * - * Ensures that the object being tested against is of a valid type. - * - * utils.expectTypes(this, ['array', 'object', 'string']); - * - * @param {Mixed} obj constructed Assertion - * @param {Array} type A list of allowed types for this assertion - * @namespace Utils - * @name expectTypes - * @api public - */ - -var AssertionError = require('assertion-error'); -var flag = require('./flag'); -var type = require('type-detect'); - -module.exports = function expectTypes(obj, types) { - var flagMsg = flag(obj, 'message'); - var ssfi = flag(obj, 'ssfi'); - - flagMsg = flagMsg ? flagMsg + ': ' : ''; - - obj = flag(obj, 'object'); - types = types.map(function (t) { return t.toLowerCase(); }); - types.sort(); - - // Transforms ['lorem', 'ipsum'] into 'a lorem, or an ipsum' - var str = types.map(function (t, index) { - var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a'; - var or = types.length > 1 && index === types.length - 1 ? 'or ' : ''; - return or + art + ' ' + t; - }).join(', '); - - var objType = type(obj).toLowerCase(); - - if (!types.some(function (expected) { return objType === expected; })) { - throw new AssertionError( - flagMsg + 'object tested must be ' + str + ', but ' + objType + ' given', - undefined, - ssfi - ); - } -}; - -},{"./flag":15,"assertion-error":33,"type-detect":38}],15:[function(require,module,exports){ -/*! - * Chai - flag utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/** - * ### .flag(object, key, [value]) - * - * Get or set a flag value on an object. If a - * value is provided it will be set, else it will - * return the currently set value or `undefined` if - * the value is not set. - * - * utils.flag(this, 'foo', 'bar'); // setter - * utils.flag(this, 'foo'); // getter, returns `bar` - * - * @param {Object} object constructed Assertion - * @param {String} key - * @param {Mixed} value (optional) - * @namespace Utils - * @name flag - * @api private - */ - -module.exports = function flag(obj, key, value) { - var flags = obj.__flags || (obj.__flags = Object.create(null)); - if (arguments.length === 3) { - flags[key] = value; - } else { - return flags[key]; - } -}; - -},{}],16:[function(require,module,exports){ -/*! - * Chai - getActual utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/** - * ### .getActual(object, [actual]) - * - * Returns the `actual` value for an Assertion. - * - * @param {Object} object (constructed Assertion) - * @param {Arguments} chai.Assertion.prototype.assert arguments - * @namespace Utils - * @name getActual - */ - -module.exports = function getActual(obj, args) { - return args.length > 4 ? args[4] : obj._obj; -}; - -},{}],17:[function(require,module,exports){ -/*! - * Chai - getEnumerableProperties utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/** - * ### .getEnumerableProperties(object) - * - * This allows the retrieval of enumerable property names of an object, - * inherited or not. - * - * @param {Object} object - * @returns {Array} - * @namespace Utils - * @name getEnumerableProperties - * @api public - */ - -module.exports = function getEnumerableProperties(object) { - var result = []; - for (var name in object) { - result.push(name); - } - return result; -}; - -},{}],18:[function(require,module,exports){ -/*! - * Chai - message composition utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/*! - * Module dependancies - */ - -var flag = require('./flag') - , getActual = require('./getActual') - , inspect = require('./inspect') - , objDisplay = require('./objDisplay'); - -/** - * ### .getMessage(object, message, negateMessage) - * - * Construct the error message based on flags - * and template tags. Template tags will return - * a stringified inspection of the object referenced. - * - * Message template tags: - * - `#{this}` current asserted object - * - `#{act}` actual value - * - `#{exp}` expected value - * - * @param {Object} object (constructed Assertion) - * @param {Arguments} chai.Assertion.prototype.assert arguments - * @namespace Utils - * @name getMessage - * @api public - */ - -module.exports = function getMessage(obj, args) { - var negate = flag(obj, 'negate') - , val = flag(obj, 'object') - , expected = args[3] - , actual = getActual(obj, args) - , msg = negate ? args[2] : args[1] - , flagMsg = flag(obj, 'message'); - - if(typeof msg === "function") msg = msg(); - msg = msg || ''; - msg = msg - .replace(/#\{this\}/g, function () { return objDisplay(val); }) - .replace(/#\{act\}/g, function () { return objDisplay(actual); }) - .replace(/#\{exp\}/g, function () { return objDisplay(expected); }); - - return flagMsg ? flagMsg + ': ' + msg : msg; -}; - -},{"./flag":15,"./getActual":16,"./inspect":23,"./objDisplay":26}],19:[function(require,module,exports){ -/*! - * Chai - getOwnEnumerableProperties utility - * Copyright(c) 2011-2016 Jake Luer - * MIT Licensed - */ - -/*! - * Module dependancies - */ - -var getOwnEnumerablePropertySymbols = require('./getOwnEnumerablePropertySymbols'); - -/** - * ### .getOwnEnumerableProperties(object) - * - * This allows the retrieval of directly-owned enumerable property names and - * symbols of an object. This function is necessary because Object.keys only - * returns enumerable property names, not enumerable property symbols. - * - * @param {Object} object - * @returns {Array} - * @namespace Utils - * @name getOwnEnumerableProperties - * @api public - */ - -module.exports = function getOwnEnumerableProperties(obj) { - return Object.keys(obj).concat(getOwnEnumerablePropertySymbols(obj)); -}; - -},{"./getOwnEnumerablePropertySymbols":20}],20:[function(require,module,exports){ -/*! - * Chai - getOwnEnumerablePropertySymbols utility - * Copyright(c) 2011-2016 Jake Luer - * MIT Licensed - */ - -/** - * ### .getOwnEnumerablePropertySymbols(object) - * - * This allows the retrieval of directly-owned enumerable property symbols of an - * object. This function is necessary because Object.getOwnPropertySymbols - * returns both enumerable and non-enumerable property symbols. - * - * @param {Object} object - * @returns {Array} - * @namespace Utils - * @name getOwnEnumerablePropertySymbols - * @api public - */ - -module.exports = function getOwnEnumerablePropertySymbols(obj) { - if (typeof Object.getOwnPropertySymbols !== 'function') return []; - - return Object.getOwnPropertySymbols(obj).filter(function (sym) { - return Object.getOwnPropertyDescriptor(obj, sym).enumerable; - }); -}; - -},{}],21:[function(require,module,exports){ -/*! - * Chai - getProperties utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/** - * ### .getProperties(object) - * - * This allows the retrieval of property names of an object, enumerable or not, - * inherited or not. - * - * @param {Object} object - * @returns {Array} - * @namespace Utils - * @name getProperties - * @api public - */ - -module.exports = function getProperties(object) { - var result = Object.getOwnPropertyNames(object); - - function addProperty(property) { - if (result.indexOf(property) === -1) { - result.push(property); - } - } - - var proto = Object.getPrototypeOf(object); - while (proto !== null) { - Object.getOwnPropertyNames(proto).forEach(addProperty); - proto = Object.getPrototypeOf(proto); - } - - return result; -}; - -},{}],22:[function(require,module,exports){ -/*! - * chai - * Copyright(c) 2011 Jake Luer - * MIT Licensed - */ - -/*! - * Dependencies that are used for multiple exports are required here only once - */ - -var pathval = require('pathval'); - -/*! - * test utility - */ - -exports.test = require('./test'); - -/*! - * type utility - */ - -exports.type = require('type-detect'); - -/*! - * expectTypes utility - */ -exports.expectTypes = require('./expectTypes'); - -/*! - * message utility - */ - -exports.getMessage = require('./getMessage'); - -/*! - * actual utility - */ - -exports.getActual = require('./getActual'); - -/*! - * Inspect util - */ - -exports.inspect = require('./inspect'); - -/*! - * Object Display util - */ - -exports.objDisplay = require('./objDisplay'); - -/*! - * Flag utility - */ - -exports.flag = require('./flag'); - -/*! - * Flag transferring utility - */ - -exports.transferFlags = require('./transferFlags'); - -/*! - * Deep equal utility - */ - -exports.eql = require('deep-eql'); - -/*! - * Deep path info - */ - -exports.getPathInfo = pathval.getPathInfo; - -/*! - * Check if a property exists - */ - -exports.hasProperty = pathval.hasProperty; - -/*! - * Function name - */ - -exports.getName = require('get-func-name'); - -/*! - * add Property - */ - -exports.addProperty = require('./addProperty'); - -/*! - * add Method - */ - -exports.addMethod = require('./addMethod'); - -/*! - * overwrite Property - */ - -exports.overwriteProperty = require('./overwriteProperty'); - -/*! - * overwrite Method - */ - -exports.overwriteMethod = require('./overwriteMethod'); - -/*! - * Add a chainable method - */ - -exports.addChainableMethod = require('./addChainableMethod'); - -/*! - * Overwrite chainable method - */ - -exports.overwriteChainableMethod = require('./overwriteChainableMethod'); - -/*! - * Compare by inspect method - */ - -exports.compareByInspect = require('./compareByInspect'); - -/*! - * Get own enumerable property symbols method - */ - -exports.getOwnEnumerablePropertySymbols = require('./getOwnEnumerablePropertySymbols'); - -/*! - * Get own enumerable properties method - */ - -exports.getOwnEnumerableProperties = require('./getOwnEnumerableProperties'); - -/*! - * Checks error against a given set of criteria - */ - -exports.checkError = require('check-error'); - -/*! - * Proxify util - */ - -exports.proxify = require('./proxify'); - -/*! - * addLengthGuard util - */ - -exports.addLengthGuard = require('./addLengthGuard'); - -/*! - * isProxyEnabled helper - */ - -exports.isProxyEnabled = require('./isProxyEnabled'); - -/*! - * isNaN method - */ - -exports.isNaN = require('./isNaN'); - -},{"./addChainableMethod":9,"./addLengthGuard":10,"./addMethod":11,"./addProperty":12,"./compareByInspect":13,"./expectTypes":14,"./flag":15,"./getActual":16,"./getMessage":18,"./getOwnEnumerableProperties":19,"./getOwnEnumerablePropertySymbols":20,"./inspect":23,"./isNaN":24,"./isProxyEnabled":25,"./objDisplay":26,"./overwriteChainableMethod":27,"./overwriteMethod":28,"./overwriteProperty":29,"./proxify":30,"./test":31,"./transferFlags":32,"check-error":34,"deep-eql":35,"get-func-name":36,"pathval":37,"type-detect":38}],23:[function(require,module,exports){ -// This is (almost) directly from Node.js utils -// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js - -var getName = require('get-func-name'); -var getProperties = require('./getProperties'); -var getEnumerableProperties = require('./getEnumerableProperties'); -var config = require('../config'); - -module.exports = inspect; - -/** - * ### .inspect(obj, [showHidden], [depth], [colors]) - * - * Echoes the value of a value. Tries to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Boolean} showHidden Flag that shows hidden (not enumerable) - * properties of objects. Default is false. - * @param {Number} depth Depth in which to descend in object. Default is 2. - * @param {Boolean} colors Flag to turn on ANSI escape codes to color the - * output. Default is false (no coloring). - * @namespace Utils - * @name inspect - */ -function inspect(obj, showHidden, depth, colors) { - var ctx = { - showHidden: showHidden, - seen: [], - stylize: function (str) { return str; } - }; - return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); -} - -// Returns true if object is a DOM element. -var isDOMElement = function (object) { - if (typeof HTMLElement === 'object') { - return object instanceof HTMLElement; - } else { - return object && - typeof object === 'object' && - 'nodeType' in object && - object.nodeType === 1 && - typeof object.nodeName === 'string'; - } -}; - -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (value && typeof value.inspect === 'function' && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (typeof ret !== 'string') { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // If this is a DOM element, try to get the outer HTML. - if (isDOMElement(value)) { - if ('outerHTML' in value) { - return value.outerHTML; - // This value does not have an outerHTML attribute, - // it could still be an XML element - } else { - // Attempt to serialize it - try { - if (document.xmlVersion) { - var xmlSerializer = new XMLSerializer(); - return xmlSerializer.serializeToString(value); - } else { - // Firefox 11- do not support outerHTML - // It does, however, support innerHTML - // Use the following to render the element - var ns = "http://www.w3.org/1999/xhtml"; - var container = document.createElementNS(ns, '_'); - - container.appendChild(value.cloneNode(false)); - var html = container.innerHTML - .replace('><', '>' + value.innerHTML + '<'); - container.innerHTML = ''; - return html; - } - } catch (err) { - // This could be a non-native DOM implementation, - // continue with the normal flow: - // printing the element as if it is an object. - } - } - } - - // Look up the keys of the object. - var visibleKeys = getEnumerableProperties(value); - var keys = ctx.showHidden ? getProperties(value) : visibleKeys; - - var name, nameSuffix; - - // Some type of object without properties can be shortcutted. - // In IE, errors have a single `stack` property, or if they are vanilla `Error`, - // a `stack` plus `description` property; ignore those for consistency. - if (keys.length === 0 || (isError(value) && ( - (keys.length === 1 && keys[0] === 'stack') || - (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') - ))) { - if (typeof value === 'function') { - name = getName(value); - nameSuffix = name ? ': ' + name : ''; - return ctx.stylize('[Function' + nameSuffix + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '' - , array = false - , typedArray = false - , braces = ['{', '}']; - - if (isTypedArray(value)) { - typedArray = true; - braces = ['[', ']']; - } - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (typeof value === 'function') { - name = getName(value); - nameSuffix = name ? ': ' + name : ''; - base = ' [Function' + nameSuffix + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - return formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else if (typedArray) { - return formatTypedArray(value); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); -} - - -function formatPrimitive(ctx, value) { - switch (typeof value) { - case 'undefined': - return ctx.stylize('undefined', 'undefined'); - - case 'string': - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - - case 'number': - if (value === 0 && (1/value) === -Infinity) { - return ctx.stylize('-0', 'number'); - } - return ctx.stylize('' + value, 'number'); - - case 'boolean': - return ctx.stylize('' + value, 'boolean'); - - case 'symbol': - return ctx.stylize(value.toString(), 'symbol'); - } - // For some reason typeof null is "object", so special case here. - if (value === null) { - return ctx.stylize('null', 'null'); - } -} - - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} - - -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (Object.prototype.hasOwnProperty.call(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} - -function formatTypedArray(value) { - var str = '[ '; - - for (var i = 0; i < value.length; ++i) { - if (str.length >= config.truncateThreshold - 7) { - str += '...'; - break; - } - str += value[i] + ', '; - } - str += ' ]'; - - // Removing trailing `, ` if the array was not truncated - if (str.indexOf(', ]') !== -1) { - str = str.replace(', ]', ' ]'); - } - - return str; -} - -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name; - var propDescriptor = Object.getOwnPropertyDescriptor(value, key); - var str; - - if (propDescriptor) { - if (propDescriptor.get) { - if (propDescriptor.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (propDescriptor.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - } - if (visibleKeys.indexOf(key) < 0) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(value[key]) < 0) { - if (recurseTimes === null) { - str = formatValue(ctx, value[key], null); - } else { - str = formatValue(ctx, value[key], recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (typeof name === 'undefined') { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; -} - - -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} - -function isTypedArray(ar) { - // Unfortunately there's no way to check if an object is a TypedArray - // We have to check if it's one of these types - return (typeof ar === 'object' && /\w+Array]$/.test(objectToString(ar))); -} - -function isArray(ar) { - return Array.isArray(ar) || - (typeof ar === 'object' && objectToString(ar) === '[object Array]'); -} - -function isRegExp(re) { - return typeof re === 'object' && objectToString(re) === '[object RegExp]'; -} - -function isDate(d) { - return typeof d === 'object' && objectToString(d) === '[object Date]'; -} - -function isError(e) { - return typeof e === 'object' && objectToString(e) === '[object Error]'; -} - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - -},{"../config":4,"./getEnumerableProperties":17,"./getProperties":21,"get-func-name":36}],24:[function(require,module,exports){ -/*! - * Chai - isNaN utility - * Copyright(c) 2012-2015 Sakthipriyan Vairamani - * MIT Licensed - */ - -/** - * ### .isNaN(value) - * - * Checks if the given value is NaN or not. - * - * utils.isNaN(NaN); // true - * - * @param {Value} The value which has to be checked if it is NaN - * @name isNaN - * @api private - */ - -function isNaN(value) { - // Refer http://www.ecma-international.org/ecma-262/6.0/#sec-isnan-number - // section's NOTE. - return value !== value; -} - -// If ECMAScript 6's Number.isNaN is present, prefer that. -module.exports = Number.isNaN || isNaN; - -},{}],25:[function(require,module,exports){ -var config = require('../config'); - -/*! - * Chai - isProxyEnabled helper - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/** - * ### .isProxyEnabled() - * - * Helper function to check if Chai's proxy protection feature is enabled. If - * proxies are unsupported or disabled via the user's Chai config, then return - * false. Otherwise, return true. - * - * @namespace Utils - * @name isProxyEnabled - */ - -module.exports = function isProxyEnabled() { - return config.useProxy && - typeof Proxy !== 'undefined' && - typeof Reflect !== 'undefined'; -}; - -},{"../config":4}],26:[function(require,module,exports){ -/*! - * Chai - flag utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/*! - * Module dependancies - */ - -var inspect = require('./inspect'); -var config = require('../config'); - -/** - * ### .objDisplay(object) - * - * Determines if an object or an array matches - * criteria to be inspected in-line for error - * messages or should be truncated. - * - * @param {Mixed} javascript object to inspect - * @name objDisplay - * @namespace Utils - * @api public - */ - -module.exports = function objDisplay(obj) { - var str = inspect(obj) - , type = Object.prototype.toString.call(obj); - - if (config.truncateThreshold && str.length >= config.truncateThreshold) { - if (type === '[object Function]') { - return !obj.name || obj.name === '' - ? '[Function]' - : '[Function: ' + obj.name + ']'; - } else if (type === '[object Array]') { - return '[ Array(' + obj.length + ') ]'; - } else if (type === '[object Object]') { - var keys = Object.keys(obj) - , kstr = keys.length > 2 - ? keys.splice(0, 2).join(', ') + ', ...' - : keys.join(', '); - return '{ Object (' + kstr + ') }'; - } else { - return str; - } - } else { - return str; - } -}; - -},{"../config":4,"./inspect":23}],27:[function(require,module,exports){ -/*! - * Chai - overwriteChainableMethod utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -var chai = require('../../chai'); -var transferFlags = require('./transferFlags'); - -/** - * ### .overwriteChainableMethod(ctx, name, method, chainingBehavior) - * - * Overwites an already existing chainable method - * and provides access to the previous function or - * property. Must return functions to be used for - * name. - * - * utils.overwriteChainableMethod(chai.Assertion.prototype, 'lengthOf', - * function (_super) { - * } - * , function (_super) { - * } - * ); - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.overwriteChainableMethod('foo', fn, fn); - * - * Then can be used as any other assertion. - * - * expect(myFoo).to.have.lengthOf(3); - * expect(myFoo).to.have.lengthOf.above(3); - * - * @param {Object} ctx object whose method / property is to be overwritten - * @param {String} name of method / property to overwrite - * @param {Function} method function that returns a function to be used for name - * @param {Function} chainingBehavior function that returns a function to be used for property - * @namespace Utils - * @name overwriteChainableMethod - * @api public - */ - -module.exports = function overwriteChainableMethod(ctx, name, method, chainingBehavior) { - var chainableBehavior = ctx.__methods[name]; - - var _chainingBehavior = chainableBehavior.chainingBehavior; - chainableBehavior.chainingBehavior = function overwritingChainableMethodGetter() { - var result = chainingBehavior(_chainingBehavior).call(this); - if (result !== undefined) { - return result; - } - - var newAssertion = new chai.Assertion(); - transferFlags(this, newAssertion); - return newAssertion; - }; - - var _method = chainableBehavior.method; - chainableBehavior.method = function overwritingChainableMethodWrapper() { - var result = method(_method).apply(this, arguments); - if (result !== undefined) { - return result; - } - - var newAssertion = new chai.Assertion(); - transferFlags(this, newAssertion); - return newAssertion; - }; -}; - -},{"../../chai":2,"./transferFlags":32}],28:[function(require,module,exports){ -/*! - * Chai - overwriteMethod utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -var addLengthGuard = require('./addLengthGuard'); -var chai = require('../../chai'); -var flag = require('./flag'); -var proxify = require('./proxify'); -var transferFlags = require('./transferFlags'); - -/** - * ### .overwriteMethod(ctx, name, fn) - * - * Overwites an already existing method and provides - * access to previous function. Must return function - * to be used for name. - * - * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { - * return function (str) { - * var obj = utils.flag(this, 'object'); - * if (obj instanceof Foo) { - * new chai.Assertion(obj.value).to.equal(str); - * } else { - * _super.apply(this, arguments); - * } - * } - * }); - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.overwriteMethod('foo', fn); - * - * Then can be used as any other assertion. - * - * expect(myFoo).to.equal('bar'); - * - * @param {Object} ctx object whose method is to be overwritten - * @param {String} name of method to overwrite - * @param {Function} method function that returns a function to be used for name - * @namespace Utils - * @name overwriteMethod - * @api public - */ - -module.exports = function overwriteMethod(ctx, name, method) { - var _method = ctx[name] - , _super = function () { - throw new Error(name + ' is not a function'); - }; - - if (_method && 'function' === typeof _method) - _super = _method; - - var overwritingMethodWrapper = function () { - // Setting the `ssfi` flag to `overwritingMethodWrapper` causes this - // function to be the starting point for removing implementation frames from - // the stack trace of a failed assertion. - // - // However, we only want to use this function as the starting point if the - // `lockSsfi` flag isn't set. - // - // If the `lockSsfi` flag is set, then either this assertion has been - // overwritten by another assertion, or this assertion is being invoked from - // inside of another assertion. In the first case, the `ssfi` flag has - // already been set by the overwriting assertion. In the second case, the - // `ssfi` flag has already been set by the outer assertion. - if (!flag(this, 'lockSsfi')) { - flag(this, 'ssfi', overwritingMethodWrapper); - } - - // Setting the `lockSsfi` flag to `true` prevents the overwritten assertion - // from changing the `ssfi` flag. By this point, the `ssfi` flag is already - // set to the correct starting point for this assertion. - var origLockSsfi = flag(this, 'lockSsfi'); - flag(this, 'lockSsfi', true); - var result = method(_super).apply(this, arguments); - flag(this, 'lockSsfi', origLockSsfi); - - if (result !== undefined) { - return result; - } - - var newAssertion = new chai.Assertion(); - transferFlags(this, newAssertion); - return newAssertion; - } - - addLengthGuard(overwritingMethodWrapper, name, false); - ctx[name] = proxify(overwritingMethodWrapper, name); -}; - -},{"../../chai":2,"./addLengthGuard":10,"./flag":15,"./proxify":30,"./transferFlags":32}],29:[function(require,module,exports){ -/*! - * Chai - overwriteProperty utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -var chai = require('../../chai'); -var flag = require('./flag'); -var isProxyEnabled = require('./isProxyEnabled'); -var transferFlags = require('./transferFlags'); - -/** - * ### .overwriteProperty(ctx, name, fn) - * - * Overwites an already existing property getter and provides - * access to previous value. Must return function to use as getter. - * - * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { - * return function () { - * var obj = utils.flag(this, 'object'); - * if (obj instanceof Foo) { - * new chai.Assertion(obj.name).to.equal('bar'); - * } else { - * _super.call(this); - * } - * } - * }); - * - * - * Can also be accessed directly from `chai.Assertion`. - * - * chai.Assertion.overwriteProperty('foo', fn); - * - * Then can be used as any other assertion. - * - * expect(myFoo).to.be.ok; - * - * @param {Object} ctx object whose property is to be overwritten - * @param {String} name of property to overwrite - * @param {Function} getter function that returns a getter function to be used for name - * @namespace Utils - * @name overwriteProperty - * @api public - */ - -module.exports = function overwriteProperty(ctx, name, getter) { - var _get = Object.getOwnPropertyDescriptor(ctx, name) - , _super = function () {}; - - if (_get && 'function' === typeof _get.get) - _super = _get.get - - Object.defineProperty(ctx, name, - { get: function overwritingPropertyGetter() { - // Setting the `ssfi` flag to `overwritingPropertyGetter` causes this - // function to be the starting point for removing implementation frames - // from the stack trace of a failed assertion. - // - // However, we only want to use this function as the starting point if - // the `lockSsfi` flag isn't set and proxy protection is disabled. - // - // If the `lockSsfi` flag is set, then either this assertion has been - // overwritten by another assertion, or this assertion is being invoked - // from inside of another assertion. In the first case, the `ssfi` flag - // has already been set by the overwriting assertion. In the second - // case, the `ssfi` flag has already been set by the outer assertion. - // - // If proxy protection is enabled, then the `ssfi` flag has already been - // set by the proxy getter. - if (!isProxyEnabled() && !flag(this, 'lockSsfi')) { - flag(this, 'ssfi', overwritingPropertyGetter); - } - - // Setting the `lockSsfi` flag to `true` prevents the overwritten - // assertion from changing the `ssfi` flag. By this point, the `ssfi` - // flag is already set to the correct starting point for this assertion. - var origLockSsfi = flag(this, 'lockSsfi'); - flag(this, 'lockSsfi', true); - var result = getter(_super).call(this); - flag(this, 'lockSsfi', origLockSsfi); - - if (result !== undefined) { - return result; - } - - var newAssertion = new chai.Assertion(); - transferFlags(this, newAssertion); - return newAssertion; - } - , configurable: true - }); -}; - -},{"../../chai":2,"./flag":15,"./isProxyEnabled":25,"./transferFlags":32}],30:[function(require,module,exports){ -var config = require('../config'); -var flag = require('./flag'); -var getProperties = require('./getProperties'); -var isProxyEnabled = require('./isProxyEnabled'); - -/*! - * Chai - proxify utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/** - * ### .proxify(object) - * - * Return a proxy of given object that throws an error when a non-existent - * property is read. By default, the root cause is assumed to be a misspelled - * property, and thus an attempt is made to offer a reasonable suggestion from - * the list of existing properties. However, if a nonChainableMethodName is - * provided, then the root cause is instead a failure to invoke a non-chainable - * method prior to reading the non-existent property. - * - * If proxies are unsupported or disabled via the user's Chai config, then - * return object without modification. - * - * @param {Object} obj - * @param {String} nonChainableMethodName - * @namespace Utils - * @name proxify - */ - -var builtins = ['__flags', '__methods', '_obj', 'assert']; - -module.exports = function proxify(obj, nonChainableMethodName) { - if (!isProxyEnabled()) return obj; - - return new Proxy(obj, { - get: function proxyGetter(target, property) { - // This check is here because we should not throw errors on Symbol properties - // such as `Symbol.toStringTag`. - // The values for which an error should be thrown can be configured using - // the `config.proxyExcludedKeys` setting. - if (typeof property === 'string' && - config.proxyExcludedKeys.indexOf(property) === -1 && - !Reflect.has(target, property)) { - // Special message for invalid property access of non-chainable methods. - if (nonChainableMethodName) { - throw Error('Invalid Chai property: ' + nonChainableMethodName + '.' + - property + '. See docs for proper usage of "' + - nonChainableMethodName + '".'); - } - - var orderedProperties = getProperties(target).filter(function(property) { - return !Object.prototype.hasOwnProperty(property) && - builtins.indexOf(property) === -1; - }).sort(function(a, b) { - return stringDistance(property, a) - stringDistance(property, b); - }); - - if (orderedProperties.length && - stringDistance(orderedProperties[0], property) < 4) { - // If the property is reasonably close to an existing Chai property, - // suggest that property to the user. - throw Error('Invalid Chai property: ' + property + - '. Did you mean "' + orderedProperties[0] + '"?'); - } else { - throw Error('Invalid Chai property: ' + property); - } - } - - // Use this proxy getter as the starting point for removing implementation - // frames from the stack trace of a failed assertion. For property - // assertions, this prevents the proxy getter from showing up in the stack - // trace since it's invoked before the property getter. For method and - // chainable method assertions, this flag will end up getting changed to - // the method wrapper, which is good since this frame will no longer be in - // the stack once the method is invoked. Note that Chai builtin assertion - // properties such as `__flags` are skipped since this is only meant to - // capture the starting point of an assertion. This step is also skipped - // if the `lockSsfi` flag is set, thus indicating that this assertion is - // being called from within another assertion. In that case, the `ssfi` - // flag is already set to the outer assertion's starting point. - if (builtins.indexOf(property) === -1 && !flag(target, 'lockSsfi')) { - flag(target, 'ssfi', proxyGetter); - } - - return Reflect.get(target, property); - } - }); -}; - -/** - * # stringDistance(strA, strB) - * Return the Levenshtein distance between two strings. - * @param {string} strA - * @param {string} strB - * @return {number} the string distance between strA and strB - * @api private - */ - -function stringDistance(strA, strB, memo) { - if (!memo) { - // `memo` is a two-dimensional array containing a cache of distances - // memo[i][j] is the distance between strA.slice(0, i) and - // strB.slice(0, j). - memo = []; - for (var i = 0; i <= strA.length; i++) { - memo[i] = []; - } - } - - if (!memo[strA.length] || !memo[strA.length][strB.length]) { - if (strA.length === 0 || strB.length === 0) { - memo[strA.length][strB.length] = Math.max(strA.length, strB.length); - } else { - memo[strA.length][strB.length] = Math.min( - stringDistance(strA.slice(0, -1), strB, memo) + 1, - stringDistance(strA, strB.slice(0, -1), memo) + 1, - stringDistance(strA.slice(0, -1), strB.slice(0, -1), memo) + - (strA.slice(-1) === strB.slice(-1) ? 0 : 1) - ); - } - } - - return memo[strA.length][strB.length]; -} - -},{"../config":4,"./flag":15,"./getProperties":21,"./isProxyEnabled":25}],31:[function(require,module,exports){ -/*! - * Chai - test utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/*! - * Module dependancies - */ - -var flag = require('./flag'); - -/** - * ### .test(object, expression) - * - * Test and object for expression. - * - * @param {Object} object (constructed Assertion) - * @param {Arguments} chai.Assertion.prototype.assert arguments - * @namespace Utils - * @name test - */ - -module.exports = function test(obj, args) { - var negate = flag(obj, 'negate') - , expr = args[0]; - return negate ? !expr : expr; -}; - -},{"./flag":15}],32:[function(require,module,exports){ -/*! - * Chai - transferFlags utility - * Copyright(c) 2012-2014 Jake Luer - * MIT Licensed - */ - -/** - * ### .transferFlags(assertion, object, includeAll = true) - * - * Transfer all the flags for `assertion` to `object`. If - * `includeAll` is set to `false`, then the base Chai - * assertion flags (namely `object`, `ssfi`, `lockSsfi`, - * and `message`) will not be transferred. - * - * - * var newAssertion = new Assertion(); - * utils.transferFlags(assertion, newAssertion); - * - * var anotherAsseriton = new Assertion(myObj); - * utils.transferFlags(assertion, anotherAssertion, false); - * - * @param {Assertion} assertion the assertion to transfer the flags from - * @param {Object} object the object to transfer the flags to; usually a new assertion - * @param {Boolean} includeAll - * @namespace Utils - * @name transferFlags - * @api private - */ - -module.exports = function transferFlags(assertion, object, includeAll) { - var flags = assertion.__flags || (assertion.__flags = Object.create(null)); - - if (!object.__flags) { - object.__flags = Object.create(null); - } - - includeAll = arguments.length === 3 ? includeAll : true; - - for (var flag in flags) { - if (includeAll || - (flag !== 'object' && flag !== 'ssfi' && flag !== 'lockSsfi' && flag != 'message')) { - object.__flags[flag] = flags[flag]; - } - } -}; - -},{}],33:[function(require,module,exports){ -/*! - * assertion-error - * Copyright(c) 2013 Jake Luer - * MIT Licensed - */ - -/*! - * Return a function that will copy properties from - * one object to another excluding any originally - * listed. Returned function will create a new `{}`. - * - * @param {String} excluded properties ... - * @return {Function} - */ - -function exclude () { - var excludes = [].slice.call(arguments); - - function excludeProps (res, obj) { - Object.keys(obj).forEach(function (key) { - if (!~excludes.indexOf(key)) res[key] = obj[key]; - }); - } - - return function extendExclude () { - var args = [].slice.call(arguments) - , i = 0 - , res = {}; - - for (; i < args.length; i++) { - excludeProps(res, args[i]); - } - - return res; - }; -}; - -/*! - * Primary Exports - */ - -module.exports = AssertionError; - -/** - * ### AssertionError - * - * An extension of the JavaScript `Error` constructor for - * assertion and validation scenarios. - * - * @param {String} message - * @param {Object} properties to include (optional) - * @param {callee} start stack function (optional) - */ - -function AssertionError (message, _props, ssf) { - var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') - , props = extend(_props || {}); - - // default values - this.message = message || 'Unspecified AssertionError'; - this.showDiff = false; - - // copy from properties - for (var key in props) { - this[key] = props[key]; - } - - // capture stack trace - ssf = ssf || arguments.callee; - if (ssf && Error.captureStackTrace) { - Error.captureStackTrace(this, ssf); - } else { - try { - throw new Error(); - } catch(e) { - this.stack = e.stack; - } - } -} - -/*! - * Inherit from Error.prototype - */ - -AssertionError.prototype = Object.create(Error.prototype); - -/*! - * Statically set name - */ - -AssertionError.prototype.name = 'AssertionError'; - -/*! - * Ensure correct constructor - */ - -AssertionError.prototype.constructor = AssertionError; - -/** - * Allow errors to be converted to JSON for static transfer. - * - * @param {Boolean} include stack (default: `true`) - * @return {Object} object that can be `JSON.stringify` - */ - -AssertionError.prototype.toJSON = function (stack) { - var extend = exclude('constructor', 'toJSON', 'stack') - , props = extend({ name: this.name }, this); - - // include stack if exists and not turned off - if (false !== stack && this.stack) { - props.stack = this.stack; - } - - return props; -}; - -},{}],34:[function(require,module,exports){ -'use strict'; - -/* ! - * Chai - checkError utility - * Copyright(c) 2012-2016 Jake Luer - * MIT Licensed - */ - -/** - * ### .checkError - * - * Checks that an error conforms to a given set of criteria and/or retrieves information about it. - * - * @api public - */ - -/** - * ### .compatibleInstance(thrown, errorLike) - * - * Checks if two instances are compatible (strict equal). - * Returns false if errorLike is not an instance of Error, because instances - * can only be compatible if they're both error instances. - * - * @name compatibleInstance - * @param {Error} thrown error - * @param {Error|ErrorConstructor} errorLike object to compare against - * @namespace Utils - * @api public - */ - -function compatibleInstance(thrown, errorLike) { - return errorLike instanceof Error && thrown === errorLike; -} - -/** - * ### .compatibleConstructor(thrown, errorLike) - * - * Checks if two constructors are compatible. - * This function can receive either an error constructor or - * an error instance as the `errorLike` argument. - * Constructors are compatible if they're the same or if one is - * an instance of another. - * - * @name compatibleConstructor - * @param {Error} thrown error - * @param {Error|ErrorConstructor} errorLike object to compare against - * @namespace Utils - * @api public - */ - -function compatibleConstructor(thrown, errorLike) { - if (errorLike instanceof Error) { - // If `errorLike` is an instance of any error we compare their constructors - return thrown.constructor === errorLike.constructor || thrown instanceof errorLike.constructor; - } else if (errorLike.prototype instanceof Error || errorLike === Error) { - // If `errorLike` is a constructor that inherits from Error, we compare `thrown` to `errorLike` directly - return thrown.constructor === errorLike || thrown instanceof errorLike; - } - - return false; -} - -/** - * ### .compatibleMessage(thrown, errMatcher) - * - * Checks if an error's message is compatible with a matcher (String or RegExp). - * If the message contains the String or passes the RegExp test, - * it is considered compatible. - * - * @name compatibleMessage - * @param {Error} thrown error - * @param {String|RegExp} errMatcher to look for into the message - * @namespace Utils - * @api public - */ - -function compatibleMessage(thrown, errMatcher) { - var comparisonString = typeof thrown === 'string' ? thrown : thrown.message; - if (errMatcher instanceof RegExp) { - return errMatcher.test(comparisonString); - } else if (typeof errMatcher === 'string') { - return comparisonString.indexOf(errMatcher) !== -1; // eslint-disable-line no-magic-numbers - } - - return false; -} - -/** - * ### .getFunctionName(constructorFn) - * - * Returns the name of a function. - * This also includes a polyfill function if `constructorFn.name` is not defined. - * - * @name getFunctionName - * @param {Function} constructorFn - * @namespace Utils - * @api private - */ - -var functionNameMatch = /\s*function(?:\s|\s*\/\*[^(?:*\/)]+\*\/\s*)*([^\(\/]+)/; -function getFunctionName(constructorFn) { - var name = ''; - if (typeof constructorFn.name === 'undefined') { - // Here we run a polyfill if constructorFn.name is not defined - var match = String(constructorFn).match(functionNameMatch); - if (match) { - name = match[1]; - } - } else { - name = constructorFn.name; - } - - return name; -} - -/** - * ### .getConstructorName(errorLike) - * - * Gets the constructor name for an Error instance or constructor itself. - * - * @name getConstructorName - * @param {Error|ErrorConstructor} errorLike - * @namespace Utils - * @api public - */ - -function getConstructorName(errorLike) { - var constructorName = errorLike; - if (errorLike instanceof Error) { - constructorName = getFunctionName(errorLike.constructor); - } else if (typeof errorLike === 'function') { - // If `err` is not an instance of Error it is an error constructor itself or another function. - // If we've got a common function we get its name, otherwise we may need to create a new instance - // of the error just in case it's a poorly-constructed error. Please see chaijs/chai/issues/45 to know more. - constructorName = getFunctionName(errorLike).trim() || - getFunctionName(new errorLike()); // eslint-disable-line new-cap - } - - return constructorName; -} - -/** - * ### .getMessage(errorLike) - * - * Gets the error message from an error. - * If `err` is a String itself, we return it. - * If the error has no message, we return an empty string. - * - * @name getMessage - * @param {Error|String} errorLike - * @namespace Utils - * @api public - */ - -function getMessage(errorLike) { - var msg = ''; - if (errorLike && errorLike.message) { - msg = errorLike.message; - } else if (typeof errorLike === 'string') { - msg = errorLike; - } - - return msg; -} - -module.exports = { - compatibleInstance: compatibleInstance, - compatibleConstructor: compatibleConstructor, - compatibleMessage: compatibleMessage, - getMessage: getMessage, - getConstructorName: getConstructorName, -}; - -},{}],35:[function(require,module,exports){ -'use strict'; -/* globals Symbol: false, Uint8Array: false, WeakMap: false */ -/*! - * deep-eql - * Copyright(c) 2013 Jake Luer - * MIT Licensed - */ - -var type = require('type-detect'); -function FakeMap() { - this._key = 'chai/deep-eql__' + Math.random() + Date.now(); -} - -FakeMap.prototype = { - get: function getMap(key) { - return key[this._key]; - }, - set: function setMap(key, value) { - if (!Object.isFrozen(key)) { - Object.defineProperty(key, this._key, { - value: value, - configurable: true, - }); - } - }, -}; - -var MemoizeMap = typeof WeakMap === 'function' ? WeakMap : FakeMap; -/*! - * Check to see if the MemoizeMap has recorded a result of the two operands - * - * @param {Mixed} leftHandOperand - * @param {Mixed} rightHandOperand - * @param {MemoizeMap} memoizeMap - * @returns {Boolean|null} result -*/ -function memoizeCompare(leftHandOperand, rightHandOperand, memoizeMap) { - // Technically, WeakMap keys can *only* be objects, not primitives. - if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) { - return null; - } - var leftHandMap = memoizeMap.get(leftHandOperand); - if (leftHandMap) { - var result = leftHandMap.get(rightHandOperand); - if (typeof result === 'boolean') { - return result; - } - } - return null; -} - -/*! - * Set the result of the equality into the MemoizeMap - * - * @param {Mixed} leftHandOperand - * @param {Mixed} rightHandOperand - * @param {MemoizeMap} memoizeMap - * @param {Boolean} result -*/ -function memoizeSet(leftHandOperand, rightHandOperand, memoizeMap, result) { - // Technically, WeakMap keys can *only* be objects, not primitives. - if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) { - return; - } - var leftHandMap = memoizeMap.get(leftHandOperand); - if (leftHandMap) { - leftHandMap.set(rightHandOperand, result); - } else { - leftHandMap = new MemoizeMap(); - leftHandMap.set(rightHandOperand, result); - memoizeMap.set(leftHandOperand, leftHandMap); - } -} - -/*! - * Primary Export - */ - -module.exports = deepEqual; -module.exports.MemoizeMap = MemoizeMap; - -/** - * Assert deeply nested sameValue equality between two objects of any type. - * - * @param {Mixed} leftHandOperand - * @param {Mixed} rightHandOperand - * @param {Object} [options] (optional) Additional options - * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality. - * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of - complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular - references to blow the stack. - * @return {Boolean} equal match - */ -function deepEqual(leftHandOperand, rightHandOperand, options) { - // If we have a comparator, we can't assume anything; so bail to its check first. - if (options && options.comparator) { - return extensiveDeepEqual(leftHandOperand, rightHandOperand, options); - } - - var simpleResult = simpleEqual(leftHandOperand, rightHandOperand); - if (simpleResult !== null) { - return simpleResult; - } - - // Deeper comparisons are pushed through to a larger function - return extensiveDeepEqual(leftHandOperand, rightHandOperand, options); -} - -/** - * Many comparisons can be canceled out early via simple equality or primitive checks. - * @param {Mixed} leftHandOperand - * @param {Mixed} rightHandOperand - * @return {Boolean|null} equal match - */ -function simpleEqual(leftHandOperand, rightHandOperand) { - // Equal references (except for Numbers) can be returned early - if (leftHandOperand === rightHandOperand) { - // Handle +-0 cases - return leftHandOperand !== 0 || 1 / leftHandOperand === 1 / rightHandOperand; - } - - // handle NaN cases - if ( - leftHandOperand !== leftHandOperand && // eslint-disable-line no-self-compare - rightHandOperand !== rightHandOperand // eslint-disable-line no-self-compare - ) { - return true; - } - - // Anything that is not an 'object', i.e. symbols, functions, booleans, numbers, - // strings, and undefined, can be compared by reference. - if (isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) { - // Easy out b/c it would have passed the first equality check - return false; - } - return null; -} - -/*! - * The main logic of the `deepEqual` function. - * - * @param {Mixed} leftHandOperand - * @param {Mixed} rightHandOperand - * @param {Object} [options] (optional) Additional options - * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality. - * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of - complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular - references to blow the stack. - * @return {Boolean} equal match -*/ -function extensiveDeepEqual(leftHandOperand, rightHandOperand, options) { - options = options || {}; - options.memoize = options.memoize === false ? false : options.memoize || new MemoizeMap(); - var comparator = options && options.comparator; - - // Check if a memoized result exists. - var memoizeResultLeft = memoizeCompare(leftHandOperand, rightHandOperand, options.memoize); - if (memoizeResultLeft !== null) { - return memoizeResultLeft; - } - var memoizeResultRight = memoizeCompare(rightHandOperand, leftHandOperand, options.memoize); - if (memoizeResultRight !== null) { - return memoizeResultRight; - } - - // If a comparator is present, use it. - if (comparator) { - var comparatorResult = comparator(leftHandOperand, rightHandOperand); - // Comparators may return null, in which case we want to go back to default behavior. - if (comparatorResult === false || comparatorResult === true) { - memoizeSet(leftHandOperand, rightHandOperand, options.memoize, comparatorResult); - return comparatorResult; - } - // To allow comparators to override *any* behavior, we ran them first. Since it didn't decide - // what to do, we need to make sure to return the basic tests first before we move on. - var simpleResult = simpleEqual(leftHandOperand, rightHandOperand); - if (simpleResult !== null) { - // Don't memoize this, it takes longer to set/retrieve than to just compare. - return simpleResult; - } - } - - var leftHandType = type(leftHandOperand); - if (leftHandType !== type(rightHandOperand)) { - memoizeSet(leftHandOperand, rightHandOperand, options.memoize, false); - return false; - } - - // Temporarily set the operands in the memoize object to prevent blowing the stack - memoizeSet(leftHandOperand, rightHandOperand, options.memoize, true); - - var result = extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options); - memoizeSet(leftHandOperand, rightHandOperand, options.memoize, result); - return result; -} - -function extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options) { - switch (leftHandType) { - case 'String': - case 'Number': - case 'Boolean': - case 'Date': - // If these types are their instance types (e.g. `new Number`) then re-deepEqual against their values - return deepEqual(leftHandOperand.valueOf(), rightHandOperand.valueOf()); - case 'Promise': - case 'Symbol': - case 'function': - case 'WeakMap': - case 'WeakSet': - case 'Error': - return leftHandOperand === rightHandOperand; - case 'Arguments': - case 'Int8Array': - case 'Uint8Array': - case 'Uint8ClampedArray': - case 'Int16Array': - case 'Uint16Array': - case 'Int32Array': - case 'Uint32Array': - case 'Float32Array': - case 'Float64Array': - case 'Array': - return iterableEqual(leftHandOperand, rightHandOperand, options); - case 'RegExp': - return regexpEqual(leftHandOperand, rightHandOperand); - case 'Generator': - return generatorEqual(leftHandOperand, rightHandOperand, options); - case 'DataView': - return iterableEqual(new Uint8Array(leftHandOperand.buffer), new Uint8Array(rightHandOperand.buffer), options); - case 'ArrayBuffer': - return iterableEqual(new Uint8Array(leftHandOperand), new Uint8Array(rightHandOperand), options); - case 'Set': - return entriesEqual(leftHandOperand, rightHandOperand, options); - case 'Map': - return entriesEqual(leftHandOperand, rightHandOperand, options); - default: - return objectEqual(leftHandOperand, rightHandOperand, options); - } -} - -/*! - * Compare two Regular Expressions for equality. - * - * @param {RegExp} leftHandOperand - * @param {RegExp} rightHandOperand - * @return {Boolean} result - */ - -function regexpEqual(leftHandOperand, rightHandOperand) { - return leftHandOperand.toString() === rightHandOperand.toString(); -} - -/*! - * Compare two Sets/Maps for equality. Faster than other equality functions. - * - * @param {Set} leftHandOperand - * @param {Set} rightHandOperand - * @param {Object} [options] (Optional) - * @return {Boolean} result - */ - -function entriesEqual(leftHandOperand, rightHandOperand, options) { - // IE11 doesn't support Set#entries or Set#@@iterator, so we need manually populate using Set#forEach - if (leftHandOperand.size !== rightHandOperand.size) { - return false; - } - if (leftHandOperand.size === 0) { - return true; - } - var leftHandItems = []; - var rightHandItems = []; - leftHandOperand.forEach(function gatherEntries(key, value) { - leftHandItems.push([ key, value ]); - }); - rightHandOperand.forEach(function gatherEntries(key, value) { - rightHandItems.push([ key, value ]); - }); - return iterableEqual(leftHandItems.sort(), rightHandItems.sort(), options); -} - -/*! - * Simple equality for flat iterable objects such as Arrays, TypedArrays or Node.js buffers. - * - * @param {Iterable} leftHandOperand - * @param {Iterable} rightHandOperand - * @param {Object} [options] (Optional) - * @return {Boolean} result - */ - -function iterableEqual(leftHandOperand, rightHandOperand, options) { - var length = leftHandOperand.length; - if (length !== rightHandOperand.length) { - return false; - } - if (length === 0) { - return true; - } - var index = -1; - while (++index < length) { - if (deepEqual(leftHandOperand[index], rightHandOperand[index], options) === false) { - return false; - } - } - return true; -} - -/*! - * Simple equality for generator objects such as those returned by generator functions. - * - * @param {Iterable} leftHandOperand - * @param {Iterable} rightHandOperand - * @param {Object} [options] (Optional) - * @return {Boolean} result - */ - -function generatorEqual(leftHandOperand, rightHandOperand, options) { - return iterableEqual(getGeneratorEntries(leftHandOperand), getGeneratorEntries(rightHandOperand), options); -} - -/*! - * Determine if the given object has an @@iterator function. - * - * @param {Object} target - * @return {Boolean} `true` if the object has an @@iterator function. - */ -function hasIteratorFunction(target) { - return typeof Symbol !== 'undefined' && - typeof target === 'object' && - typeof Symbol.iterator !== 'undefined' && - typeof target[Symbol.iterator] === 'function'; -} - -/*! - * Gets all iterator entries from the given Object. If the Object has no @@iterator function, returns an empty array. - * This will consume the iterator - which could have side effects depending on the @@iterator implementation. - * - * @param {Object} target - * @returns {Array} an array of entries from the @@iterator function - */ -function getIteratorEntries(target) { - if (hasIteratorFunction(target)) { - try { - return getGeneratorEntries(target[Symbol.iterator]()); - } catch (iteratorError) { - return []; - } - } - return []; -} - -/*! - * Gets all entries from a Generator. This will consume the generator - which could have side effects. - * - * @param {Generator} target - * @returns {Array} an array of entries from the Generator. - */ -function getGeneratorEntries(generator) { - var generatorResult = generator.next(); - var accumulator = [ generatorResult.value ]; - while (generatorResult.done === false) { - generatorResult = generator.next(); - accumulator.push(generatorResult.value); - } - return accumulator; -} - -/*! - * Gets all own and inherited enumerable keys from a target. - * - * @param {Object} target - * @returns {Array} an array of own and inherited enumerable keys from the target. - */ -function getEnumerableKeys(target) { - var keys = []; - for (var key in target) { - keys.push(key); - } - return keys; -} - -/*! - * Determines if two objects have matching values, given a set of keys. Defers to deepEqual for the equality check of - * each key. If any value of the given key is not equal, the function will return false (early). - * - * @param {Mixed} leftHandOperand - * @param {Mixed} rightHandOperand - * @param {Array} keys An array of keys to compare the values of leftHandOperand and rightHandOperand against - * @param {Object} [options] (Optional) - * @return {Boolean} result - */ -function keysEqual(leftHandOperand, rightHandOperand, keys, options) { - var length = keys.length; - if (length === 0) { - return true; - } - for (var i = 0; i < length; i += 1) { - if (deepEqual(leftHandOperand[keys[i]], rightHandOperand[keys[i]], options) === false) { - return false; - } - } - return true; -} - -/*! - * Recursively check the equality of two Objects. Once basic sameness has been established it will defer to `deepEqual` - * for each enumerable key in the object. - * - * @param {Mixed} leftHandOperand - * @param {Mixed} rightHandOperand - * @param {Object} [options] (Optional) - * @return {Boolean} result - */ - -function objectEqual(leftHandOperand, rightHandOperand, options) { - var leftHandKeys = getEnumerableKeys(leftHandOperand); - var rightHandKeys = getEnumerableKeys(rightHandOperand); - if (leftHandKeys.length && leftHandKeys.length === rightHandKeys.length) { - leftHandKeys.sort(); - rightHandKeys.sort(); - if (iterableEqual(leftHandKeys, rightHandKeys) === false) { - return false; - } - return keysEqual(leftHandOperand, rightHandOperand, leftHandKeys, options); - } - - var leftHandEntries = getIteratorEntries(leftHandOperand); - var rightHandEntries = getIteratorEntries(rightHandOperand); - if (leftHandEntries.length && leftHandEntries.length === rightHandEntries.length) { - leftHandEntries.sort(); - rightHandEntries.sort(); - return iterableEqual(leftHandEntries, rightHandEntries, options); - } - - if (leftHandKeys.length === 0 && - leftHandEntries.length === 0 && - rightHandKeys.length === 0 && - rightHandEntries.length === 0) { - return true; - } - - return false; -} - -/*! - * Returns true if the argument is a primitive. - * - * This intentionally returns true for all objects that can be compared by reference, - * including functions and symbols. - * - * @param {Mixed} value - * @return {Boolean} result - */ -function isPrimitive(value) { - return value === null || typeof value !== 'object'; -} - -},{"type-detect":38}],36:[function(require,module,exports){ -'use strict'; - -/* ! - * Chai - getFuncName utility - * Copyright(c) 2012-2016 Jake Luer - * MIT Licensed - */ - -/** - * ### .getFuncName(constructorFn) - * - * Returns the name of a function. - * When a non-function instance is passed, returns `null`. - * This also includes a polyfill function if `aFunc.name` is not defined. - * - * @name getFuncName - * @param {Function} funct - * @namespace Utils - * @api public - */ - -var toString = Function.prototype.toString; -var functionNameMatch = /\s*function(?:\s|\s*\/\*[^(?:*\/)]+\*\/\s*)*([^\s\(\/]+)/; -function getFuncName(aFunc) { - if (typeof aFunc !== 'function') { - return null; - } - - var name = ''; - if (typeof Function.prototype.name === 'undefined' && typeof aFunc.name === 'undefined') { - // Here we run a polyfill if Function does not support the `name` property and if aFunc.name is not defined - var match = toString.call(aFunc).match(functionNameMatch); - if (match) { - name = match[1]; - } - } else { - // If we've got a `name` property we just use it - name = aFunc.name; - } - - return name; -} - -module.exports = getFuncName; - -},{}],37:[function(require,module,exports){ -'use strict'; - -/* ! - * Chai - pathval utility - * Copyright(c) 2012-2014 Jake Luer - * @see https://github.com/logicalparadox/filtr - * MIT Licensed - */ - -/** - * ### .hasProperty(object, name) - * - * This allows checking whether an object has own - * or inherited from prototype chain named property. - * - * Basically does the same thing as the `in` - * operator but works properly with null/undefined values - * and other primitives. - * - * var obj = { - * arr: ['a', 'b', 'c'] - * , str: 'Hello' - * } - * - * The following would be the results. - * - * hasProperty(obj, 'str'); // true - * hasProperty(obj, 'constructor'); // true - * hasProperty(obj, 'bar'); // false - * - * hasProperty(obj.str, 'length'); // true - * hasProperty(obj.str, 1); // true - * hasProperty(obj.str, 5); // false - * - * hasProperty(obj.arr, 'length'); // true - * hasProperty(obj.arr, 2); // true - * hasProperty(obj.arr, 3); // false - * - * @param {Object} object - * @param {String|Symbol} name - * @returns {Boolean} whether it exists - * @namespace Utils - * @name hasProperty - * @api public - */ - -function hasProperty(obj, name) { - if (typeof obj === 'undefined' || obj === null) { - return false; - } - - // The `in` operator does not work with primitives. - return name in Object(obj); -} - -/* ! - * ## parsePath(path) - * - * Helper function used to parse string object - * paths. Use in conjunction with `internalGetPathValue`. - * - * var parsed = parsePath('myobject.property.subprop'); - * - * ### Paths: - * - * * Can be infinitely deep and nested. - * * Arrays are also valid using the formal `myobject.document[3].property`. - * * Literal dots and brackets (not delimiter) must be backslash-escaped. - * - * @param {String} path - * @returns {Object} parsed - * @api private - */ - -function parsePath(path) { - var str = path.replace(/([^\\])\[/g, '$1.['); - var parts = str.match(/(\\\.|[^.]+?)+/g); - return parts.map(function mapMatches(value) { - var regexp = /^\[(\d+)\]$/; - var mArr = regexp.exec(value); - var parsed = null; - if (mArr) { - parsed = { i: parseFloat(mArr[1]) }; - } else { - parsed = { p: value.replace(/\\([.\[\]])/g, '$1') }; - } - - return parsed; - }); -} - -/* ! - * ## internalGetPathValue(obj, parsed[, pathDepth]) - * - * Helper companion function for `.parsePath` that returns - * the value located at the parsed address. - * - * var value = getPathValue(obj, parsed); - * - * @param {Object} object to search against - * @param {Object} parsed definition from `parsePath`. - * @param {Number} depth (nesting level) of the property we want to retrieve - * @returns {Object|Undefined} value - * @api private - */ - -function internalGetPathValue(obj, parsed, pathDepth) { - var temporaryValue = obj; - var res = null; - pathDepth = (typeof pathDepth === 'undefined' ? parsed.length : pathDepth); - - for (var i = 0; i < pathDepth; i++) { - var part = parsed[i]; - if (temporaryValue) { - if (typeof part.p === 'undefined') { - temporaryValue = temporaryValue[part.i]; - } else { - temporaryValue = temporaryValue[part.p]; - } - - if (i === (pathDepth - 1)) { - res = temporaryValue; - } - } - } - - return res; -} - -/* ! - * ## internalSetPathValue(obj, value, parsed) - * - * Companion function for `parsePath` that sets - * the value located at a parsed address. - * - * internalSetPathValue(obj, 'value', parsed); - * - * @param {Object} object to search and define on - * @param {*} value to use upon set - * @param {Object} parsed definition from `parsePath` - * @api private - */ - -function internalSetPathValue(obj, val, parsed) { - var tempObj = obj; - var pathDepth = parsed.length; - var part = null; - // Here we iterate through every part of the path - for (var i = 0; i < pathDepth; i++) { - var propName = null; - var propVal = null; - part = parsed[i]; - - // If it's the last part of the path, we set the 'propName' value with the property name - if (i === (pathDepth - 1)) { - propName = typeof part.p === 'undefined' ? part.i : part.p; - // Now we set the property with the name held by 'propName' on object with the desired val - tempObj[propName] = val; - } else if (typeof part.p !== 'undefined' && tempObj[part.p]) { - tempObj = tempObj[part.p]; - } else if (typeof part.i !== 'undefined' && tempObj[part.i]) { - tempObj = tempObj[part.i]; - } else { - // If the obj doesn't have the property we create one with that name to define it - var next = parsed[i + 1]; - // Here we set the name of the property which will be defined - propName = typeof part.p === 'undefined' ? part.i : part.p; - // Here we decide if this property will be an array or a new object - propVal = typeof next.p === 'undefined' ? [] : {}; - tempObj[propName] = propVal; - tempObj = tempObj[propName]; - } - } -} - -/** - * ### .getPathInfo(object, path) - * - * This allows the retrieval of property info in an - * object given a string path. - * - * The path info consists of an object with the - * following properties: - * - * * parent - The parent object of the property referenced by `path` - * * name - The name of the final property, a number if it was an array indexer - * * value - The value of the property, if it exists, otherwise `undefined` - * * exists - Whether the property exists or not - * - * @param {Object} object - * @param {String} path - * @returns {Object} info - * @namespace Utils - * @name getPathInfo - * @api public - */ - -function getPathInfo(obj, path) { - var parsed = parsePath(path); - var last = parsed[parsed.length - 1]; - var info = { - parent: parsed.length > 1 ? internalGetPathValue(obj, parsed, parsed.length - 1) : obj, - name: last.p || last.i, - value: internalGetPathValue(obj, parsed), - }; - info.exists = hasProperty(info.parent, info.name); - - return info; -} - -/** - * ### .getPathValue(object, path) - * - * This allows the retrieval of values in an - * object given a string path. - * - * var obj = { - * prop1: { - * arr: ['a', 'b', 'c'] - * , str: 'Hello' - * } - * , prop2: { - * arr: [ { nested: 'Universe' } ] - * , str: 'Hello again!' - * } - * } - * - * The following would be the results. - * - * getPathValue(obj, 'prop1.str'); // Hello - * getPathValue(obj, 'prop1.att[2]'); // b - * getPathValue(obj, 'prop2.arr[0].nested'); // Universe - * - * @param {Object} object - * @param {String} path - * @returns {Object} value or `undefined` - * @namespace Utils - * @name getPathValue - * @api public - */ - -function getPathValue(obj, path) { - var info = getPathInfo(obj, path); - return info.value; -} - -/** - * ### .setPathValue(object, path, value) - * - * Define the value in an object at a given string path. - * - * ```js - * var obj = { - * prop1: { - * arr: ['a', 'b', 'c'] - * , str: 'Hello' - * } - * , prop2: { - * arr: [ { nested: 'Universe' } ] - * , str: 'Hello again!' - * } - * }; - * ``` - * - * The following would be acceptable. - * - * ```js - * var properties = require('tea-properties'); - * properties.set(obj, 'prop1.str', 'Hello Universe!'); - * properties.set(obj, 'prop1.arr[2]', 'B'); - * properties.set(obj, 'prop2.arr[0].nested.value', { hello: 'universe' }); - * ``` - * - * @param {Object} object - * @param {String} path - * @param {Mixed} value - * @api private - */ - -function setPathValue(obj, path, val) { - var parsed = parsePath(path); - internalSetPathValue(obj, val, parsed); - return obj; -} - -module.exports = { - hasProperty: hasProperty, - getPathInfo: getPathInfo, - getPathValue: getPathValue, - setPathValue: setPathValue, -}; - -},{}],38:[function(require,module,exports){ -'use strict'; - -/* ! - * type-detect - * Copyright(c) 2013 jake luer - * MIT Licensed - */ -var promiseExists = typeof Promise === 'function'; -var globalObject = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : self; // eslint-disable-line -var isDom = 'location' in globalObject && 'document' in globalObject; -var symbolExists = typeof Symbol !== 'undefined'; -var mapExists = typeof Map !== 'undefined'; -var setExists = typeof Set !== 'undefined'; -var weakMapExists = typeof WeakMap !== 'undefined'; -var weakSetExists = typeof WeakSet !== 'undefined'; -var dataViewExists = typeof DataView !== 'undefined'; -var symbolIteratorExists = symbolExists && typeof Symbol.iterator !== 'undefined'; -var symbolToStringTagExists = symbolExists && typeof Symbol.toStringTag !== 'undefined'; -var setEntriesExists = setExists && typeof Set.prototype.entries === 'function'; -var mapEntriesExists = mapExists && typeof Map.prototype.entries === 'function'; -var setIteratorPrototype = setEntriesExists && Object.getPrototypeOf(new Set().entries()); -var mapIteratorPrototype = mapEntriesExists && Object.getPrototypeOf(new Map().entries()); -var arrayIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function'; -var arrayIteratorPrototype = arrayIteratorExists && Object.getPrototypeOf([][Symbol.iterator]()); -var stringIteratorExists = symbolIteratorExists && typeof String.prototype[Symbol.iterator] === 'function'; -var stringIteratorPrototype = stringIteratorExists && Object.getPrototypeOf(''[Symbol.iterator]()); -var toStringLeftSliceLength = 8; -var toStringRightSliceLength = -1; -/** - * ### typeOf (obj) - * - * Uses `Object.prototype.toString` to determine the type of an object, - * normalising behaviour across engine versions & well optimised. - * - * @param {Mixed} object - * @return {String} object type - * @api public - */ -module.exports = function typeDetect(obj) { - /* ! Speed optimisation - * Pre: - * string literal x 3,039,035 ops/sec ±1.62% (78 runs sampled) - * boolean literal x 1,424,138 ops/sec ±4.54% (75 runs sampled) - * number literal x 1,653,153 ops/sec ±1.91% (82 runs sampled) - * undefined x 9,978,660 ops/sec ±1.92% (75 runs sampled) - * function x 2,556,769 ops/sec ±1.73% (77 runs sampled) - * Post: - * string literal x 38,564,796 ops/sec ±1.15% (79 runs sampled) - * boolean literal x 31,148,940 ops/sec ±1.10% (79 runs sampled) - * number literal x 32,679,330 ops/sec ±1.90% (78 runs sampled) - * undefined x 32,363,368 ops/sec ±1.07% (82 runs sampled) - * function x 31,296,870 ops/sec ±0.96% (83 runs sampled) - */ - var typeofObj = typeof obj; - if (typeofObj !== 'object') { - return typeofObj; - } - - /* ! Speed optimisation - * Pre: - * null x 28,645,765 ops/sec ±1.17% (82 runs sampled) - * Post: - * null x 36,428,962 ops/sec ±1.37% (84 runs sampled) - */ - if (obj === null) { - return 'null'; - } - - /* ! Spec Conformance - * Test: `Object.prototype.toString.call(window)`` - * - Node === "[object global]" - * - Chrome === "[object global]" - * - Firefox === "[object Window]" - * - PhantomJS === "[object Window]" - * - Safari === "[object Window]" - * - IE 11 === "[object Window]" - * - IE Edge === "[object Window]" - * Test: `Object.prototype.toString.call(this)`` - * - Chrome Worker === "[object global]" - * - Firefox Worker === "[object DedicatedWorkerGlobalScope]" - * - Safari Worker === "[object DedicatedWorkerGlobalScope]" - * - IE 11 Worker === "[object WorkerGlobalScope]" - * - IE Edge Worker === "[object WorkerGlobalScope]" - */ - if (obj === globalObject) { - return 'global'; - } - - /* ! Speed optimisation - * Pre: - * array literal x 2,888,352 ops/sec ±0.67% (82 runs sampled) - * Post: - * array literal x 22,479,650 ops/sec ±0.96% (81 runs sampled) - */ - if ( - Array.isArray(obj) && - (symbolToStringTagExists === false || !(Symbol.toStringTag in obj)) - ) { - return 'Array'; - } - - if (isDom) { - /* ! Spec Conformance - * (https://html.spec.whatwg.org/multipage/browsers.html#location) - * WhatWG HTML$7.7.3 - The `Location` interface - * Test: `Object.prototype.toString.call(window.location)`` - * - IE <=11 === "[object Object]" - * - IE Edge <=13 === "[object Object]" - */ - if (obj === globalObject.location) { - return 'Location'; - } - - /* ! Spec Conformance - * (https://html.spec.whatwg.org/#document) - * WhatWG HTML$3.1.1 - The `Document` object - * Note: Most browsers currently adher to the W3C DOM Level 2 spec - * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268) - * which suggests that browsers should use HTMLTableCellElement for - * both TD and TH elements. WhatWG separates these. - * WhatWG HTML states: - * > For historical reasons, Window objects must also have a - * > writable, configurable, non-enumerable property named - * > HTMLDocument whose value is the Document interface object. - * Test: `Object.prototype.toString.call(document)`` - * - Chrome === "[object HTMLDocument]" - * - Firefox === "[object HTMLDocument]" - * - Safari === "[object HTMLDocument]" - * - IE <=10 === "[object Document]" - * - IE 11 === "[object HTMLDocument]" - * - IE Edge <=13 === "[object HTMLDocument]" - */ - if (obj === globalObject.document) { - return 'Document'; - } - - /* ! Spec Conformance - * (https://html.spec.whatwg.org/multipage/webappapis.html#mimetypearray) - * WhatWG HTML$8.6.1.5 - Plugins - Interface MimeTypeArray - * Test: `Object.prototype.toString.call(navigator.mimeTypes)`` - * - IE <=10 === "[object MSMimeTypesCollection]" - */ - if (obj === (globalObject.navigator || {}).mimeTypes) { - return 'MimeTypeArray'; - } - - /* ! Spec Conformance - * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray) - * WhatWG HTML$8.6.1.5 - Plugins - Interface PluginArray - * Test: `Object.prototype.toString.call(navigator.plugins)`` - * - IE <=10 === "[object MSPluginsCollection]" - */ - if (obj === (globalObject.navigator || {}).plugins) { - return 'PluginArray'; - } - - /* ! Spec Conformance - * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray) - * WhatWG HTML$4.4.4 - The `blockquote` element - Interface `HTMLQuoteElement` - * Test: `Object.prototype.toString.call(document.createElement('blockquote'))`` - * - IE <=10 === "[object HTMLBlockElement]" - */ - if (obj instanceof HTMLElement && obj.tagName === 'BLOCKQUOTE') { - return 'HTMLQuoteElement'; - } - - /* ! Spec Conformance - * (https://html.spec.whatwg.org/#htmltabledatacellelement) - * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableDataCellElement` - * Note: Most browsers currently adher to the W3C DOM Level 2 spec - * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075) - * which suggests that browsers should use HTMLTableCellElement for - * both TD and TH elements. WhatWG separates these. - * Test: Object.prototype.toString.call(document.createElement('td')) - * - Chrome === "[object HTMLTableCellElement]" - * - Firefox === "[object HTMLTableCellElement]" - * - Safari === "[object HTMLTableCellElement]" - */ - if (obj instanceof HTMLElement && obj.tagName === 'TD') { - return 'HTMLTableDataCellElement'; - } - - /* ! Spec Conformance - * (https://html.spec.whatwg.org/#htmltableheadercellelement) - * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableHeaderCellElement` - * Note: Most browsers currently adher to the W3C DOM Level 2 spec - * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075) - * which suggests that browsers should use HTMLTableCellElement for - * both TD and TH elements. WhatWG separates these. - * Test: Object.prototype.toString.call(document.createElement('th')) - * - Chrome === "[object HTMLTableCellElement]" - * - Firefox === "[object HTMLTableCellElement]" - * - Safari === "[object HTMLTableCellElement]" - */ - if (obj instanceof HTMLElement && obj.tagName === 'TH') { - return 'HTMLTableHeaderCellElement'; - } - } - - /* ! Speed optimisation - * Pre: - * Float64Array x 625,644 ops/sec ±1.58% (80 runs sampled) - * Float32Array x 1,279,852 ops/sec ±2.91% (77 runs sampled) - * Uint32Array x 1,178,185 ops/sec ±1.95% (83 runs sampled) - * Uint16Array x 1,008,380 ops/sec ±2.25% (80 runs sampled) - * Uint8Array x 1,128,040 ops/sec ±2.11% (81 runs sampled) - * Int32Array x 1,170,119 ops/sec ±2.88% (80 runs sampled) - * Int16Array x 1,176,348 ops/sec ±5.79% (86 runs sampled) - * Int8Array x 1,058,707 ops/sec ±4.94% (77 runs sampled) - * Uint8ClampedArray x 1,110,633 ops/sec ±4.20% (80 runs sampled) - * Post: - * Float64Array x 7,105,671 ops/sec ±13.47% (64 runs sampled) - * Float32Array x 5,887,912 ops/sec ±1.46% (82 runs sampled) - * Uint32Array x 6,491,661 ops/sec ±1.76% (79 runs sampled) - * Uint16Array x 6,559,795 ops/sec ±1.67% (82 runs sampled) - * Uint8Array x 6,463,966 ops/sec ±1.43% (85 runs sampled) - * Int32Array x 5,641,841 ops/sec ±3.49% (81 runs sampled) - * Int16Array x 6,583,511 ops/sec ±1.98% (80 runs sampled) - * Int8Array x 6,606,078 ops/sec ±1.74% (81 runs sampled) - * Uint8ClampedArray x 6,602,224 ops/sec ±1.77% (83 runs sampled) - */ - var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]); - if (typeof stringTag === 'string') { - return stringTag; - } - - var objPrototype = Object.getPrototypeOf(obj); - /* ! Speed optimisation - * Pre: - * regex literal x 1,772,385 ops/sec ±1.85% (77 runs sampled) - * regex constructor x 2,143,634 ops/sec ±2.46% (78 runs sampled) - * Post: - * regex literal x 3,928,009 ops/sec ±0.65% (78 runs sampled) - * regex constructor x 3,931,108 ops/sec ±0.58% (84 runs sampled) - */ - if (objPrototype === RegExp.prototype) { - return 'RegExp'; - } - - /* ! Speed optimisation - * Pre: - * date x 2,130,074 ops/sec ±4.42% (68 runs sampled) - * Post: - * date x 3,953,779 ops/sec ±1.35% (77 runs sampled) - */ - if (objPrototype === Date.prototype) { - return 'Date'; - } - - /* ! Spec Conformance - * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype-@@tostringtag) - * ES6$25.4.5.4 - Promise.prototype[@@toStringTag] should be "Promise": - * Test: `Object.prototype.toString.call(Promise.resolve())`` - * - Chrome <=47 === "[object Object]" - * - Edge <=20 === "[object Object]" - * - Firefox 29-Latest === "[object Promise]" - * - Safari 7.1-Latest === "[object Promise]" - */ - if (promiseExists && objPrototype === Promise.prototype) { - return 'Promise'; - } - - /* ! Speed optimisation - * Pre: - * set x 2,222,186 ops/sec ±1.31% (82 runs sampled) - * Post: - * set x 4,545,879 ops/sec ±1.13% (83 runs sampled) - */ - if (setExists && objPrototype === Set.prototype) { - return 'Set'; - } - - /* ! Speed optimisation - * Pre: - * map x 2,396,842 ops/sec ±1.59% (81 runs sampled) - * Post: - * map x 4,183,945 ops/sec ±6.59% (82 runs sampled) - */ - if (mapExists && objPrototype === Map.prototype) { - return 'Map'; - } - - /* ! Speed optimisation - * Pre: - * weakset x 1,323,220 ops/sec ±2.17% (76 runs sampled) - * Post: - * weakset x 4,237,510 ops/sec ±2.01% (77 runs sampled) - */ - if (weakSetExists && objPrototype === WeakSet.prototype) { - return 'WeakSet'; - } - - /* ! Speed optimisation - * Pre: - * weakmap x 1,500,260 ops/sec ±2.02% (78 runs sampled) - * Post: - * weakmap x 3,881,384 ops/sec ±1.45% (82 runs sampled) - */ - if (weakMapExists && objPrototype === WeakMap.prototype) { - return 'WeakMap'; - } - - /* ! Spec Conformance - * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-dataview.prototype-@@tostringtag) - * ES6$24.2.4.21 - DataView.prototype[@@toStringTag] should be "DataView": - * Test: `Object.prototype.toString.call(new DataView(new ArrayBuffer(1)))`` - * - Edge <=13 === "[object Object]" - */ - if (dataViewExists && objPrototype === DataView.prototype) { - return 'DataView'; - } - - /* ! Spec Conformance - * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%mapiteratorprototype%-@@tostringtag) - * ES6$23.1.5.2.2 - %MapIteratorPrototype%[@@toStringTag] should be "Map Iterator": - * Test: `Object.prototype.toString.call(new Map().entries())`` - * - Edge <=13 === "[object Object]" - */ - if (mapExists && objPrototype === mapIteratorPrototype) { - return 'Map Iterator'; - } - - /* ! Spec Conformance - * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%setiteratorprototype%-@@tostringtag) - * ES6$23.2.5.2.2 - %SetIteratorPrototype%[@@toStringTag] should be "Set Iterator": - * Test: `Object.prototype.toString.call(new Set().entries())`` - * - Edge <=13 === "[object Object]" - */ - if (setExists && objPrototype === setIteratorPrototype) { - return 'Set Iterator'; - } - - /* ! Spec Conformance - * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%-@@tostringtag) - * ES6$22.1.5.2.2 - %ArrayIteratorPrototype%[@@toStringTag] should be "Array Iterator": - * Test: `Object.prototype.toString.call([][Symbol.iterator]())`` - * - Edge <=13 === "[object Object]" - */ - if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) { - return 'Array Iterator'; - } - - /* ! Spec Conformance - * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%stringiteratorprototype%-@@tostringtag) - * ES6$21.1.5.2.2 - %StringIteratorPrototype%[@@toStringTag] should be "String Iterator": - * Test: `Object.prototype.toString.call(''[Symbol.iterator]())`` - * - Edge <=13 === "[object Object]" - */ - if (stringIteratorExists && objPrototype === stringIteratorPrototype) { - return 'String Iterator'; - } - - /* ! Speed optimisation - * Pre: - * object from null x 2,424,320 ops/sec ±1.67% (76 runs sampled) - * Post: - * object from null x 5,838,000 ops/sec ±0.99% (84 runs sampled) - */ - if (objPrototype === null) { - return 'Object'; - } - - return Object - .prototype - .toString - .call(obj) - .slice(toStringLeftSliceLength, toStringRightSliceLength); -}; - -module.exports.typeDetect = module.exports; - -},{}]},{},[1])(1) -}); \ No newline at end of file diff --git a/src/bin/test/main.rs b/src/bin/test/main.rs deleted file mode 100644 index 3904ff9..0000000 --- a/src/bin/test/main.rs +++ /dev/null @@ -1,68 +0,0 @@ -extern crate fly; - -#[macro_use] -extern crate log; -extern crate env_logger; -use env_logger::Env; - -extern crate libfly; - -use fly::runtime::Runtime; -use fly::settings::SETTINGS; -use std::env; - -extern crate futures; -use futures::Future; - -extern crate tokio; - -use std::str; - -extern crate glob; -use glob::glob; - -// const LIB_SOURCE: &'static [u8] = include_bytes!("lib.js"); -const MOCHA_SOURCE: &'static [u8] = include_bytes!("mocha.js"); -const CHAI_SOURCE: &'static [u8] = include_bytes!("chai.js"); -// const EXPECT_SOURCE: &'static [u8] = include_bytes!("expect.js"); -const SETUP_SOURCE: &'static [u8] = include_bytes!("setup.js"); -const RUN_SOURCE: &'static [u8] = include_bytes!("run.js"); - -const FLY_TESTING_SOURCE: &'static [u8] = include_bytes!("../../../v8env/dist/testing.js"); - -fn main() { - let env = Env::default().filter_or("LOG_LEVEL", "info"); - env_logger::init_from_env(env); - - let mut rt = Runtime::new(None, None, &SETTINGS.read().unwrap()); - rt.eval("mocha.js", str::from_utf8(MOCHA_SOURCE).unwrap()); - rt.eval("chai.js", str::from_utf8(CHAI_SOURCE).unwrap()); - rt.eval("testing.js", str::from_utf8(FLY_TESTING_SOURCE).unwrap()); - rt.eval("setup.js", str::from_utf8(SETUP_SOURCE).unwrap()); - - let args: Vec = env::args().collect(); - - let mut patterns: Vec = args[1..].to_vec(); - - debug!("args: {:?}", &args); - debug!("patterns: {:?}", &patterns); - - if patterns.len() == 0 { - patterns.push(String::from("./**/*[._]spec.js")); - patterns.push(String::from("./**/*[._]test.js")); - } - - for pattern in patterns { - for path in glob(&pattern).unwrap().filter_map(Result::ok) { - debug!("{}", path.display()); - rt.eval_file(path.to_str().expect("invalid path")); - } - } - - rt.eval("run.js", str::from_utf8(RUN_SOURCE).unwrap()); - - tokio::run( - rt.run() - .map_err(|_| error!("error running runtime event loop")), - ); -} diff --git a/src/bin/test/mocha.js b/src/bin/test/mocha.js deleted file mode 100644 index 7b849fd..0000000 --- a/src/bin/test/mocha.js +++ /dev/null @@ -1,15373 +0,0 @@ -require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1) { - suites.shift(); - } - return common.suite.create({ - title: title, - file: file, - fn: false - }); - }; - - /** - * Exclusive Suite. - */ - - context.suite.only = function (title) { - if (suites.length > 1) { - suites.shift(); - } - return common.suite.only({ - title: title, - file: file, - fn: false - }); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function (title, fn) { - var test = new Test(title, fn); - test.file = file; - suites[0].addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.test.only = function (title, fn) { - return common.test.only(mocha, context.test(title, fn)); - }; - - context.test.skip = common.test.skip; - context.test.retries = common.test.retries; - }); -}; - -},{"../test":35,"./common":8}],12:[function(require,module,exports){ -'use strict'; - -/** - * Module dependencies. - */ - -var Test = require('../test'); - -/** - * TDD-style interface: - * - * suite('Array', function() { - * suite('#indexOf()', function() { - * suiteSetup(function() { - * - * }); - * - * test('should return -1 when not present', function() { - * - * }); - * - * test('should return the index when present', function() { - * - * }); - * - * suiteTeardown(function() { - * - * }); - * }); - * }); - * - * @param {Suite} suite Root suite. - */ -module.exports = function (suite) { - var suites = [suite]; - - suite.on('pre-require', function (context, file, mocha) { - var common = require('./common')(suites, context, mocha); - - context.setup = common.beforeEach; - context.teardown = common.afterEach; - context.suiteSetup = common.before; - context.suiteTeardown = common.after; - context.run = mocha.options.delay && common.runWithSuite(suite); - - /** - * Describe a "suite" with the given `title` and callback `fn` containing - * nested suites and/or tests. - */ - context.suite = function (title, fn) { - return common.suite.create({ - title: title, - file: file, - fn: fn - }); - }; - - /** - * Pending suite. - */ - context.suite.skip = function (title, fn) { - return common.suite.skip({ - title: title, - file: file, - fn: fn - }); - }; - - /** - * Exclusive test-case. - */ - context.suite.only = function (title, fn) { - return common.suite.only({ - title: title, - file: file, - fn: fn - }); - }; - - /** - * Describe a specification or test-case with the given `title` and - * callback `fn` acting as a thunk. - */ - context.test = function (title, fn) { - var suite = suites[0]; - if (suite.isPending()) { - fn = null; - } - var test = new Test(title, fn); - test.file = file; - suite.addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.test.only = function (title, fn) { - return common.test.only(mocha, context.test(title, fn)); - }; - - context.test.skip = common.test.skip; - context.test.retries = common.test.retries; - }); -}; - -},{"../test":35,"./common":8}],13:[function(require,module,exports){ -(function (process,global,__dirname){ -'use strict'; - -/*! - * mocha - * Copyright(c) 2011 TJ Holowaychuk - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var escapeRe = require('escape-string-regexp'); -var path = require('path'); -var reporters = require('./reporters'); -var utils = require('./utils'); - -/** - * Expose `Mocha`. - */ - -exports = module.exports = Mocha; - -/** - * To require local UIs and reporters when running in node. - */ - -if (!process.browser) { - var cwd = process.cwd(); - module.paths.push(cwd, path.join(cwd, 'node_modules')); -} - -/** - * Expose internals. - */ - -exports.utils = utils; -exports.interfaces = require('./interfaces'); -exports.reporters = reporters; -exports.Runnable = require('./runnable'); -exports.Context = require('./context'); -exports.Runner = require('./runner'); -exports.Suite = require('./suite'); -exports.Hook = require('./hook'); -exports.Test = require('./test'); - -/** - * Return image `name` path. - * - * @api private - * @param {string} name - * @return {string} - */ -function image (name) { - return path.join(__dirname, '../images', name + '.png'); -} - -/** - * Set up mocha with `options`. - * - * Options: - * - * - `ui` name "bdd", "tdd", "exports" etc - * - `reporter` reporter instance, defaults to `mocha.reporters.spec` - * - `globals` array of accepted globals - * - `timeout` timeout in milliseconds - * - `retries` number of times to retry failed tests - * - `bail` bail on the first test failure - * - `slow` milliseconds to wait before considering a test slow - * - `ignoreLeaks` ignore global leaks - * - `fullTrace` display the full stack-trace on failing - * - `grep` string or regexp to filter tests with - * - * @param {Object} options - * @api public - */ -function Mocha (options) { - options = options || {}; - this.files = []; - this.options = options; - if (options.grep) { - this.grep(new RegExp(options.grep)); - } - if (options.fgrep) { - this.fgrep(options.fgrep); - } - this.suite = new exports.Suite('', new exports.Context()); - this.ui(options.ui); - this.bail(options.bail); - this.reporter(options.reporter, options.reporterOptions); - if (typeof options.timeout !== 'undefined' && options.timeout !== null) { - this.timeout(options.timeout); - } - if (typeof options.retries !== 'undefined' && options.retries !== null) { - this.retries(options.retries); - } - this.useColors(options.useColors); - if (options.enableTimeouts !== null) { - this.enableTimeouts(options.enableTimeouts); - } - if (options.slow) { - this.slow(options.slow); - } -} - -/** - * Enable or disable bailing on the first failure. - * - * @api public - * @param {boolean} [bail] - */ -Mocha.prototype.bail = function (bail) { - if (!arguments.length) { - bail = true; - } - this.suite.bail(bail); - return this; -}; - -/** - * Add test `file`. - * - * @api public - * @param {string} file - */ -Mocha.prototype.addFile = function (file) { - this.files.push(file); - return this; -}; - -/** - * Set reporter to `reporter`, defaults to "spec". - * - * @param {String|Function} reporter name or constructor - * @param {Object} reporterOptions optional options - * @api public - * @param {string|Function} reporter name or constructor - * @param {Object} reporterOptions optional options - */ -Mocha.prototype.reporter = function (reporter, reporterOptions) { - if (typeof reporter === 'function') { - this._reporter = reporter; - } else { - reporter = reporter || 'spec'; - var _reporter; - // Try to load a built-in reporter. - if (reporters[reporter]) { - _reporter = reporters[reporter]; - } - // Try to load reporters from process.cwd() and node_modules - if (!_reporter) { - try { - _reporter = require(reporter); - } catch (err) { - if (err.message.indexOf('Cannot find module') !== -1) { - // Try to load reporters from a path (absolute or relative) - try { - _reporter = require(path.resolve(process.cwd(), reporter)); - } catch (_err) { - err.message.indexOf('Cannot find module') !== -1 ? console.warn('"' + reporter + '" reporter not found') - : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack); - } - } else { - console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack); - } - } - } - if (!_reporter && reporter === 'teamcity') { - console.warn('The Teamcity reporter was moved to a package named ' + - 'mocha-teamcity-reporter ' + - '(https://npmjs.org/package/mocha-teamcity-reporter).'); - } - if (!_reporter) { - throw new Error('invalid reporter "' + reporter + '"'); - } - this._reporter = _reporter; - } - this.options.reporterOptions = reporterOptions; - return this; -}; - -/** - * Set test UI `name`, defaults to "bdd". - * - * @api public - * @param {string} bdd - */ -Mocha.prototype.ui = function (name) { - name = name || 'bdd'; - this._ui = exports.interfaces[name]; - if (!this._ui) { - try { - this._ui = require(name); - } catch (err) { - throw new Error('invalid interface "' + name + '"'); - } - } - this._ui = this._ui(this.suite); - - this.suite.on('pre-require', function (context) { - exports.afterEach = context.afterEach || context.teardown; - exports.after = context.after || context.suiteTeardown; - exports.beforeEach = context.beforeEach || context.setup; - exports.before = context.before || context.suiteSetup; - exports.describe = context.describe || context.suite; - exports.it = context.it || context.test; - exports.xit = context.xit || context.test.skip; - exports.setup = context.setup || context.beforeEach; - exports.suiteSetup = context.suiteSetup || context.before; - exports.suiteTeardown = context.suiteTeardown || context.after; - exports.suite = context.suite || context.describe; - exports.teardown = context.teardown || context.afterEach; - exports.test = context.test || context.it; - exports.run = context.run; - }); - - return this; -}; - -/** - * Load registered files. - * - * @api private - */ -Mocha.prototype.loadFiles = function (fn) { - var self = this; - var suite = this.suite; - this.files.forEach(function (file) { - file = path.resolve(file); - suite.emit('pre-require', global, file, self); - suite.emit('require', require(file), file, self); - suite.emit('post-require', global, file, self); - }); - fn && fn(); -}; - -/** - * Enable growl support. - * - * @api private - */ -Mocha.prototype._growl = function (runner, reporter) { - var notify = require('growl'); - - runner.on('end', function () { - var stats = reporter.stats; - if (stats.failures) { - var msg = stats.failures + ' of ' + runner.total + ' tests failed'; - notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); - } else { - notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { - name: 'mocha', - title: 'Passed', - image: image('ok') - }); - } - }); -}; - -/** - * Escape string and add it to grep as a regexp. - * - * @api public - * @param str - * @returns {Mocha} - */ -Mocha.prototype.fgrep = function (str) { - return this.grep(new RegExp(escapeRe(str))); -}; - -/** - * Add regexp to grep, if `re` is a string it is escaped. - * - * @param {RegExp|String} re - * @return {Mocha} - * @api public - * @param {RegExp|string} re - * @return {Mocha} - */ -Mocha.prototype.grep = function (re) { - if (utils.isString(re)) { - // extract args if it's regex-like, i.e: [string, pattern, flag] - var arg = re.match(/^\/(.*)\/(g|i|)$|.*/); - this.options.grep = new RegExp(arg[1] || arg[0], arg[2]); - } else { - this.options.grep = re; - } - return this; -}; -/** - * Invert `.grep()` matches. - * - * @return {Mocha} - * @api public - */ -Mocha.prototype.invert = function () { - this.options.invert = true; - return this; -}; - -/** - * Ignore global leaks. - * - * @param {Boolean} ignore - * @return {Mocha} - * @api public - * @param {boolean} ignore - * @return {Mocha} - */ -Mocha.prototype.ignoreLeaks = function (ignore) { - this.options.ignoreLeaks = Boolean(ignore); - return this; -}; - -/** - * Enable global leak checking. - * - * @return {Mocha} - * @api public - */ -Mocha.prototype.checkLeaks = function () { - this.options.ignoreLeaks = false; - return this; -}; - -/** - * Display long stack-trace on failing - * - * @return {Mocha} - * @api public - */ -Mocha.prototype.fullTrace = function () { - this.options.fullStackTrace = true; - return this; -}; - -/** - * Enable growl support. - * - * @return {Mocha} - * @api public - */ -Mocha.prototype.growl = function () { - this.options.growl = true; - return this; -}; - -/** - * Ignore `globals` array or string. - * - * @param {Array|String} globals - * @return {Mocha} - * @api public - * @param {Array|string} globals - * @return {Mocha} - */ -Mocha.prototype.globals = function (globals) { - this.options.globals = (this.options.globals || []).concat(globals); - return this; -}; - -/** - * Emit color output. - * - * @param {Boolean} colors - * @return {Mocha} - * @api public - * @param {boolean} colors - * @return {Mocha} - */ -Mocha.prototype.useColors = function (colors) { - if (colors !== undefined) { - this.options.useColors = colors; - } - return this; -}; - -/** - * Use inline diffs rather than +/-. - * - * @param {Boolean} inlineDiffs - * @return {Mocha} - * @api public - * @param {boolean} inlineDiffs - * @return {Mocha} - */ -Mocha.prototype.useInlineDiffs = function (inlineDiffs) { - this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs; - return this; -}; - -/** - * Set the timeout in milliseconds. - * - * @param {Number} timeout - * @return {Mocha} - * @api public - * @param {number} timeout - * @return {Mocha} - */ -Mocha.prototype.timeout = function (timeout) { - this.suite.timeout(timeout); - return this; -}; - -/** - * Set the number of times to retry failed tests. - * - * @param {Number} retry times - * @return {Mocha} - * @api public - */ -Mocha.prototype.retries = function (n) { - this.suite.retries(n); - return this; -}; - -/** - * Set slowness threshold in milliseconds. - * - * @param {Number} slow - * @return {Mocha} - * @api public - * @param {number} slow - * @return {Mocha} - */ -Mocha.prototype.slow = function (slow) { - this.suite.slow(slow); - return this; -}; - -/** - * Enable timeouts. - * - * @param {Boolean} enabled - * @return {Mocha} - * @api public - * @param {boolean} enabled - * @return {Mocha} - */ -Mocha.prototype.enableTimeouts = function (enabled) { - this.suite.enableTimeouts(arguments.length && enabled !== undefined ? enabled : true); - return this; -}; - -/** - * Makes all tests async (accepting a callback) - * - * @return {Mocha} - * @api public - */ -Mocha.prototype.asyncOnly = function () { - this.options.asyncOnly = true; - return this; -}; - -/** - * Disable syntax highlighting (in browser). - * - * @api public - */ -Mocha.prototype.noHighlighting = function () { - this.options.noHighlighting = true; - return this; -}; - -/** - * Enable uncaught errors to propagate (in browser). - * - * @return {Mocha} - * @api public - */ -Mocha.prototype.allowUncaught = function () { - this.options.allowUncaught = true; - return this; -}; - -/** - * Delay root suite execution. - * @returns {Mocha} - */ -Mocha.prototype.delay = function delay () { - this.options.delay = true; - return this; -}; - -/** - * Tests marked only fail the suite - * @returns {Mocha} - */ -Mocha.prototype.forbidOnly = function () { - this.options.forbidOnly = true; - return this; -}; - -/** - * Pending tests and tests marked skip fail the suite - * @returns {Mocha} - */ -Mocha.prototype.forbidPending = function () { - this.options.forbidPending = true; - return this; -}; - -/** - * Run tests and invoke `fn()` when complete. - * - * @api public - * @param {Function} fn - * @return {Runner} - */ -Mocha.prototype.run = function (fn) { - if (this.files.length) { - this.loadFiles(); - } - var suite = this.suite; - var options = this.options; - options.files = this.files; - var runner = new exports.Runner(suite, options.delay); - var reporter = new this._reporter(runner, options); - runner.ignoreLeaks = options.ignoreLeaks !== false; - runner.fullStackTrace = options.fullStackTrace; - runner.asyncOnly = options.asyncOnly; - runner.allowUncaught = options.allowUncaught; - runner.forbidOnly = options.forbidOnly; - runner.forbidPending = options.forbidPending; - if (options.grep) { - runner.grep(options.grep, options.invert); - } - if (options.globals) { - runner.globals(options.globals); - } - if (options.growl) { - this._growl(runner, reporter); - } - if (options.useColors !== undefined) { - exports.reporters.Base.useColors = options.useColors; - } - exports.reporters.Base.inlineDiffs = options.useInlineDiffs; - - function done (failures) { - if (reporter.done) { - reporter.done(failures, fn); - } else { - fn && fn(failures); - } - } - - return runner.run(done); -}; - -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/lib") -},{"./context":5,"./hook":6,"./interfaces":10,"./reporters":20,"./runnable":32,"./runner":33,"./suite":34,"./test":35,"./utils":36,"_process":55,"escape-string-regexp":45,"growl":2,"path":40}],14:[function(require,module,exports){ -'use strict'; - -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @api public - * @param {string|number} val - * @param {Object} options - * @return {string|number} - */ -module.exports = function (val, options) { - options = options || {}; - if (typeof val === 'string') { - return parse(val); - } - // https://github.com/mochajs/mocha/pull/1035 - return options['long'] ? longFormat(val) : shortFormat(val); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @api private - * @param {string} str - * @return {number} - */ -function parse (str) { - var match = (/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i).exec(str); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 's': - return n * s; - case 'ms': - return n; - default: - // No default case - } -} - -/** - * Short format for `ms`. - * - * @api private - * @param {number} ms - * @return {string} - */ -function shortFormat (ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @api private - * @param {number} ms - * @return {string} - */ -function longFormat (ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; -} - -/** - * Pluralization helper. - * - * @api private - * @param {number} ms - * @param {number} n - * @param {string} name - */ -function plural (ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; -} - -},{}],15:[function(require,module,exports){ -'use strict'; - -/** - * Expose `Pending`. - */ - -module.exports = Pending; - -/** - * Initialize a new `Pending` error with the given message. - * - * @param {string} message - */ -function Pending (message) { - this.message = message; -} - -},{}],16:[function(require,module,exports){ -(function (process,global){ -'use strict'; - -/** - * Module dependencies. - */ - -var tty = require('tty'); -var diff = require('diff'); -var ms = require('../ms'); -var utils = require('../utils'); -var supportsColor = process.browser ? null : require('supports-color'); - -/** - * Expose `Base`. - */ - -exports = module.exports = Base; - -/** - * Save timer references to avoid Sinon interfering. - * See: https://github.com/mochajs/mocha/issues/237 - */ - -/* eslint-disable no-unused-vars, no-native-reassign */ -var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ - -/** - * Check if both stdio streams are associated with a tty. - */ - -var isatty = tty.isatty(1) && tty.isatty(2); - -/** - * Enable coloring by default, except in the browser interface. - */ - -exports.useColors = !process.browser && (supportsColor || (process.env.MOCHA_COLORS !== undefined)); - -/** - * Inline diffs instead of +/- - */ - -exports.inlineDiffs = false; - -/** - * Default color map. - */ - -exports.colors = { - pass: 90, - fail: 31, - 'bright pass': 92, - 'bright fail': 91, - 'bright yellow': 93, - pending: 36, - suite: 0, - 'error title': 0, - 'error message': 31, - 'error stack': 90, - checkmark: 32, - fast: 90, - medium: 33, - slow: 31, - green: 32, - light: 90, - 'diff gutter': 90, - 'diff added': 32, - 'diff removed': 31 -}; - -/** - * Default symbol map. - */ - -exports.symbols = { - ok: '✓', - err: '✖', - dot: '․', - comma: ',', - bang: '!' -}; - -// With node.js on Windows: use symbols available in terminal default fonts -if (process.platform === 'win32') { - exports.symbols.ok = '\u221A'; - exports.symbols.err = '\u00D7'; - exports.symbols.dot = '.'; -} - -/** - * Color `str` with the given `type`, - * allowing colors to be disabled, - * as well as user-defined color - * schemes. - * - * @param {string} type - * @param {string} str - * @return {string} - * @api private - */ -var color = exports.color = function (type, str) { - if (!exports.useColors) { - return String(str); - } - return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; -}; - -/** - * Expose term window size, with some defaults for when stderr is not a tty. - */ - -exports.window = { - width: 75 -}; - -if (isatty) { - exports.window.width = process.stdout.getWindowSize - ? process.stdout.getWindowSize(1)[0] - : tty.getWindowSize()[1]; -} - -/** - * Expose some basic cursor interactions that are common among reporters. - */ - -exports.cursor = { - hide: function () { - isatty && process.stdout.write('\u001b[?25l'); - }, - - show: function () { - isatty && process.stdout.write('\u001b[?25h'); - }, - - deleteLine: function () { - isatty && process.stdout.write('\u001b[2K'); - }, - - beginningOfLine: function () { - isatty && process.stdout.write('\u001b[0G'); - }, - - CR: function () { - if (isatty) { - exports.cursor.deleteLine(); - exports.cursor.beginningOfLine(); - } else { - process.stdout.write('\r'); - } - } -}; - -/** - * Output the given `failures` as a list. - * - * @param {Array} failures - * @api public - */ - -exports.list = function (failures) { - console.log(); - failures.forEach(function (test, i) { - // format - var fmt = color('error title', ' %s) %s:\n') + - color('error message', ' %s') + - color('error stack', '\n%s\n'); - - // msg - var msg; - var err = test.err; - var message; - if (err.message && typeof err.message.toString === 'function') { - message = err.message + ''; - } else if (typeof err.inspect === 'function') { - message = err.inspect() + ''; - } else { - message = ''; - } - var stack = err.stack || message; - var index = message ? stack.indexOf(message) : -1; - var actual = err.actual; - var expected = err.expected; - var escape = true; - - if (index === -1) { - msg = message; - } else { - index += message.length; - msg = stack.slice(0, index); - // remove msg from stack - stack = stack.slice(index + 1); - } - - // uncaught - if (err.uncaught) { - msg = 'Uncaught ' + msg; - } - // explicitly show diff - if (err.showDiff !== false && sameType(actual, expected) && expected !== undefined) { - escape = false; - if (!(utils.isString(actual) && utils.isString(expected))) { - err.actual = actual = utils.stringify(actual); - err.expected = expected = utils.stringify(expected); - } - - fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); - var match = message.match(/^([^:]+): expected/); - msg = '\n ' + color('error message', match ? match[1] : msg); - - if (exports.inlineDiffs) { - msg += inlineDiff(err, escape); - } else { - msg += unifiedDiff(err, escape); - } - } - - // indent stack trace - stack = stack.replace(/^/gm, ' '); - - // indented test title - var testTitle = ''; - test.titlePath().forEach(function (str, index) { - if (index !== 0) { - testTitle += '\n '; - } - for (var i = 0; i < index; i++) { - testTitle += ' '; - } - testTitle += str; - }); - - console.log(fmt, (i + 1), testTitle, msg, stack); - }); -}; - -/** - * Initialize a new `Base` reporter. - * - * All other reporters generally - * inherit from this reporter, providing - * stats such as test duration, number - * of tests passed / failed etc. - * - * @param {Runner} runner - * @api public - */ - -function Base (runner) { - var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; - var failures = this.failures = []; - - if (!runner) { - return; - } - this.runner = runner; - - runner.stats = stats; - - runner.on('start', function () { - stats.start = new Date(); - }); - - runner.on('suite', function (suite) { - stats.suites = stats.suites || 0; - suite.root || stats.suites++; - }); - - runner.on('test end', function () { - stats.tests = stats.tests || 0; - stats.tests++; - }); - - runner.on('pass', function (test) { - stats.passes = stats.passes || 0; - - if (test.duration > test.slow()) { - test.speed = 'slow'; - } else if (test.duration > test.slow() / 2) { - test.speed = 'medium'; - } else { - test.speed = 'fast'; - } - - stats.passes++; - }); - - runner.on('fail', function (test, err) { - stats.failures = stats.failures || 0; - stats.failures++; - test.err = err; - failures.push(test); - }); - - runner.on('end', function () { - stats.end = new Date(); - stats.duration = new Date() - stats.start; - }); - - runner.on('pending', function () { - stats.pending++; - }); -} - -/** - * Output common epilogue used by many of - * the bundled reporters. - * - * @api public - */ -Base.prototype.epilogue = function () { - var stats = this.stats; - var fmt; - - console.log(); - - // passes - fmt = color('bright pass', ' ') + - color('green', ' %d passing') + - color('light', ' (%s)'); - - console.log(fmt, - stats.passes || 0, - ms(stats.duration)); - - // pending - if (stats.pending) { - fmt = color('pending', ' ') + - color('pending', ' %d pending'); - - console.log(fmt, stats.pending); - } - - // failures - if (stats.failures) { - fmt = color('fail', ' %d failing'); - - console.log(fmt, stats.failures); - - Base.list(this.failures); - console.log(); - } - - console.log(); -}; - -/** - * Pad the given `str` to `len`. - * - * @api private - * @param {string} str - * @param {string} len - * @return {string} - */ -function pad (str, len) { - str = String(str); - return Array(len - str.length + 1).join(' ') + str; -} - -/** - * Returns an inline diff between 2 strings with coloured ANSI output - * - * @api private - * @param {Error} err with actual/expected - * @param {boolean} escape - * @return {string} Diff - */ -function inlineDiff (err, escape) { - var msg = errorDiff(err, 'WordsWithSpace', escape); - - // linenos - var lines = msg.split('\n'); - if (lines.length > 4) { - var width = String(lines.length).length; - msg = lines.map(function (str, i) { - return pad(++i, width) + ' |' + ' ' + str; - }).join('\n'); - } - - // legend - msg = '\n' + - color('diff removed', 'actual') + - ' ' + - color('diff added', 'expected') + - '\n\n' + - msg + - '\n'; - - // indent - msg = msg.replace(/^/gm, ' '); - return msg; -} - -/** - * Returns a unified diff between two strings. - * - * @api private - * @param {Error} err with actual/expected - * @param {boolean} escape - * @return {string} The diff. - */ -function unifiedDiff (err, escape) { - var indent = ' '; - function cleanUp (line) { - if (escape) { - line = escapeInvisibles(line); - } - if (line[0] === '+') { - return indent + colorLines('diff added', line); - } - if (line[0] === '-') { - return indent + colorLines('diff removed', line); - } - if (line.match(/@@/)) { - return '--'; - } - if (line.match(/\\ No newline/)) { - return null; - } - return indent + line; - } - function notBlank (line) { - return typeof line !== 'undefined' && line !== null; - } - var msg = diff.createPatch('string', err.actual, err.expected); - var lines = msg.split('\n').splice(5); - return '\n ' + - colorLines('diff added', '+ expected') + ' ' + - colorLines('diff removed', '- actual') + - '\n\n' + - lines.map(cleanUp).filter(notBlank).join('\n'); -} - -/** - * Return a character diff for `err`. - * - * @api private - * @param {Error} err - * @param {string} type - * @param {boolean} escape - * @return {string} - */ -function errorDiff (err, type, escape) { - var actual = escape ? escapeInvisibles(err.actual) : err.actual; - var expected = escape ? escapeInvisibles(err.expected) : err.expected; - return diff['diff' + type](actual, expected).map(function (str) { - if (str.added) { - return colorLines('diff added', str.value); - } - if (str.removed) { - return colorLines('diff removed', str.value); - } - return str.value; - }).join(''); -} - -/** - * Returns a string with all invisible characters in plain text - * - * @api private - * @param {string} line - * @return {string} - */ -function escapeInvisibles (line) { - return line.replace(/\t/g, '') - .replace(/\r/g, '') - .replace(/\n/g, '\n'); -} - -/** - * Color lines for `str`, using the color `name`. - * - * @api private - * @param {string} name - * @param {string} str - * @return {string} - */ -function colorLines (name, str) { - return str.split('\n').map(function (str) { - return color(name, str); - }).join('\n'); -} - -/** - * Object#toString reference. - */ -var objToString = Object.prototype.toString; - -/** - * Check that a / b have the same type. - * - * @api private - * @param {Object} a - * @param {Object} b - * @return {boolean} - */ -function sameType (a, b) { - return objToString.call(a) === objToString.call(b); -} - -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../ms":14,"../utils":36,"_process":55,"diff":44,"supports-color":40,"tty":4}],17:[function(require,module,exports){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var utils = require('../utils'); - -/** - * Expose `Doc`. - */ - -exports = module.exports = Doc; - -/** - * Initialize a new `Doc` reporter. - * - * @param {Runner} runner - * @api public - */ -function Doc (runner) { - Base.call(this, runner); - - var indents = 2; - - function indent () { - return Array(indents).join(' '); - } - - runner.on('suite', function (suite) { - if (suite.root) { - return; - } - ++indents; - console.log('%s
', indent()); - ++indents; - console.log('%s

%s

', indent(), utils.escape(suite.title)); - console.log('%s
', indent()); - }); - - runner.on('suite end', function (suite) { - if (suite.root) { - return; - } - console.log('%s
', indent()); - --indents; - console.log('%s
', indent()); - --indents; - }); - - runner.on('pass', function (test) { - console.log('%s
%s
', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.body)); - console.log('%s
%s
', indent(), code); - }); - - runner.on('fail', function (test, err) { - console.log('%s
%s
', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.body)); - console.log('%s
%s
', indent(), code); - console.log('%s
%s
', indent(), utils.escape(err)); - }); -} - -},{"../utils":36,"./base":16}],18:[function(require,module,exports){ -(function (process){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var inherits = require('../utils').inherits; -var color = Base.color; - -/** - * Expose `Dot`. - */ - -exports = module.exports = Dot; - -/** - * Initialize a new `Dot` matrix test reporter. - * - * @api public - * @param {Runner} runner - */ -function Dot (runner) { - Base.call(this, runner); - - var self = this; - var width = Base.window.width * 0.75 | 0; - var n = -1; - - runner.on('start', function () { - process.stdout.write('\n'); - }); - - runner.on('pending', function () { - if (++n % width === 0) { - process.stdout.write('\n '); - } - process.stdout.write(color('pending', Base.symbols.comma)); - }); - - runner.on('pass', function (test) { - if (++n % width === 0) { - process.stdout.write('\n '); - } - if (test.speed === 'slow') { - process.stdout.write(color('bright yellow', Base.symbols.dot)); - } else { - process.stdout.write(color(test.speed, Base.symbols.dot)); - } - }); - - runner.on('fail', function () { - if (++n % width === 0) { - process.stdout.write('\n '); - } - process.stdout.write(color('fail', Base.symbols.bang)); - }); - - runner.on('end', function () { - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ -inherits(Dot, Base); - -}).call(this,require('_process')) -},{"../utils":36,"./base":16,"_process":55}],19:[function(require,module,exports){ -(function (global){ -'use strict'; - -/* eslint-env browser */ - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var utils = require('../utils'); -var Progress = require('../browser/progress'); -var escapeRe = require('escape-string-regexp'); -var escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -/* eslint-disable no-unused-vars, no-native-reassign */ -var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ - -/** - * Expose `HTML`. - */ - -exports = module.exports = HTML; - -/** - * Stats template. - */ - -var statsTemplate = ''; - -var playIcon = '‣'; - -/** - * Initialize a new `HTML` reporter. - * - * @api public - * @param {Runner} runner - */ -function HTML (runner) { - Base.call(this, runner); - - var self = this; - var stats = this.stats; - var stat = fragment(statsTemplate); - var items = stat.getElementsByTagName('li'); - var passes = items[1].getElementsByTagName('em')[0]; - var passesLink = items[1].getElementsByTagName('a')[0]; - var failures = items[2].getElementsByTagName('em')[0]; - var failuresLink = items[2].getElementsByTagName('a')[0]; - var duration = items[3].getElementsByTagName('em')[0]; - var canvas = stat.getElementsByTagName('canvas')[0]; - var report = fragment('
    '); - var stack = [report]; - var progress; - var ctx; - var root = document.getElementById('mocha'); - - if (canvas.getContext) { - var ratio = window.devicePixelRatio || 1; - canvas.style.width = canvas.width; - canvas.style.height = canvas.height; - canvas.width *= ratio; - canvas.height *= ratio; - ctx = canvas.getContext('2d'); - ctx.scale(ratio, ratio); - progress = new Progress(); - } - - if (!root) { - return error('#mocha div missing, add it to your document'); - } - - // pass toggle - on(passesLink, 'click', function (evt) { - evt.preventDefault(); - unhide(); - var name = (/pass/).test(report.className) ? '' : ' pass'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) { - hideSuitesWithout('test pass'); - } - }); - - // failure toggle - on(failuresLink, 'click', function (evt) { - evt.preventDefault(); - unhide(); - var name = (/fail/).test(report.className) ? '' : ' fail'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) { - hideSuitesWithout('test fail'); - } - }); - - root.appendChild(stat); - root.appendChild(report); - - if (progress) { - progress.size(40); - } - - runner.on('suite', function (suite) { - if (suite.root) { - return; - } - - // suite - var url = self.suiteURL(suite); - var el = fragment('
  • %s

  • ', url, escape(suite.title)); - - // container - stack[0].appendChild(el); - stack.unshift(document.createElement('ul')); - el.appendChild(stack[0]); - }); - - runner.on('suite end', function (suite) { - if (suite.root) { - updateStats(); - return; - } - stack.shift(); - }); - - runner.on('pass', function (test) { - var url = self.testURL(test); - var markup = '
  • %e%ems ' + - '' + playIcon + '

  • '; - var el = fragment(markup, test.speed, test.title, test.duration, url); - self.addCodeToggle(el, test.body); - appendToStack(el); - updateStats(); - }); - - runner.on('fail', function (test) { - var el = fragment('
  • %e ' + playIcon + '

  • ', - test.title, self.testURL(test)); - var stackString; // Note: Includes leading newline - var message = test.err.toString(); - - // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we - // check for the result of the stringifying. - if (message === '[object Error]') { - message = test.err.message; - } - - if (test.err.stack) { - var indexOfMessage = test.err.stack.indexOf(test.err.message); - if (indexOfMessage === -1) { - stackString = test.err.stack; - } else { - stackString = test.err.stack.substr(test.err.message.length + indexOfMessage); - } - } else if (test.err.sourceURL && test.err.line !== undefined) { - // Safari doesn't give you a stack. Let's at least provide a source line. - stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')'; - } - - stackString = stackString || ''; - - if (test.err.htmlMessage && stackString) { - el.appendChild(fragment('
    %s\n
    %e
    ', - test.err.htmlMessage, stackString)); - } else if (test.err.htmlMessage) { - el.appendChild(fragment('
    %s
    ', test.err.htmlMessage)); - } else { - el.appendChild(fragment('
    %e%e
    ', message, stackString)); - } - - self.addCodeToggle(el, test.body); - appendToStack(el); - updateStats(); - }); - - runner.on('pending', function (test) { - var el = fragment('
  • %e

  • ', test.title); - appendToStack(el); - updateStats(); - }); - - function appendToStack (el) { - // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. - if (stack[0]) { - stack[0].appendChild(el); - } - } - - function updateStats () { - // TODO: add to stats - var percent = stats.tests / runner.total * 100 | 0; - if (progress) { - progress.update(percent).draw(ctx); - } - - // update stats - var ms = new Date() - stats.start; - text(passes, stats.passes); - text(failures, stats.failures); - text(duration, (ms / 1000).toFixed(2)); - } -} - -/** - * Makes a URL, preserving querystring ("search") parameters. - * - * @param {string} s - * @return {string} A new URL. - */ -function makeUrl (s) { - var search = window.location.search; - - // Remove previous grep query parameter if present - if (search) { - search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?'); - } - - return window.location.pathname + (search ? search + '&' : '?') + 'grep=' + encodeURIComponent(escapeRe(s)); -} - -/** - * Provide suite URL. - * - * @param {Object} [suite] - */ -HTML.prototype.suiteURL = function (suite) { - return makeUrl(suite.fullTitle()); -}; - -/** - * Provide test URL. - * - * @param {Object} [test] - */ -HTML.prototype.testURL = function (test) { - return makeUrl(test.fullTitle()); -}; - -/** - * Adds code toggle functionality for the provided test's list element. - * - * @param {HTMLLIElement} el - * @param {string} contents - */ -HTML.prototype.addCodeToggle = function (el, contents) { - var h2 = el.getElementsByTagName('h2')[0]; - - on(h2, 'click', function () { - pre.style.display = pre.style.display === 'none' ? 'block' : 'none'; - }); - - var pre = fragment('
    %e
    ', utils.clean(contents)); - el.appendChild(pre); - pre.style.display = 'none'; -}; - -/** - * Display error `msg`. - * - * @param {string} msg - */ -function error (msg) { - document.body.appendChild(fragment('
    %s
    ', msg)); -} - -/** - * Return a DOM fragment from `html`. - * - * @param {string} html - */ -function fragment (html) { - var args = arguments; - var div = document.createElement('div'); - var i = 1; - - div.innerHTML = html.replace(/%([se])/g, function (_, type) { - switch (type) { - case 's': return String(args[i++]); - case 'e': return escape(args[i++]); - // no default - } - }); - - return div.firstChild; -} - -/** - * Check for suites that do not have elements - * with `classname`, and hide them. - * - * @param {text} classname - */ -function hideSuitesWithout (classname) { - var suites = document.getElementsByClassName('suite'); - for (var i = 0; i < suites.length; i++) { - var els = suites[i].getElementsByClassName(classname); - if (!els.length) { - suites[i].className += ' hidden'; - } - } -} - -/** - * Unhide .hidden suites. - */ -function unhide () { - var els = document.getElementsByClassName('suite hidden'); - for (var i = 0; i < els.length; ++i) { - els[i].className = els[i].className.replace('suite hidden', 'suite'); - } -} - -/** - * Set an element's text contents. - * - * @param {HTMLElement} el - * @param {string} contents - */ -function text (el, contents) { - if (el.textContent) { - el.textContent = contents; - } else { - el.innerText = contents; - } -} - -/** - * Listen on `event` with callback `fn`. - */ -function on (el, event, fn) { - if (el.addEventListener) { - el.addEventListener(event, fn, false); - } else { - el.attachEvent('on' + event, fn); - } -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../browser/progress":3,"../utils":36,"./base":16,"escape-string-regexp":45}],20:[function(require,module,exports){ -'use strict'; - -// Alias exports to a their normalized format Mocha#reporter to prevent a need -// for dynamic (try/catch) requires, which Browserify doesn't handle. -exports.Base = exports.base = require('./base'); -exports.Dot = exports.dot = require('./dot'); -exports.Doc = exports.doc = require('./doc'); -exports.TAP = exports.tap = require('./tap'); -exports.JSON = exports.json = require('./json'); -exports.HTML = exports.html = require('./html'); -exports.List = exports.list = require('./list'); -exports.Min = exports.min = require('./min'); -exports.Spec = exports.spec = require('./spec'); -exports.Nyan = exports.nyan = require('./nyan'); -exports.XUnit = exports.xunit = require('./xunit'); -exports.Markdown = exports.markdown = require('./markdown'); -exports.Progress = exports.progress = require('./progress'); -exports.Landing = exports.landing = require('./landing'); -exports.JSONStream = exports['json-stream'] = require('./json-stream'); - -},{"./base":16,"./doc":17,"./dot":18,"./html":19,"./json":22,"./json-stream":21,"./landing":23,"./list":24,"./markdown":25,"./min":26,"./nyan":27,"./progress":28,"./spec":29,"./tap":30,"./xunit":31}],21:[function(require,module,exports){ -(function (process){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @api public - * @param {Runner} runner - */ -function List (runner) { - Base.call(this, runner); - - var self = this; - var total = runner.total; - - runner.on('start', function () { - console.log(JSON.stringify(['start', { total: total }])); - }); - - runner.on('pass', function (test) { - console.log(JSON.stringify(['pass', clean(test)])); - }); - - runner.on('fail', function (test, err) { - test = clean(test); - test.err = err.message; - test.stack = err.stack || null; - console.log(JSON.stringify(['fail', test])); - }); - - runner.on('end', function () { - process.stdout.write(JSON.stringify(['end', self.stats])); - }); -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @api private - * @param {Object} test - * @return {Object} - */ -function clean (test) { - return { - title: test.title, - fullTitle: test.fullTitle(), - duration: test.duration, - currentRetry: test.currentRetry() - }; -} - -}).call(this,require('_process')) -},{"./base":16,"_process":55}],22:[function(require,module,exports){ -(function (process){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `JSON`. - */ - -exports = module.exports = JSONReporter; - -/** - * Initialize a new `JSON` reporter. - * - * @api public - * @param {Runner} runner - */ -function JSONReporter (runner) { - Base.call(this, runner); - - var self = this; - var tests = []; - var pending = []; - var failures = []; - var passes = []; - - runner.on('test end', function (test) { - tests.push(test); - }); - - runner.on('pass', function (test) { - passes.push(test); - }); - - runner.on('fail', function (test) { - failures.push(test); - }); - - runner.on('pending', function (test) { - pending.push(test); - }); - - runner.on('end', function () { - var obj = { - stats: self.stats, - tests: tests.map(clean), - pending: pending.map(clean), - failures: failures.map(clean), - passes: passes.map(clean) - }; - - runner.testResults = obj; - - process.stdout.write(JSON.stringify(obj, null, 2)); - }); -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @api private - * @param {Object} test - * @return {Object} - */ -function clean (test) { - return { - title: test.title, - fullTitle: test.fullTitle(), - duration: test.duration, - currentRetry: test.currentRetry(), - err: errorJSON(test.err || {}) - }; -} - -/** - * Transform `error` into a JSON object. - * - * @api private - * @param {Error} err - * @return {Object} - */ -function errorJSON (err) { - var res = {}; - Object.getOwnPropertyNames(err).forEach(function (key) { - res[key] = err[key]; - }, err); - return res; -} - -}).call(this,require('_process')) -},{"./base":16,"_process":55}],23:[function(require,module,exports){ -(function (process){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var inherits = require('../utils').inherits; -var cursor = Base.cursor; -var color = Base.color; - -/** - * Expose `Landing`. - */ - -exports = module.exports = Landing; - -/** - * Airplane color. - */ - -Base.colors.plane = 0; - -/** - * Airplane crash color. - */ - -Base.colors['plane crash'] = 31; - -/** - * Runway color. - */ - -Base.colors.runway = 90; - -/** - * Initialize a new `Landing` reporter. - * - * @api public - * @param {Runner} runner - */ -function Landing (runner) { - Base.call(this, runner); - - var self = this; - var width = Base.window.width * 0.75 | 0; - var total = runner.total; - var stream = process.stdout; - var plane = color('plane', '✈'); - var crashed = -1; - var n = 0; - - function runway () { - var buf = Array(width).join('-'); - return ' ' + color('runway', buf); - } - - runner.on('start', function () { - stream.write('\n\n\n '); - cursor.hide(); - }); - - runner.on('test end', function (test) { - // check if the plane crashed - var col = crashed === -1 ? width * ++n / total | 0 : crashed; - - // show the crash - if (test.state === 'failed') { - plane = color('plane crash', '✈'); - crashed = col; - } - - // render landing strip - stream.write('\u001b[' + (width + 1) + 'D\u001b[2A'); - stream.write(runway()); - stream.write('\n '); - stream.write(color('runway', Array(col).join('⋅'))); - stream.write(plane); - stream.write(color('runway', Array(width - col).join('⋅') + '\n')); - stream.write(runway()); - stream.write('\u001b[0m'); - }); - - runner.on('end', function () { - cursor.show(); - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ -inherits(Landing, Base); - -}).call(this,require('_process')) -},{"../utils":36,"./base":16,"_process":55}],24:[function(require,module,exports){ -(function (process){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var inherits = require('../utils').inherits; -var color = Base.color; -var cursor = Base.cursor; - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @api public - * @param {Runner} runner - */ -function List (runner) { - Base.call(this, runner); - - var self = this; - var n = 0; - - runner.on('start', function () { - console.log(); - }); - - runner.on('test', function (test) { - process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); - }); - - runner.on('pending', function (test) { - var fmt = color('checkmark', ' -') + - color('pending', ' %s'); - console.log(fmt, test.fullTitle()); - }); - - runner.on('pass', function (test) { - var fmt = color('checkmark', ' ' + Base.symbols.ok) + - color('pass', ' %s: ') + - color(test.speed, '%dms'); - cursor.CR(); - console.log(fmt, test.fullTitle(), test.duration); - }); - - runner.on('fail', function (test) { - cursor.CR(); - console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ -inherits(List, Base); - -}).call(this,require('_process')) -},{"../utils":36,"./base":16,"_process":55}],25:[function(require,module,exports){ -(function (process){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var utils = require('../utils'); - -/** - * Constants - */ - -var SUITE_PREFIX = '$'; - -/** - * Expose `Markdown`. - */ - -exports = module.exports = Markdown; - -/** - * Initialize a new `Markdown` reporter. - * - * @api public - * @param {Runner} runner - */ -function Markdown (runner) { - Base.call(this, runner); - - var level = 0; - var buf = ''; - - function title (str) { - return Array(level).join('#') + ' ' + str; - } - - function mapTOC (suite, obj) { - var ret = obj; - var key = SUITE_PREFIX + suite.title; - - obj = obj[key] = obj[key] || { suite: suite }; - suite.suites.forEach(function (suite) { - mapTOC(suite, obj); - }); - - return ret; - } - - function stringifyTOC (obj, level) { - ++level; - var buf = ''; - var link; - for (var key in obj) { - if (key === 'suite') { - continue; - } - if (key !== SUITE_PREFIX) { - link = ' - [' + key.substring(1) + ']'; - link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; - buf += Array(level).join(' ') + link; - } - buf += stringifyTOC(obj[key], level); - } - return buf; - } - - function generateTOC (suite) { - var obj = mapTOC(suite, {}); - return stringifyTOC(obj, 0); - } - - generateTOC(runner.suite); - - runner.on('suite', function (suite) { - ++level; - var slug = utils.slug(suite.fullTitle()); - buf += '' + '\n'; - buf += title(suite.title) + '\n'; - }); - - runner.on('suite end', function () { - --level; - }); - - runner.on('pass', function (test) { - var code = utils.clean(test.body); - buf += test.title + '.\n'; - buf += '\n```js\n'; - buf += code + '\n'; - buf += '```\n\n'; - }); - - runner.on('end', function () { - process.stdout.write('# TOC\n'); - process.stdout.write(generateTOC(runner.suite)); - process.stdout.write(buf); - }); -} - -}).call(this,require('_process')) -},{"../utils":36,"./base":16,"_process":55}],26:[function(require,module,exports){ -(function (process){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var inherits = require('../utils').inherits; - -/** - * Expose `Min`. - */ - -exports = module.exports = Min; - -/** - * Initialize a new `Min` minimal test reporter (best used with --watch). - * - * @api public - * @param {Runner} runner - */ -function Min (runner) { - Base.call(this, runner); - - runner.on('start', function () { - // clear screen - process.stdout.write('\u001b[2J'); - // set cursor position - process.stdout.write('\u001b[1;3H'); - }); - - runner.on('end', this.epilogue.bind(this)); -} - -/** - * Inherit from `Base.prototype`. - */ -inherits(Min, Base); - -}).call(this,require('_process')) -},{"../utils":36,"./base":16,"_process":55}],27:[function(require,module,exports){ -(function (process){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var inherits = require('../utils').inherits; - -/** - * Expose `Dot`. - */ - -exports = module.exports = NyanCat; - -/** - * Initialize a new `Dot` matrix test reporter. - * - * @param {Runner} runner - * @api public - */ - -function NyanCat (runner) { - Base.call(this, runner); - - var self = this; - var width = Base.window.width * 0.75 | 0; - var nyanCatWidth = this.nyanCatWidth = 11; - - this.colorIndex = 0; - this.numberOfLines = 4; - this.rainbowColors = self.generateColors(); - this.scoreboardWidth = 5; - this.tick = 0; - this.trajectories = [[], [], [], []]; - this.trajectoryWidthMax = (width - nyanCatWidth); - - runner.on('start', function () { - Base.cursor.hide(); - self.draw(); - }); - - runner.on('pending', function () { - self.draw(); - }); - - runner.on('pass', function () { - self.draw(); - }); - - runner.on('fail', function () { - self.draw(); - }); - - runner.on('end', function () { - Base.cursor.show(); - for (var i = 0; i < self.numberOfLines; i++) { - write('\n'); - } - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ -inherits(NyanCat, Base); - -/** - * Draw the nyan cat - * - * @api private - */ - -NyanCat.prototype.draw = function () { - this.appendRainbow(); - this.drawScoreboard(); - this.drawRainbow(); - this.drawNyanCat(); - this.tick = !this.tick; -}; - -/** - * Draw the "scoreboard" showing the number - * of passes, failures and pending tests. - * - * @api private - */ - -NyanCat.prototype.drawScoreboard = function () { - var stats = this.stats; - - function draw (type, n) { - write(' '); - write(Base.color(type, n)); - write('\n'); - } - - draw('green', stats.passes); - draw('fail', stats.failures); - draw('pending', stats.pending); - write('\n'); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Append the rainbow. - * - * @api private - */ - -NyanCat.prototype.appendRainbow = function () { - var segment = this.tick ? '_' : '-'; - var rainbowified = this.rainbowify(segment); - - for (var index = 0; index < this.numberOfLines; index++) { - var trajectory = this.trajectories[index]; - if (trajectory.length >= this.trajectoryWidthMax) { - trajectory.shift(); - } - trajectory.push(rainbowified); - } -}; - -/** - * Draw the rainbow. - * - * @api private - */ - -NyanCat.prototype.drawRainbow = function () { - var self = this; - - this.trajectories.forEach(function (line) { - write('\u001b[' + self.scoreboardWidth + 'C'); - write(line.join('')); - write('\n'); - }); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Draw the nyan cat - * - * @api private - */ -NyanCat.prototype.drawNyanCat = function () { - var self = this; - var startWidth = this.scoreboardWidth + this.trajectories[0].length; - var dist = '\u001b[' + startWidth + 'C'; - var padding = ''; - - write(dist); - write('_,------,'); - write('\n'); - - write(dist); - padding = self.tick ? ' ' : ' '; - write('_|' + padding + '/\\_/\\ '); - write('\n'); - - write(dist); - padding = self.tick ? '_' : '__'; - var tail = self.tick ? '~' : '^'; - write(tail + '|' + padding + this.face() + ' '); - write('\n'); - - write(dist); - padding = self.tick ? ' ' : ' '; - write(padding + '"" "" '); - write('\n'); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Draw nyan cat face. - * - * @api private - * @return {string} - */ - -NyanCat.prototype.face = function () { - var stats = this.stats; - if (stats.failures) { - return '( x .x)'; - } else if (stats.pending) { - return '( o .o)'; - } else if (stats.passes) { - return '( ^ .^)'; - } - return '( - .-)'; -}; - -/** - * Move cursor up `n`. - * - * @api private - * @param {number} n - */ - -NyanCat.prototype.cursorUp = function (n) { - write('\u001b[' + n + 'A'); -}; - -/** - * Move cursor down `n`. - * - * @api private - * @param {number} n - */ - -NyanCat.prototype.cursorDown = function (n) { - write('\u001b[' + n + 'B'); -}; - -/** - * Generate rainbow colors. - * - * @api private - * @return {Array} - */ -NyanCat.prototype.generateColors = function () { - var colors = []; - - for (var i = 0; i < (6 * 7); i++) { - var pi3 = Math.floor(Math.PI / 3); - var n = (i * (1.0 / 6)); - var r = Math.floor(3 * Math.sin(n) + 3); - var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); - var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); - colors.push(36 * r + 6 * g + b + 16); - } - - return colors; -}; - -/** - * Apply rainbow to the given `str`. - * - * @api private - * @param {string} str - * @return {string} - */ -NyanCat.prototype.rainbowify = function (str) { - if (!Base.useColors) { - return str; - } - var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; - this.colorIndex += 1; - return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; -}; - -/** - * Stdout helper. - * - * @param {string} string A message to write to stdout. - */ -function write (string) { - process.stdout.write(string); -} - -}).call(this,require('_process')) -},{"../utils":36,"./base":16,"_process":55}],28:[function(require,module,exports){ -(function (process){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var inherits = require('../utils').inherits; -var color = Base.color; -var cursor = Base.cursor; - -/** - * Expose `Progress`. - */ - -exports = module.exports = Progress; - -/** - * General progress bar color. - */ - -Base.colors.progress = 90; - -/** - * Initialize a new `Progress` bar test reporter. - * - * @api public - * @param {Runner} runner - * @param {Object} options - */ -function Progress (runner, options) { - Base.call(this, runner); - - var self = this; - var width = Base.window.width * 0.50 | 0; - var total = runner.total; - var complete = 0; - var lastN = -1; - - // default chars - options = options || {}; - options.open = options.open || '['; - options.complete = options.complete || '▬'; - options.incomplete = options.incomplete || Base.symbols.dot; - options.close = options.close || ']'; - options.verbose = false; - - // tests started - runner.on('start', function () { - console.log(); - cursor.hide(); - }); - - // tests complete - runner.on('test end', function () { - complete++; - - var percent = complete / total; - var n = width * percent | 0; - var i = width - n; - - if (n === lastN && !options.verbose) { - // Don't re-render the line if it hasn't changed - return; - } - lastN = n; - - cursor.CR(); - process.stdout.write('\u001b[J'); - process.stdout.write(color('progress', ' ' + options.open)); - process.stdout.write(Array(n).join(options.complete)); - process.stdout.write(Array(i).join(options.incomplete)); - process.stdout.write(color('progress', options.close)); - if (options.verbose) { - process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); - } - }); - - // tests are complete, output some stats - // and the failures if any - runner.on('end', function () { - cursor.show(); - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ -inherits(Progress, Base); - -}).call(this,require('_process')) -},{"../utils":36,"./base":16,"_process":55}],29:[function(require,module,exports){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var inherits = require('../utils').inherits; -var color = Base.color; - -/** - * Expose `Spec`. - */ - -exports = module.exports = Spec; - -/** - * Initialize a new `Spec` test reporter. - * - * @api public - * @param {Runner} runner - */ -function Spec (runner) { - Base.call(this, runner); - - var self = this; - var indents = 0; - var n = 0; - - function indent () { - return Array(indents).join(' '); - } - - runner.on('start', function () { - console.log(); - }); - - runner.on('suite', function (suite) { - ++indents; - console.log(color('suite', '%s%s'), indent(), suite.title); - }); - - runner.on('suite end', function () { - --indents; - if (indents === 1) { - console.log(); - } - }); - - runner.on('pending', function (test) { - var fmt = indent() + color('pending', ' - %s'); - console.log(fmt, test.title); - }); - - runner.on('pass', function (test) { - var fmt; - if (test.speed === 'fast') { - fmt = indent() + - color('checkmark', ' ' + Base.symbols.ok) + - color('pass', ' %s'); - console.log(fmt, test.title); - } else { - fmt = indent() + - color('checkmark', ' ' + Base.symbols.ok) + - color('pass', ' %s') + - color(test.speed, ' (%dms)'); - console.log(fmt, test.title, test.duration); - } - }); - - runner.on('fail', function (test) { - console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ -inherits(Spec, Base); - -},{"../utils":36,"./base":16}],30:[function(require,module,exports){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `TAP`. - */ - -exports = module.exports = TAP; - -/** - * Initialize a new `TAP` reporter. - * - * @api public - * @param {Runner} runner - */ -function TAP (runner) { - Base.call(this, runner); - - var n = 1; - var passes = 0; - var failures = 0; - - runner.on('start', function () { - var total = runner.grepTotal(runner.suite); - console.log('%d..%d', 1, total); - }); - - runner.on('test end', function () { - ++n; - }); - - runner.on('pending', function (test) { - console.log('ok %d %s # SKIP -', n, title(test)); - }); - - runner.on('pass', function (test) { - passes++; - console.log('ok %d %s', n, title(test)); - }); - - runner.on('fail', function (test, err) { - failures++; - console.log('not ok %d %s', n, title(test)); - if (err.stack) { - console.log(err.stack.replace(/^/gm, ' ')); - } - }); - - runner.on('end', function () { - console.log('# tests ' + (passes + failures)); - console.log('# pass ' + passes); - console.log('# fail ' + failures); - }); -} - -/** - * Return a TAP-safe title of `test` - * - * @api private - * @param {Object} test - * @return {String} - */ -function title (test) { - return test.fullTitle().replace(/#/g, ''); -} - -},{"./base":16}],31:[function(require,module,exports){ -(function (process,global){ -'use strict'; - -/** - * Module dependencies. - */ - -var Base = require('./base'); -var utils = require('../utils'); -var inherits = utils.inherits; -var fs = require('fs'); -var escape = utils.escape; -var mkdirp = require('mkdirp'); -var path = require('path'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -/* eslint-disable no-unused-vars, no-native-reassign */ -var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ - -/** - * Expose `XUnit`. - */ - -exports = module.exports = XUnit; - -/** - * Initialize a new `XUnit` reporter. - * - * @api public - * @param {Runner} runner - */ -function XUnit (runner, options) { - Base.call(this, runner); - - var stats = this.stats; - var tests = []; - var self = this; - - // the name of the test suite, as it will appear in the resulting XML file - var suiteName; - - // the default name of the test suite if none is provided - var DEFAULT_SUITE_NAME = 'Mocha Tests'; - - if (options && options.reporterOptions) { - if (options.reporterOptions.output) { - if (!fs.createWriteStream) { - throw new Error('file output not supported in browser'); - } - - mkdirp.sync(path.dirname(options.reporterOptions.output)); - self.fileStream = fs.createWriteStream(options.reporterOptions.output); - } - - // get the suite name from the reporter options (if provided) - suiteName = options.reporterOptions.suiteName; - } - - // fall back to the default suite name - suiteName = suiteName || DEFAULT_SUITE_NAME; - - runner.on('pending', function (test) { - tests.push(test); - }); - - runner.on('pass', function (test) { - tests.push(test); - }); - - runner.on('fail', function (test) { - tests.push(test); - }); - - runner.on('end', function () { - self.write(tag('testsuite', { - name: suiteName, - tests: stats.tests, - failures: stats.failures, - errors: stats.failures, - skipped: stats.tests - stats.failures - stats.passes, - timestamp: (new Date()).toUTCString(), - time: (stats.duration / 1000) || 0 - }, false)); - - tests.forEach(function (t) { - self.test(t); - }); - - self.write(''); - }); -} - -/** - * Inherit from `Base.prototype`. - */ -inherits(XUnit, Base); - -/** - * Override done to close the stream (if it's a file). - * - * @param failures - * @param {Function} fn - */ -XUnit.prototype.done = function (failures, fn) { - if (this.fileStream) { - this.fileStream.end(function () { - fn(failures); - }); - } else { - fn(failures); - } -}; - -/** - * Write out the given line. - * - * @param {string} line - */ -XUnit.prototype.write = function (line) { - if (this.fileStream) { - this.fileStream.write(line + '\n'); - } else if (typeof process === 'object' && process.stdout) { - process.stdout.write(line + '\n'); - } else { - console.log(line); - } -}; - -/** - * Output tag for the given `test.` - * - * @param {Test} test - */ -XUnit.prototype.test = function (test) { - var attrs = { - classname: test.parent.fullTitle(), - name: test.title, - time: (test.duration / 1000) || 0 - }; - - if (test.state === 'failed') { - var err = test.err; - this.write(tag('testcase', attrs, false, tag('failure', {}, false, escape(err.message) + '\n' + escape(err.stack)))); - } else if (test.isPending()) { - this.write(tag('testcase', attrs, false, tag('skipped', {}, true))); - } else { - this.write(tag('testcase', attrs, true)); - } -}; - -/** - * HTML tag helper. - * - * @param name - * @param attrs - * @param close - * @param content - * @return {string} - */ -function tag (name, attrs, close, content) { - var end = close ? '/>' : '>'; - var pairs = []; - var tag; - - for (var key in attrs) { - if (Object.prototype.hasOwnProperty.call(attrs, key)) { - pairs.push(key + '="' + escape(attrs[key]) + '"'); - } - } - - tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; - if (content) { - tag += content + ' Math.pow(2, 31)) { - this._enableTimeouts = false; - } - if (typeof ms === 'string') { - ms = milliseconds(ms); - } - debug('timeout %d', ms); - this._timeout = ms; - if (this.timer) { - this.resetTimeout(); - } - return this; -}; - -/** - * Set & get slow `ms`. - * - * @api private - * @param {number|string} ms - * @return {Runnable|number} ms or Runnable instance. - */ -Runnable.prototype.slow = function (ms) { - if (typeof ms === 'undefined') { - return this._slow; - } - if (typeof ms === 'string') { - ms = milliseconds(ms); - } - debug('timeout %d', ms); - this._slow = ms; - return this; -}; - -/** - * Set and get whether timeout is `enabled`. - * - * @api private - * @param {boolean} enabled - * @return {Runnable|boolean} enabled or Runnable instance. - */ -Runnable.prototype.enableTimeouts = function (enabled) { - if (!arguments.length) { - return this._enableTimeouts; - } - debug('enableTimeouts %s', enabled); - this._enableTimeouts = enabled; - return this; -}; - -/** - * Halt and mark as pending. - * - * @api public - */ -Runnable.prototype.skip = function () { - throw new Pending('sync skip'); -}; - -/** - * Check if this runnable or its parent suite is marked as pending. - * - * @api private - */ -Runnable.prototype.isPending = function () { - return this.pending || (this.parent && this.parent.isPending()); -}; - -/** - * Set number of retries. - * - * @api private - */ -Runnable.prototype.retries = function (n) { - if (!arguments.length) { - return this._retries; - } - this._retries = n; -}; - -/** - * Get current retry - * - * @api private - */ -Runnable.prototype.currentRetry = function (n) { - if (!arguments.length) { - return this._currentRetry; - } - this._currentRetry = n; -}; - -/** - * Return the full title generated by recursively concatenating the parent's - * full title. - * - * @api public - * @return {string} - */ -Runnable.prototype.fullTitle = function () { - return this.titlePath().join(' '); -}; - -/** - * Return the title path generated by concatenating the parent's title path with the title. - * - * @api public - * @return {string} - */ -Runnable.prototype.titlePath = function () { - return this.parent.titlePath().concat([this.title]); -}; - -/** - * Clear the timeout. - * - * @api private - */ -Runnable.prototype.clearTimeout = function () { - clearTimeout(this.timer); -}; - -/** - * Inspect the runnable void of private properties. - * - * @api private - * @return {string} - */ -Runnable.prototype.inspect = function () { - return JSON.stringify(this, function (key, val) { - if (key[0] === '_') { - return; - } - if (key === 'parent') { - return '#'; - } - if (key === 'ctx') { - return '#'; - } - return val; - }, 2); -}; - -/** - * Reset the timeout. - * - * @api private - */ -Runnable.prototype.resetTimeout = function () { - var self = this; - var ms = this.timeout() || 1e9; - - if (!this._enableTimeouts) { - return; - } - this.clearTimeout(); - this.timer = setTimeout(function () { - if (!self._enableTimeouts) { - return; - } - self.callback(new Error('Timeout of ' + ms + - 'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.')); - self.timedOut = true; - }, ms); -}; - -/** - * Whitelist a list of globals for this test run. - * - * @api private - * @param {string[]} globals - */ -Runnable.prototype.globals = function (globals) { - if (!arguments.length) { - return this._allowedGlobals; - } - this._allowedGlobals = globals; -}; - -/** - * Run the test and invoke `fn(err)`. - * - * @param {Function} fn - * @api private - */ -Runnable.prototype.run = function (fn) { - var self = this; - var start = new Date(); - var ctx = this.ctx; - var finished; - var emitted; - - // Sometimes the ctx exists, but it is not runnable - if (ctx && ctx.runnable) { - ctx.runnable(this); - } - - // called multiple times - function multiple (err) { - if (emitted) { - return; - } - emitted = true; - self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate')); - } - - // finished - function done (err) { - var ms = self.timeout(); - if (self.timedOut) { - return; - } - if (finished) { - return multiple(err || self._trace); - } - - self.clearTimeout(); - self.duration = new Date() - start; - finished = true; - if (!err && self.duration > ms && self._enableTimeouts) { - err = new Error('Timeout of ' + ms + - 'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.'); - } - fn(err); - } - - // for .resetTimeout() - this.callback = done; - - // explicit async with `done` argument - if (this.async) { - this.resetTimeout(); - - // allows skip() to be used in an explicit async context - this.skip = function asyncSkip () { - done(new Pending('async skip call')); - // halt execution. the Runnable will be marked pending - // by the previous call, and the uncaught handler will ignore - // the failure. - throw new Pending('async skip; aborting execution'); - }; - - if (this.allowUncaught) { - return callFnAsync(this.fn); - } - try { - callFnAsync(this.fn); - } catch (err) { - emitted = true; - done(utils.getError(err)); - } - return; - } - - if (this.allowUncaught) { - if (this.isPending()) { - done(); - } else { - callFn(this.fn); - } - return; - } - - // sync or promise-returning - try { - if (this.isPending()) { - done(); - } else { - callFn(this.fn); - } - } catch (err) { - emitted = true; - done(utils.getError(err)); - } - - function callFn (fn) { - var result = fn.call(ctx); - if (result && typeof result.then === 'function') { - self.resetTimeout(); - result - .then(function () { - done(); - // Return null so libraries like bluebird do not warn about - // subsequently constructed Promises. - return null; - }, - function (reason) { - done(reason || new Error('Promise rejected with no or falsy reason')); - }); - } else { - if (self.asyncOnly) { - return done(new Error('--async-only option in use without declaring `done()` or returning a promise')); - } - - done(); - } - } - - function callFnAsync (fn) { - var result = fn.call(ctx, function (err) { - if (err instanceof Error || toString.call(err) === '[object Error]') { - return done(err); - } - if (err) { - if (Object.prototype.toString.call(err) === '[object Object]') { - return done(new Error('done() invoked with non-Error: ' + - JSON.stringify(err))); - } - return done(new Error('done() invoked with non-Error: ' + err)); - } - if (result && utils.isPromise(result)) { - return done(new Error('Resolution method is overspecified. Specify a callback *or* return a Promise; not both.')); - } - - done(); - }); - } -}; - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./ms":14,"./pending":15,"./utils":36,"debug":42,"events":46}],33:[function(require,module,exports){ -(function (process,global){ -'use strict'; - -/** - * Module dependencies. - */ - -var EventEmitter = require('events').EventEmitter; -var Pending = require('./pending'); -var utils = require('./utils'); -var inherits = utils.inherits; -var debug = require('debug')('mocha:runner'); -var Runnable = require('./runnable'); -var stackFilter = utils.stackTraceFilter(); -var stringify = utils.stringify; -var type = utils.type; -var undefinedError = utils.undefinedError; - -/** - * Non-enumerable globals. - */ - -var globals = [ - 'setTimeout', - 'clearTimeout', - 'setInterval', - 'clearInterval', - 'XMLHttpRequest', - 'Date', - 'setImmediate', - 'clearImmediate' -]; - -/** - * Expose `Runner`. - */ - -module.exports = Runner; - -/** - * Initialize a `Runner` for the given `suite`. - * - * Events: - * - * - `start` execution started - * - `end` execution complete - * - `suite` (suite) test suite execution started - * - `suite end` (suite) all tests (and sub-suites) have finished - * - `test` (test) test execution started - * - `test end` (test) test completed - * - `hook` (hook) hook execution started - * - `hook end` (hook) hook complete - * - `pass` (test) test passed - * - `fail` (test, err) test failed - * - `pending` (test) test pending - * - * @api public - * @param {Suite} suite Root suite - * @param {boolean} [delay] Whether or not to delay execution of root suite - * until ready. - */ -function Runner (suite, delay) { - var self = this; - this._globals = []; - this._abort = false; - this._delay = delay; - this.suite = suite; - this.started = false; - this.total = suite.total(); - this.failures = 0; - this.on('test end', function (test) { - self.checkGlobals(test); - }); - this.on('hook end', function (hook) { - self.checkGlobals(hook); - }); - this._defaultGrep = /.*/; - this.grep(this._defaultGrep); - this.globals(this.globalProps().concat(extraGlobals())); -} - -/** - * Wrapper for setImmediate, process.nextTick, or browser polyfill. - * - * @param {Function} fn - * @api private - */ -Runner.immediately = global.setImmediate || process.nextTick; - -/** - * Inherit from `EventEmitter.prototype`. - */ -inherits(Runner, EventEmitter); - -/** - * Run tests with full titles matching `re`. Updates runner.total - * with number of tests matched. - * - * @param {RegExp} re - * @param {Boolean} invert - * @return {Runner} for chaining - * @api public - * @param {RegExp} re - * @param {boolean} invert - * @return {Runner} Runner instance. - */ -Runner.prototype.grep = function (re, invert) { - debug('grep %s', re); - this._grep = re; - this._invert = invert; - this.total = this.grepTotal(this.suite); - return this; -}; - -/** - * Returns the number of tests matching the grep search for the - * given suite. - * - * @param {Suite} suite - * @return {Number} - * @api public - * @param {Suite} suite - * @return {number} - */ -Runner.prototype.grepTotal = function (suite) { - var self = this; - var total = 0; - - suite.eachTest(function (test) { - var match = self._grep.test(test.fullTitle()); - if (self._invert) { - match = !match; - } - if (match) { - total++; - } - }); - - return total; -}; - -/** - * Return a list of global properties. - * - * @return {Array} - * @api private - */ -Runner.prototype.globalProps = function () { - var props = Object.keys(global); - - // non-enumerables - for (var i = 0; i < globals.length; ++i) { - if (~props.indexOf(globals[i])) { - continue; - } - props.push(globals[i]); - } - - return props; -}; - -/** - * Allow the given `arr` of globals. - * - * @param {Array} arr - * @return {Runner} for chaining - * @api public - * @param {Array} arr - * @return {Runner} Runner instance. - */ -Runner.prototype.globals = function (arr) { - if (!arguments.length) { - return this._globals; - } - debug('globals %j', arr); - this._globals = this._globals.concat(arr); - return this; -}; - -/** - * Check for global variable leaks. - * - * @api private - */ -Runner.prototype.checkGlobals = function (test) { - if (this.ignoreLeaks) { - return; - } - var ok = this._globals; - - var globals = this.globalProps(); - var leaks; - - if (test) { - ok = ok.concat(test._allowedGlobals || []); - } - - if (this.prevGlobalsLength === globals.length) { - return; - } - this.prevGlobalsLength = globals.length; - - leaks = filterLeaks(ok, globals); - this._globals = this._globals.concat(leaks); - - if (leaks.length > 1) { - this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); - } else if (leaks.length) { - this.fail(test, new Error('global leak detected: ' + leaks[0])); - } -}; - -/** - * Fail the given `test`. - * - * @api private - * @param {Test} test - * @param {Error} err - */ -Runner.prototype.fail = function (test, err) { - if (test.isPending()) { - return; - } - - ++this.failures; - test.state = 'failed'; - - if (!(err instanceof Error || (err && typeof err.message === 'string'))) { - err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)'); - } - - try { - err.stack = (this.fullStackTrace || !err.stack) - ? err.stack - : stackFilter(err.stack); - } catch (ignored) { - // some environments do not take kindly to monkeying with the stack - } - - this.emit('fail', test, err); -}; - -/** - * Fail the given `hook` with `err`. - * - * Hook failures work in the following pattern: - * - If bail, then exit - * - Failed `before` hook skips all tests in a suite and subsuites, - * but jumps to corresponding `after` hook - * - Failed `before each` hook skips remaining tests in a - * suite and jumps to corresponding `after each` hook, - * which is run only once - * - Failed `after` hook does not alter - * execution order - * - Failed `after each` hook skips remaining tests in a - * suite and subsuites, but executes other `after each` - * hooks - * - * @api private - * @param {Hook} hook - * @param {Error} err - */ -Runner.prototype.failHook = function (hook, err) { - if (hook.ctx && hook.ctx.currentTest) { - hook.originalTitle = hook.originalTitle || hook.title; - hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"'; - } - - this.fail(hook, err); - if (this.suite.bail()) { - this.emit('end'); - } -}; - -/** - * Run hook `name` callbacks and then invoke `fn()`. - * - * @api private - * @param {string} name - * @param {Function} fn - */ - -Runner.prototype.hook = function (name, fn) { - var suite = this.suite; - var hooks = suite['_' + name]; - var self = this; - - function next (i) { - var hook = hooks[i]; - if (!hook) { - return fn(); - } - self.currentRunnable = hook; - - hook.ctx.currentTest = self.test; - - self.emit('hook', hook); - - if (!hook.listeners('error').length) { - hook.on('error', function (err) { - self.failHook(hook, err); - }); - } - - hook.run(function (err) { - var testError = hook.error(); - if (testError) { - self.fail(self.test, testError); - } - if (err) { - if (err instanceof Pending) { - if (name === 'beforeEach' || name === 'afterEach') { - self.test.pending = true; - } else { - suite.tests.forEach(function (test) { - test.pending = true; - }); - // a pending hook won't be executed twice. - hook.pending = true; - } - } else { - self.failHook(hook, err); - - // stop executing hooks, notify callee of hook err - return fn(err); - } - } - self.emit('hook end', hook); - delete hook.ctx.currentTest; - next(++i); - }); - } - - Runner.immediately(function () { - next(0); - }); -}; - -/** - * Run hook `name` for the given array of `suites` - * in order, and callback `fn(err, errSuite)`. - * - * @api private - * @param {string} name - * @param {Array} suites - * @param {Function} fn - */ -Runner.prototype.hooks = function (name, suites, fn) { - var self = this; - var orig = this.suite; - - function next (suite) { - self.suite = suite; - - if (!suite) { - self.suite = orig; - return fn(); - } - - self.hook(name, function (err) { - if (err) { - var errSuite = self.suite; - self.suite = orig; - return fn(err, errSuite); - } - - next(suites.pop()); - }); - } - - next(suites.pop()); -}; - -/** - * Run hooks from the top level down. - * - * @param {String} name - * @param {Function} fn - * @api private - */ -Runner.prototype.hookUp = function (name, fn) { - var suites = [this.suite].concat(this.parents()).reverse(); - this.hooks(name, suites, fn); -}; - -/** - * Run hooks from the bottom up. - * - * @param {String} name - * @param {Function} fn - * @api private - */ -Runner.prototype.hookDown = function (name, fn) { - var suites = [this.suite].concat(this.parents()); - this.hooks(name, suites, fn); -}; - -/** - * Return an array of parent Suites from - * closest to furthest. - * - * @return {Array} - * @api private - */ -Runner.prototype.parents = function () { - var suite = this.suite; - var suites = []; - while (suite.parent) { - suite = suite.parent; - suites.push(suite); - } - return suites; -}; - -/** - * Run the current test and callback `fn(err)`. - * - * @param {Function} fn - * @api private - */ -Runner.prototype.runTest = function (fn) { - var self = this; - var test = this.test; - - if (!test) { - return; - } - if (this.forbidOnly && hasOnly(this.parents().reverse()[0] || this.suite)) { - fn(new Error('`.only` forbidden')); - return; - } - if (this.asyncOnly) { - test.asyncOnly = true; - } - test.on('error', function (err) { - self.fail(test, err); - }); - if (this.allowUncaught) { - test.allowUncaught = true; - return test.run(fn); - } - try { - test.run(fn); - } catch (err) { - fn(err); - } -}; - -/** - * Run tests in the given `suite` and invoke the callback `fn()` when complete. - * - * @api private - * @param {Suite} suite - * @param {Function} fn - */ -Runner.prototype.runTests = function (suite, fn) { - var self = this; - var tests = suite.tests.slice(); - var test; - - function hookErr (_, errSuite, after) { - // before/after Each hook for errSuite failed: - var orig = self.suite; - - // for failed 'after each' hook start from errSuite parent, - // otherwise start from errSuite itself - self.suite = after ? errSuite.parent : errSuite; - - if (self.suite) { - // call hookUp afterEach - self.hookUp('afterEach', function (err2, errSuite2) { - self.suite = orig; - // some hooks may fail even now - if (err2) { - return hookErr(err2, errSuite2, true); - } - // report error suite - fn(errSuite); - }); - } else { - // there is no need calling other 'after each' hooks - self.suite = orig; - fn(errSuite); - } - } - - function next (err, errSuite) { - // if we bail after first err - if (self.failures && suite._bail) { - return fn(); - } - - if (self._abort) { - return fn(); - } - - if (err) { - return hookErr(err, errSuite, true); - } - - // next test - test = tests.shift(); - - // all done - if (!test) { - return fn(); - } - - // grep - var match = self._grep.test(test.fullTitle()); - if (self._invert) { - match = !match; - } - if (!match) { - // Run immediately only if we have defined a grep. When we - // define a grep — It can cause maximum callstack error if - // the grep is doing a large recursive loop by neglecting - // all tests. The run immediately function also comes with - // a performance cost. So we don't want to run immediately - // if we run the whole test suite, because running the whole - // test suite don't do any immediate recursive loops. Thus, - // allowing a JS runtime to breathe. - if (self._grep !== self._defaultGrep) { - Runner.immediately(next); - } else { - next(); - } - return; - } - - if (test.isPending()) { - if (self.forbidPending) { - test.isPending = alwaysFalse; - self.fail(test, new Error('Pending test forbidden')); - delete test.isPending; - } else { - self.emit('pending', test); - } - self.emit('test end', test); - return next(); - } - - // execute test and hook(s) - self.emit('test', self.test = test); - self.hookDown('beforeEach', function (err, errSuite) { - if (test.isPending()) { - if (self.forbidPending) { - test.isPending = alwaysFalse; - self.fail(test, new Error('Pending test forbidden')); - delete test.isPending; - } else { - self.emit('pending', test); - } - self.emit('test end', test); - return next(); - } - if (err) { - return hookErr(err, errSuite, false); - } - self.currentRunnable = self.test; - self.runTest(function (err) { - test = self.test; - if (err) { - var retry = test.currentRetry(); - if (err instanceof Pending && self.forbidPending) { - self.fail(test, new Error('Pending test forbidden')); - } else if (err instanceof Pending) { - test.pending = true; - self.emit('pending', test); - } else if (retry < test.retries()) { - var clonedTest = test.clone(); - clonedTest.currentRetry(retry + 1); - tests.unshift(clonedTest); - - // Early return + hook trigger so that it doesn't - // increment the count wrong - return self.hookUp('afterEach', next); - } else { - self.fail(test, err); - } - self.emit('test end', test); - - if (err instanceof Pending) { - return next(); - } - - return self.hookUp('afterEach', next); - } - - test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); - }); - }); - } - - this.next = next; - this.hookErr = hookErr; - next(); -}; - -function alwaysFalse () { - return false; -} - -/** - * Run the given `suite` and invoke the callback `fn()` when complete. - * - * @api private - * @param {Suite} suite - * @param {Function} fn - */ -Runner.prototype.runSuite = function (suite, fn) { - var i = 0; - var self = this; - var total = this.grepTotal(suite); - var afterAllHookCalled = false; - - debug('run suite %s', suite.fullTitle()); - - if (!total || (self.failures && suite._bail)) { - return fn(); - } - - this.emit('suite', this.suite = suite); - - function next (errSuite) { - if (errSuite) { - // current suite failed on a hook from errSuite - if (errSuite === suite) { - // if errSuite is current suite - // continue to the next sibling suite - return done(); - } - // errSuite is among the parents of current suite - // stop execution of errSuite and all sub-suites - return done(errSuite); - } - - if (self._abort) { - return done(); - } - - var curr = suite.suites[i++]; - if (!curr) { - return done(); - } - - // Avoid grep neglecting large number of tests causing a - // huge recursive loop and thus a maximum call stack error. - // See comment in `this.runTests()` for more information. - if (self._grep !== self._defaultGrep) { - Runner.immediately(function () { - self.runSuite(curr, next); - }); - } else { - self.runSuite(curr, next); - } - } - - function done (errSuite) { - self.suite = suite; - self.nextSuite = next; - - if (afterAllHookCalled) { - fn(errSuite); - } else { - // mark that the afterAll block has been called once - // and so can be skipped if there is an error in it. - afterAllHookCalled = true; - - // remove reference to test - delete self.test; - - self.hook('afterAll', function () { - self.emit('suite end', suite); - fn(errSuite); - }); - } - } - - this.nextSuite = next; - - this.hook('beforeAll', function (err) { - if (err) { - return done(); - } - self.runTests(suite, next); - }); -}; - -/** - * Handle uncaught exceptions. - * - * @param {Error} err - * @api private - */ -Runner.prototype.uncaught = function (err) { - if (err) { - debug('uncaught exception %s', err === (function () { - return this; - }.call(err)) ? (err.message || err) : err); - } else { - debug('uncaught undefined exception'); - err = undefinedError(); - } - err.uncaught = true; - - var runnable = this.currentRunnable; - - if (!runnable) { - runnable = new Runnable('Uncaught error outside test suite'); - runnable.parent = this.suite; - - if (this.started) { - this.fail(runnable, err); - } else { - // Can't recover from this failure - this.emit('start'); - this.fail(runnable, err); - this.emit('end'); - } - - return; - } - - runnable.clearTimeout(); - - // Ignore errors if complete or pending - if (runnable.state || runnable.isPending()) { - return; - } - this.fail(runnable, err); - - // recover from test - if (runnable.type === 'test') { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // recover from hooks - if (runnable.type === 'hook') { - var errSuite = this.suite; - // if hook failure is in afterEach block - if (runnable.fullTitle().indexOf('after each') > -1) { - return this.hookErr(err, errSuite, true); - } - // if hook failure is in beforeEach block - if (runnable.fullTitle().indexOf('before each') > -1) { - return this.hookErr(err, errSuite, false); - } - // if hook failure is in after or before blocks - return this.nextSuite(errSuite); - } - - // bail - this.emit('end'); -}; - -/** - * Cleans up the references to all the deferred functions - * (before/after/beforeEach/afterEach) and tests of a Suite. - * These must be deleted otherwise a memory leak can happen, - * as those functions may reference variables from closures, - * thus those variables can never be garbage collected as long - * as the deferred functions exist. - * - * @param {Suite} suite - */ -function cleanSuiteReferences (suite) { - function cleanArrReferences (arr) { - for (var i = 0; i < arr.length; i++) { - delete arr[i].fn; - } - } - - if (Array.isArray(suite._beforeAll)) { - cleanArrReferences(suite._beforeAll); - } - - if (Array.isArray(suite._beforeEach)) { - cleanArrReferences(suite._beforeEach); - } - - if (Array.isArray(suite._afterAll)) { - cleanArrReferences(suite._afterAll); - } - - if (Array.isArray(suite._afterEach)) { - cleanArrReferences(suite._afterEach); - } - - for (var i = 0; i < suite.tests.length; i++) { - delete suite.tests[i].fn; - } -} - -/** - * Run the root suite and invoke `fn(failures)` - * on completion. - * - * @param {Function} fn - * @return {Runner} for chaining - * @api public - * @param {Function} fn - * @return {Runner} Runner instance. - */ -Runner.prototype.run = function (fn) { - var self = this; - var rootSuite = this.suite; - - // If there is an `only` filter - if (hasOnly(rootSuite)) { - filterOnly(rootSuite); - } - - fn = fn || function () {}; - - function uncaught (err) { - self.uncaught(err); - } - - function start () { - self.started = true; - self.emit('start'); - self.runSuite(rootSuite, function () { - debug('finished running'); - self.emit('end'); - }); - } - - debug('start'); - - // references cleanup to avoid memory leaks - this.on('suite end', cleanSuiteReferences); - - // callback - this.on('end', function () { - debug('end'); - process.removeListener('uncaughtException', uncaught); - fn(self.failures); - }); - - // uncaught exception - process.on('uncaughtException', uncaught); - - if (this._delay) { - // for reporters, I guess. - // might be nice to debounce some dots while we wait. - this.emit('waiting', rootSuite); - rootSuite.once('run', start); - } else { - start(); - } - - return this; -}; - -/** - * Cleanly abort execution. - * - * @api public - * @return {Runner} Runner instance. - */ -Runner.prototype.abort = function () { - debug('aborting'); - this._abort = true; - - return this; -}; - -/** - * Filter suites based on `isOnly` logic. - * - * @param {Array} suite - * @returns {Boolean} - * @api private - */ -function filterOnly (suite) { - if (suite._onlyTests.length) { - // If the suite contains `only` tests, run those and ignore any nested suites. - suite.tests = suite._onlyTests; - suite.suites = []; - } else { - // Otherwise, do not run any of the tests in this suite. - suite.tests = []; - suite._onlySuites.forEach(function (onlySuite) { - // If there are other `only` tests/suites nested in the current `only` suite, then filter that `only` suite. - // Otherwise, all of the tests on this `only` suite should be run, so don't filter it. - if (hasOnly(onlySuite)) { - filterOnly(onlySuite); - } - }); - // Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants. - suite.suites = suite.suites.filter(function (childSuite) { - return suite._onlySuites.indexOf(childSuite) !== -1 || filterOnly(childSuite); - }); - } - // Keep the suite only if there is something to run - return suite.tests.length || suite.suites.length; -} - -/** - * Determines whether a suite has an `only` test or suite as a descendant. - * - * @param {Array} suite - * @returns {Boolean} - * @api private - */ -function hasOnly (suite) { - return suite._onlyTests.length || suite._onlySuites.length || suite.suites.some(hasOnly); -} - -/** - * Filter leaks with the given globals flagged as `ok`. - * - * @api private - * @param {Array} ok - * @param {Array} globals - * @return {Array} - */ -function filterLeaks (ok, globals) { - return globals.filter(function (key) { - // Firefox and Chrome exposes iframes as index inside the window object - if (/^\d+/.test(key)) { - return false; - } - - // in firefox - // if runner runs in an iframe, this iframe's window.getInterface method - // not init at first it is assigned in some seconds - if (global.navigator && (/^getInterface/).test(key)) { - return false; - } - - // an iframe could be approached by window[iframeIndex] - // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak - if (global.navigator && (/^\d+/).test(key)) { - return false; - } - - // Opera and IE expose global variables for HTML element IDs (issue #243) - if (/^mocha-/.test(key)) { - return false; - } - - var matched = ok.filter(function (ok) { - if (~ok.indexOf('*')) { - return key.indexOf(ok.split('*')[0]) === 0; - } - return key === ok; - }); - return !matched.length && (!global.navigator || key !== 'onerror'); - }); -} - -/** - * Array of globals dependent on the environment. - * - * @return {Array} - * @api private - */ -function extraGlobals () { - if (typeof process === 'object' && typeof process.version === 'string') { - var parts = process.version.split('.'); - var nodeVersion = parts.reduce(function (a, v) { - return a << 8 | v; - }); - - // 'errno' was renamed to process._errno in v0.9.11. - - if (nodeVersion < 0x00090B) { - return ['errno']; - } - } - - return []; -} - -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./pending":15,"./runnable":32,"./utils":36,"_process":55,"debug":42,"events":46}],34:[function(require,module,exports){ -'use strict'; - -/** - * Module dependencies. - */ - -var EventEmitter = require('events').EventEmitter; -var Hook = require('./hook'); -var utils = require('./utils'); -var inherits = utils.inherits; -var debug = require('debug')('mocha:suite'); -var milliseconds = require('./ms'); - -/** - * Expose `Suite`. - */ - -exports = module.exports = Suite; - -/** - * Create a new `Suite` with the given `title` and parent `Suite`. When a suite - * with the same title is already present, that suite is returned to provide - * nicer reporter and more flexible meta-testing. - * - * @api public - * @param {Suite} parent - * @param {string} title - * @return {Suite} - */ -exports.create = function (parent, title) { - var suite = new Suite(title, parent.ctx); - suite.parent = parent; - title = suite.fullTitle(); - parent.addSuite(suite); - return suite; -}; - -/** - * Initialize a new `Suite` with the given `title` and `ctx`. - * - * @api private - * @param {string} title - * @param {Context} parentContext - */ -function Suite (title, parentContext) { - if (!utils.isString(title)) { - throw new Error('Suite `title` should be a "string" but "' + typeof title + '" was given instead.'); - } - this.title = title; - function Context () {} - Context.prototype = parentContext; - this.ctx = new Context(); - this.suites = []; - this.tests = []; - this.pending = false; - this._beforeEach = []; - this._beforeAll = []; - this._afterEach = []; - this._afterAll = []; - this.root = !title; - this._timeout = 2000; - this._enableTimeouts = true; - this._slow = 75; - this._bail = false; - this._retries = -1; - this._onlyTests = []; - this._onlySuites = []; - this.delayed = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ -inherits(Suite, EventEmitter); - -/** - * Return a clone of this `Suite`. - * - * @api private - * @return {Suite} - */ -Suite.prototype.clone = function () { - var suite = new Suite(this.title); - debug('clone'); - suite.ctx = this.ctx; - suite.timeout(this.timeout()); - suite.retries(this.retries()); - suite.enableTimeouts(this.enableTimeouts()); - suite.slow(this.slow()); - suite.bail(this.bail()); - return suite; -}; - -/** - * Set timeout `ms` or short-hand such as "2s". - * - * @api private - * @param {number|string} ms - * @return {Suite|number} for chaining - */ -Suite.prototype.timeout = function (ms) { - if (!arguments.length) { - return this._timeout; - } - if (ms.toString() === '0') { - this._enableTimeouts = false; - } - if (typeof ms === 'string') { - ms = milliseconds(ms); - } - debug('timeout %d', ms); - this._timeout = parseInt(ms, 10); - return this; -}; - -/** - * Set number of times to retry a failed test. - * - * @api private - * @param {number|string} n - * @return {Suite|number} for chaining - */ -Suite.prototype.retries = function (n) { - if (!arguments.length) { - return this._retries; - } - debug('retries %d', n); - this._retries = parseInt(n, 10) || 0; - return this; -}; - -/** - * Set timeout to `enabled`. - * - * @api private - * @param {boolean} enabled - * @return {Suite|boolean} self or enabled - */ -Suite.prototype.enableTimeouts = function (enabled) { - if (!arguments.length) { - return this._enableTimeouts; - } - debug('enableTimeouts %s', enabled); - this._enableTimeouts = enabled; - return this; -}; - -/** - * Set slow `ms` or short-hand such as "2s". - * - * @api private - * @param {number|string} ms - * @return {Suite|number} for chaining - */ -Suite.prototype.slow = function (ms) { - if (!arguments.length) { - return this._slow; - } - if (typeof ms === 'string') { - ms = milliseconds(ms); - } - debug('slow %d', ms); - this._slow = ms; - return this; -}; - -/** - * Sets whether to bail after first error. - * - * @api private - * @param {boolean} bail - * @return {Suite|number} for chaining - */ -Suite.prototype.bail = function (bail) { - if (!arguments.length) { - return this._bail; - } - debug('bail %s', bail); - this._bail = bail; - return this; -}; - -/** - * Check if this suite or its parent suite is marked as pending. - * - * @api private - */ -Suite.prototype.isPending = function () { - return this.pending || (this.parent && this.parent.isPending()); -}; - -/** - * Run `fn(test[, done])` before running tests. - * - * @api private - * @param {string} title - * @param {Function} fn - * @return {Suite} for chaining - */ -Suite.prototype.beforeAll = function (title, fn) { - if (this.isPending()) { - return this; - } - if (typeof title === 'function') { - fn = title; - title = fn.name; - } - title = '"before all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeAll.push(hook); - this.emit('beforeAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after running tests. - * - * @api private - * @param {string} title - * @param {Function} fn - * @return {Suite} for chaining - */ -Suite.prototype.afterAll = function (title, fn) { - if (this.isPending()) { - return this; - } - if (typeof title === 'function') { - fn = title; - title = fn.name; - } - title = '"after all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterAll.push(hook); - this.emit('afterAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` before each test case. - * - * @api private - * @param {string} title - * @param {Function} fn - * @return {Suite} for chaining - */ -Suite.prototype.beforeEach = function (title, fn) { - if (this.isPending()) { - return this; - } - if (typeof title === 'function') { - fn = title; - title = fn.name; - } - title = '"before each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeEach.push(hook); - this.emit('beforeEach', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after each test case. - * - * @api private - * @param {string} title - * @param {Function} fn - * @return {Suite} for chaining - */ -Suite.prototype.afterEach = function (title, fn) { - if (this.isPending()) { - return this; - } - if (typeof title === 'function') { - fn = title; - title = fn.name; - } - title = '"after each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterEach.push(hook); - this.emit('afterEach', hook); - return this; -}; - -/** - * Add a test `suite`. - * - * @api private - * @param {Suite} suite - * @return {Suite} for chaining - */ -Suite.prototype.addSuite = function (suite) { - suite.parent = this; - suite.timeout(this.timeout()); - suite.retries(this.retries()); - suite.enableTimeouts(this.enableTimeouts()); - suite.slow(this.slow()); - suite.bail(this.bail()); - this.suites.push(suite); - this.emit('suite', suite); - return this; -}; - -/** - * Add a `test` to this suite. - * - * @api private - * @param {Test} test - * @return {Suite} for chaining - */ -Suite.prototype.addTest = function (test) { - test.parent = this; - test.timeout(this.timeout()); - test.retries(this.retries()); - test.enableTimeouts(this.enableTimeouts()); - test.slow(this.slow()); - test.ctx = this.ctx; - this.tests.push(test); - this.emit('test', test); - return this; -}; - -/** - * Return the full title generated by recursively concatenating the parent's - * full title. - * - * @api public - * @return {string} - */ -Suite.prototype.fullTitle = function () { - return this.titlePath().join(' '); -}; - -/** - * Return the title path generated by recursively concatenating the parent's - * title path. - * - * @api public - * @return {string} - */ -Suite.prototype.titlePath = function () { - var result = []; - if (this.parent) { - result = result.concat(this.parent.titlePath()); - } - if (!this.root) { - result.push(this.title); - } - return result; -}; - -/** - * Return the total number of tests. - * - * @api public - * @return {number} - */ -Suite.prototype.total = function () { - return this.suites.reduce(function (sum, suite) { - return sum + suite.total(); - }, 0) + this.tests.length; -}; - -/** - * Iterates through each suite recursively to find all tests. Applies a - * function in the format `fn(test)`. - * - * @api private - * @param {Function} fn - * @return {Suite} - */ -Suite.prototype.eachTest = function (fn) { - this.tests.forEach(fn); - this.suites.forEach(function (suite) { - suite.eachTest(fn); - }); - return this; -}; - -/** - * This will run the root suite if we happen to be running in delayed mode. - */ -Suite.prototype.run = function run () { - if (this.root) { - this.emit('run'); - } -}; - -},{"./hook":6,"./ms":14,"./utils":36,"debug":42,"events":46}],35:[function(require,module,exports){ -'use strict'; - -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); -var utils = require('./utils'); -var isString = utils.isString; - -/** - * Expose `Test`. - */ - -module.exports = Test; - -/** - * Initialize a new `Test` with the given `title` and callback `fn`. - * - * @api private - * @param {String} title - * @param {Function} fn - */ -function Test (title, fn) { - if (!isString(title)) { - throw new Error('Test `title` should be a "string" but "' + typeof title + '" was given instead.'); - } - Runnable.call(this, title, fn); - this.pending = !fn; - this.type = 'test'; -} - -/** - * Inherit from `Runnable.prototype`. - */ -utils.inherits(Test, Runnable); - -Test.prototype.clone = function () { - var test = new Test(this.title, this.fn); - test.timeout(this.timeout()); - test.slow(this.slow()); - test.enableTimeouts(this.enableTimeouts()); - test.retries(this.retries()); - test.currentRetry(this.currentRetry()); - test.globals(this.globals()); - test.parent = this.parent; - test.file = this.file; - test.ctx = this.ctx; - return test; -}; - -},{"./runnable":32,"./utils":36}],36:[function(require,module,exports){ -(function (process,Buffer){ -'use strict'; - -/* eslint-env browser */ - -/** - * Module dependencies. - */ - -var basename = require('path').basename; -var debug = require('debug')('mocha:watch'); -var exists = require('fs').existsSync; -var glob = require('glob'); -var path = require('path'); -var join = path.join; -var readdirSync = require('fs').readdirSync; -var statSync = require('fs').statSync; -var watchFile = require('fs').watchFile; -var lstatSync = require('fs').lstatSync; -var he = require('he'); - -/** - * Ignored directories. - */ - -var ignore = ['node_modules', '.git']; - -exports.inherits = require('util').inherits; - -/** - * Escape special characters in the given string of html. - * - * @api private - * @param {string} html - * @return {string} - */ -exports.escape = function (html) { - return he.encode(String(html), { useNamedReferences: false }); -}; - -/** - * Test if the given obj is type of string. - * - * @api private - * @param {Object} obj - * @return {boolean} - */ -exports.isString = function (obj) { - return typeof obj === 'string'; -}; - -/** - * Watch the given `files` for changes - * and invoke `fn(file)` on modification. - * - * @api private - * @param {Array} files - * @param {Function} fn - */ -exports.watch = function (files, fn) { - var options = { interval: 100 }; - files.forEach(function (file) { - debug('file %s', file); - watchFile(file, options, function (curr, prev) { - if (prev.mtime < curr.mtime) { - fn(file); - } - }); - }); -}; - -/** - * Ignored files. - * - * @api private - * @param {string} path - * @return {boolean} - */ -function ignored (path) { - return !~ignore.indexOf(path); -} - -/** - * Lookup files in the given `dir`. - * - * @api private - * @param {string} dir - * @param {string[]} [ext=['.js']] - * @param {Array} [ret=[]] - * @return {Array} - */ -exports.files = function (dir, ext, ret) { - ret = ret || []; - ext = ext || ['js']; - - var re = new RegExp('\\.(' + ext.join('|') + ')$'); - - readdirSync(dir) - .filter(ignored) - .forEach(function (path) { - path = join(dir, path); - if (lstatSync(path).isDirectory()) { - exports.files(path, ext, ret); - } else if (path.match(re)) { - ret.push(path); - } - }); - - return ret; -}; - -/** - * Compute a slug from the given `str`. - * - * @api private - * @param {string} str - * @return {string} - */ -exports.slug = function (str) { - return str - .toLowerCase() - .replace(/ +/g, '-') - .replace(/[^-\w]/g, ''); -}; - -/** - * Strip the function definition from `str`, and re-indent for pre whitespace. - * - * @param {string} str - * @return {string} - */ -exports.clean = function (str) { - str = str - .replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '') - // (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content - .replace(/^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/, '$1$2$3'); - - var spaces = str.match(/^\n?( *)/)[1].length; - var tabs = str.match(/^\n?(\t*)/)[1].length; - var re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}', 'gm'); - - str = str.replace(re, ''); - - return str.trim(); -}; - -/** - * Parse the given `qs`. - * - * @api private - * @param {string} qs - * @return {Object} - */ -exports.parseQuery = function (qs) { - return qs.replace('?', '').split('&').reduce(function (obj, pair) { - var i = pair.indexOf('='); - var key = pair.slice(0, i); - var val = pair.slice(++i); - - // Due to how the URLSearchParams API treats spaces - obj[key] = decodeURIComponent(val.replace(/\+/g, '%20')); - - return obj; - }, {}); -}; - -/** - * Highlight the given string of `js`. - * - * @api private - * @param {string} js - * @return {string} - */ -function highlight (js) { - return js - .replace(//g, '>') - .replace(/\/\/(.*)/gm, '//$1') - .replace(/('.*?')/gm, '$1') - .replace(/(\d+\.\d+)/gm, '$1') - .replace(/(\d+)/gm, '$1') - .replace(/\bnew[ \t]+(\w+)/gm, 'new $1') - .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1'); -} - -/** - * Highlight the contents of tag `name`. - * - * @api private - * @param {string} name - */ -exports.highlightTags = function (name) { - var code = document.getElementById('mocha').getElementsByTagName(name); - for (var i = 0, len = code.length; i < len; ++i) { - code[i].innerHTML = highlight(code[i].innerHTML); - } -}; - -/** - * If a value could have properties, and has none, this function is called, - * which returns a string representation of the empty value. - * - * Functions w/ no properties return `'[Function]'` - * Arrays w/ length === 0 return `'[]'` - * Objects w/ no properties return `'{}'` - * All else: return result of `value.toString()` - * - * @api private - * @param {*} value The value to inspect. - * @param {string} typeHint The type of the value - * @returns {string} - */ -function emptyRepresentation (value, typeHint) { - switch (typeHint) { - case 'function': - return '[Function]'; - case 'object': - return '{}'; - case 'array': - return '[]'; - default: - return value.toString(); - } -} - -/** - * Takes some variable and asks `Object.prototype.toString()` what it thinks it - * is. - * - * @api private - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString - * @param {*} value The value to test. - * @returns {string} Computed type - * @example - * type({}) // 'object' - * type([]) // 'array' - * type(1) // 'number' - * type(false) // 'boolean' - * type(Infinity) // 'number' - * type(null) // 'null' - * type(new Date()) // 'date' - * type(/foo/) // 'regexp' - * type('type') // 'string' - * type(global) // 'global' - * type(new String('foo') // 'object' - */ -var type = exports.type = function type (value) { - if (value === undefined) { - return 'undefined'; - } else if (value === null) { - return 'null'; - } else if (Buffer.isBuffer(value)) { - return 'buffer'; - } - return Object.prototype.toString.call(value) - .replace(/^\[.+\s(.+?)]$/, '$1') - .toLowerCase(); -}; - -/** - * Stringify `value`. Different behavior depending on type of value: - * - * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively. - * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes. - * - If `value` is an *empty* object, function, or array, return result of function - * {@link emptyRepresentation}. - * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of - * JSON.stringify(). - * - * @api private - * @see exports.type - * @param {*} value - * @return {string} - */ -exports.stringify = function (value) { - var typeHint = type(value); - - if (!~['object', 'array', 'function'].indexOf(typeHint)) { - if (typeHint === 'buffer') { - var json = Buffer.prototype.toJSON.call(value); - // Based on the toJSON result - return jsonStringify(json.data && json.type ? json.data : json, 2) - .replace(/,(\n|$)/g, '$1'); - } - - // IE7/IE8 has a bizarre String constructor; needs to be coerced - // into an array and back to obj. - if (typeHint === 'string' && typeof value === 'object') { - value = value.split('').reduce(function (acc, char, idx) { - acc[idx] = char; - return acc; - }, {}); - typeHint = 'object'; - } else { - return jsonStringify(value); - } - } - - for (var prop in value) { - if (Object.prototype.hasOwnProperty.call(value, prop)) { - return jsonStringify(exports.canonicalize(value, null, typeHint), 2).replace(/,(\n|$)/g, '$1'); - } - } - - return emptyRepresentation(value, typeHint); -}; - -/** - * like JSON.stringify but more sense. - * - * @api private - * @param {Object} object - * @param {number=} spaces - * @param {number=} depth - * @returns {*} - */ -function jsonStringify (object, spaces, depth) { - if (typeof spaces === 'undefined') { - // primitive types - return _stringify(object); - } - - depth = depth || 1; - var space = spaces * depth; - var str = Array.isArray(object) ? '[' : '{'; - var end = Array.isArray(object) ? ']' : '}'; - var length = typeof object.length === 'number' ? object.length : Object.keys(object).length; - // `.repeat()` polyfill - function repeat (s, n) { - return new Array(n).join(s); - } - - function _stringify (val) { - switch (type(val)) { - case 'null': - case 'undefined': - val = '[' + val + ']'; - break; - case 'array': - case 'object': - val = jsonStringify(val, spaces, depth + 1); - break; - case 'boolean': - case 'regexp': - case 'symbol': - case 'number': - val = val === 0 && (1 / val) === -Infinity // `-0` - ? '-0' - : val.toString(); - break; - case 'date': - var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString(); - val = '[Date: ' + sDate + ']'; - break; - case 'buffer': - var json = val.toJSON(); - // Based on the toJSON result - json = json.data && json.type ? json.data : json; - val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']'; - break; - default: - val = (val === '[Function]' || val === '[Circular]') - ? val - : JSON.stringify(val); // string - } - return val; - } - - for (var i in object) { - if (!Object.prototype.hasOwnProperty.call(object, i)) { - continue; // not my business - } - --length; - str += '\n ' + repeat(' ', space) + - (Array.isArray(object) ? '' : '"' + i + '": ') + // key - _stringify(object[i]) + // value - (length ? ',' : ''); // comma - } - - return str + - // [], {} - (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end); -} - -/** - * Return a new Thing that has the keys in sorted order. Recursive. - * - * If the Thing... - * - has already been seen, return string `'[Circular]'` - * - is `undefined`, return string `'[undefined]'` - * - is `null`, return value `null` - * - is some other primitive, return the value - * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method - * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again. - * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()` - * - * @api private - * @see {@link exports.stringify} - * @param {*} value Thing to inspect. May or may not have properties. - * @param {Array} [stack=[]] Stack of seen values - * @param {string} [typeHint] Type hint - * @return {(Object|Array|Function|string|undefined)} - */ -exports.canonicalize = function canonicalize (value, stack, typeHint) { - var canonicalizedObj; - /* eslint-disable no-unused-vars */ - var prop; - /* eslint-enable no-unused-vars */ - typeHint = typeHint || type(value); - function withStack (value, fn) { - stack.push(value); - fn(); - stack.pop(); - } - - stack = stack || []; - - if (stack.indexOf(value) !== -1) { - return '[Circular]'; - } - - switch (typeHint) { - case 'undefined': - case 'buffer': - case 'null': - canonicalizedObj = value; - break; - case 'array': - withStack(value, function () { - canonicalizedObj = value.map(function (item) { - return exports.canonicalize(item, stack); - }); - }); - break; - case 'function': - /* eslint-disable guard-for-in */ - for (prop in value) { - canonicalizedObj = {}; - break; - } - /* eslint-enable guard-for-in */ - if (!canonicalizedObj) { - canonicalizedObj = emptyRepresentation(value, typeHint); - break; - } - /* falls through */ - case 'object': - canonicalizedObj = canonicalizedObj || {}; - withStack(value, function () { - Object.keys(value).sort().forEach(function (key) { - canonicalizedObj[key] = exports.canonicalize(value[key], stack); - }); - }); - break; - case 'date': - case 'number': - case 'regexp': - case 'boolean': - case 'symbol': - canonicalizedObj = value; - break; - default: - canonicalizedObj = value + ''; - } - - return canonicalizedObj; -}; - -/** - * Lookup file names at the given `path`. - * - * @api public - * @param {string} path Base path to start searching from. - * @param {string[]} extensions File extensions to look for. - * @param {boolean} recursive Whether or not to recurse into subdirectories. - * @return {string[]} An array of paths. - */ -exports.lookupFiles = function lookupFiles (path, extensions, recursive) { - var files = []; - var re = new RegExp('\\.(' + extensions.join('|') + ')$'); - - if (!exists(path)) { - if (exists(path + '.js')) { - path += '.js'; - } else { - files = glob.sync(path); - if (!files.length) { - throw new Error("cannot resolve path (or pattern) '" + path + "'"); - } - return files; - } - } - - try { - var stat = statSync(path); - if (stat.isFile()) { - return path; - } - } catch (err) { - // ignore error - return; - } - - readdirSync(path).forEach(function (file) { - file = join(path, file); - try { - var stat = statSync(file); - if (stat.isDirectory()) { - if (recursive) { - files = files.concat(lookupFiles(file, extensions, recursive)); - } - return; - } - } catch (err) { - // ignore error - return; - } - if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') { - return; - } - files.push(file); - }); - - return files; -}; - -/** - * Generate an undefined error with a message warning the user. - * - * @return {Error} - */ - -exports.undefinedError = function () { - return new Error('Caught undefined error, did you throw without specifying what?'); -}; - -/** - * Generate an undefined error if `err` is not defined. - * - * @param {Error} err - * @return {Error} - */ - -exports.getError = function (err) { - return err || exports.undefinedError(); -}; - -/** - * @summary - * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`) - * @description - * When invoking this function you get a filter function that get the Error.stack as an input, - * and return a prettify output. - * (i.e: strip Mocha and internal node functions from stack trace). - * @returns {Function} - */ -exports.stackTraceFilter = function () { - // TODO: Replace with `process.browser` - var is = typeof document === 'undefined' ? { node: true } : { browser: true }; - var slash = path.sep; - var cwd; - if (is.node) { - cwd = process.cwd() + slash; - } else { - cwd = (typeof location === 'undefined' - ? window.location - : location).href.replace(/\/[^/]*$/, '/'); - slash = '/'; - } - - function isMochaInternal (line) { - return (~line.indexOf('node_modules' + slash + 'mocha' + slash)) || - (~line.indexOf('node_modules' + slash + 'mocha.js')) || - (~line.indexOf('bower_components' + slash + 'mocha.js')) || - (~line.indexOf(slash + 'mocha.js')); - } - - function isNodeInternal (line) { - return (~line.indexOf('(timers.js:')) || - (~line.indexOf('(events.js:')) || - (~line.indexOf('(node.js:')) || - (~line.indexOf('(module.js:')) || - (~line.indexOf('GeneratorFunctionPrototype.next (native)')) || - false; - } - - return function (stack) { - stack = stack.split('\n'); - - stack = stack.reduce(function (list, line) { - if (isMochaInternal(line)) { - return list; - } - - if (is.node && isNodeInternal(line)) { - return list; - } - - // Clean up cwd(absolute) - if (/\(?.+:\d+:\d+\)?$/.test(line)) { - line = line.replace(cwd, ''); - } - - list.push(line); - return list; - }, []); - - return stack.join('\n'); - }; -}; - -/** - * Crude, but effective. - * @api - * @param {*} value - * @returns {boolean} Whether or not `value` is a Promise - */ -exports.isPromise = function isPromise (value) { - return typeof value === 'object' && typeof value.then === 'function'; -}; - -/** - * It's a noop. - * @api - */ -exports.noop = function () {}; - -}).call(this,require('_process'),require("buffer").Buffer) -},{"_process":55,"buffer":"buffer","debug":42,"fs":40,"glob":40,"he":47,"path":40,"util":75}],37:[function(require,module,exports){ -'use strict' - -exports.byteLength = byteLength -exports.toByteArray = toByteArray -exports.fromByteArray = fromByteArray - -var lookup = [] -var revLookup = [] -var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array - -var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -for (var i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] - revLookup[code.charCodeAt(i)] = i -} - -revLookup['-'.charCodeAt(0)] = 62 -revLookup['_'.charCodeAt(0)] = 63 - -function placeHoldersCount (b64) { - var len = b64.length - if (len % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 -} - -function byteLength (b64) { - // base64 is 4/3 + up to two characters of the original data - return (b64.length * 3 / 4) - placeHoldersCount(b64) -} - -function toByteArray (b64) { - var i, l, tmp, placeHolders, arr - var len = b64.length - placeHolders = placeHoldersCount(b64) - - arr = new Arr((len * 3 / 4) - placeHolders) - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? len - 4 : len - - var L = 0 - - for (i = 0; i < l; i += 4) { - tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] - arr[L++] = (tmp >> 16) & 0xFF - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } - - if (placeHolders === 2) { - tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[L++] = tmp & 0xFF - } else if (placeHolders === 1) { - tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF - } - - return arr -} - -function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] -} - -function encodeChunk (uint8, start, end) { - var tmp - var output = [] - for (var i = start; i < end; i += 3) { - tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output.push(tripletToBase64(tmp)) - } - return output.join('') -} - -function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var output = '' - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 - - // go through the array every three bytes, we'll deal with trailing stuff later - for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 1) { - tmp = uint8[len - 1] - output += lookup[tmp >> 2] - output += lookup[(tmp << 4) & 0x3F] - output += '==' - } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) - output += lookup[tmp >> 10] - output += lookup[(tmp >> 4) & 0x3F] - output += lookup[(tmp << 2) & 0x3F] - output += '=' - } - - parts.push(output) - - return parts.join('') -} - -},{}],38:[function(require,module,exports){ - -},{}],39:[function(require,module,exports){ -(function (process){ -var WritableStream = require('stream').Writable -var inherits = require('util').inherits - -module.exports = BrowserStdout - - -inherits(BrowserStdout, WritableStream) - -function BrowserStdout(opts) { - if (!(this instanceof BrowserStdout)) return new BrowserStdout(opts) - - opts = opts || {} - WritableStream.call(this, opts) - this.label = (opts.label !== undefined) ? opts.label : 'stdout' -} - -BrowserStdout.prototype._write = function(chunks, encoding, cb) { - var output = chunks.toString ? chunks.toString() : chunks - if (this.label === false) { - console.log(output) - } else { - console.log(this.label+':', output) - } - process.nextTick(cb) -} - -}).call(this,require('_process')) -},{"_process":55,"stream":70,"util":75}],40:[function(require,module,exports){ -arguments[4][38][0].apply(exports,arguments) -},{"dup":38}],41:[function(require,module,exports){ -(function (Buffer){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. - -function isArray(arg) { - if (Array.isArray) { - return Array.isArray(arg); - } - return objectToString(arg) === '[object Array]'; -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; - -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; - -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; - -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; - -function isRegExp(re) { - return objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; - -function isDate(d) { - return objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; - -function isError(e) { - return (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; - -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; - -exports.isBuffer = Buffer.isBuffer; - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - -}).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":50}],42:[function(require,module,exports){ -(function (process){ -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = require('./debug'); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - -/** - * Colors. - */ - -exports.colors = [ - '#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', - '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', - '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', - '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', - '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', - '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', - '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', - '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', - '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', - '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', - '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33' -]; - -/** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; - } - - // Internet Explorer and Edge do not support colors. - if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) { - return false; - } - - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); -} - -/** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; - } -}; - - -/** - * Colorize log arguments if enabled. - * - * @api public - */ - -function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return; - - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit') - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - - args.splice(lastC, 0, c); -} - -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } - - return r; -} - -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ - -exports.enable(load()); - -/** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - -function localstorage() { - try { - return window.localStorage; - } catch (e) {} -} - -}).call(this,require('_process')) -},{"./debug":43,"_process":55}],43:[function(require,module,exports){ - -/** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = require('ms'); - -/** - * Active `debug` instances. - */ -exports.instances = []; - -/** - * The currently active debug mode names, and names to skip. - */ - -exports.names = []; -exports.skips = []; - -/** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". - */ - -exports.formatters = {}; - -/** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ - -function selectColor(namespace) { - var hash = 0, i; - - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer - } - - return exports.colors[Math.abs(hash) % exports.colors.length]; -} - -/** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - -function createDebug(namespace) { - - var prevTime; - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; - - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; - - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - - args[0] = exports.coerce(args[0]); - - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } - - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); - - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); - - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } - - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); - debug.destroy = destroy; - - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); - } - - exports.instances.push(debug); - - return debug; -} - -function destroy () { - var index = exports.instances.indexOf(this); - if (index !== -1) { - exports.instances.splice(index, 1); - return true; - } else { - return false; - } -} - -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ - -function enable(namespaces) { - exports.save(namespaces); - - exports.names = []; - exports.skips = []; - - var i; - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; - - for (i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } - - for (i = 0; i < exports.instances.length; i++) { - var instance = exports.instances[i]; - instance.enabled = exports.enabled(instance.namespace); - } -} - -/** - * Disable debug output. - * - * @api public - */ - -function disable() { - exports.enable(''); -} - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - -function enabled(name) { - if (name[name.length - 1] === '*') { - return true; - } - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; - } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; -} - -/** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} - -},{"ms":53}],44:[function(require,module,exports){ -/*! - - diff v3.3.1 - -Software License Agreement (BSD License) - -Copyright (c) 2009-2015, Kevin Decker - -All rights reserved. - -Redistribution and use of this software in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of Kevin Decker nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -@license -*/ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(false) - define([], factory); - else if(typeof exports === 'object') - exports["JsDiff"] = factory(); - else - root["JsDiff"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports.canonicalize = exports.convertChangesToXML = exports.convertChangesToDMP = exports.merge = exports.parsePatch = exports.applyPatches = exports.applyPatch = exports.createPatch = exports.createTwoFilesPatch = exports.structuredPatch = exports.diffArrays = exports.diffJson = exports.diffCss = exports.diffSentences = exports.diffTrimmedLines = exports.diffLines = exports.diffWordsWithSpace = exports.diffWords = exports.diffChars = exports.Diff = undefined; - - /*istanbul ignore end*/var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - - /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - - /*istanbul ignore end*/var /*istanbul ignore start*/_character = __webpack_require__(2) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_word = __webpack_require__(3) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_line = __webpack_require__(5) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_sentence = __webpack_require__(6) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_css = __webpack_require__(7) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_json = __webpack_require__(8) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_array = __webpack_require__(9) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_apply = __webpack_require__(10) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_parse = __webpack_require__(11) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_merge = __webpack_require__(13) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_create = __webpack_require__(14) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_dmp = __webpack_require__(16) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_xml = __webpack_require__(17) /*istanbul ignore end*/; - - /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - - /* See LICENSE file for terms of use */ - - /* - * Text diff implementation. - * - * This library supports the following APIS: - * JsDiff.diffChars: Character by character diff - * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace - * JsDiff.diffLines: Line based diff - * - * JsDiff.diffCss: Diff targeted at CSS content - * - * These methods are based on the implementation proposed in - * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). - * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 - */ - exports. /*istanbul ignore end*/Diff = _base2['default']; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffChars = _character.diffChars; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffWords = _word.diffWords; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffWordsWithSpace = _word.diffWordsWithSpace; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffLines = _line.diffLines; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffTrimmedLines = _line.diffTrimmedLines; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffSentences = _sentence.diffSentences; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffCss = _css.diffCss; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffJson = _json.diffJson; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffArrays = _array.diffArrays; - /*istanbul ignore start*/exports. /*istanbul ignore end*/structuredPatch = _create.structuredPatch; - /*istanbul ignore start*/exports. /*istanbul ignore end*/createTwoFilesPatch = _create.createTwoFilesPatch; - /*istanbul ignore start*/exports. /*istanbul ignore end*/createPatch = _create.createPatch; - /*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatch = _apply.applyPatch; - /*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatches = _apply.applyPatches; - /*istanbul ignore start*/exports. /*istanbul ignore end*/parsePatch = _parse.parsePatch; - /*istanbul ignore start*/exports. /*istanbul ignore end*/merge = _merge.merge; - /*istanbul ignore start*/exports. /*istanbul ignore end*/convertChangesToDMP = _dmp.convertChangesToDMP; - /*istanbul ignore start*/exports. /*istanbul ignore end*/convertChangesToXML = _xml.convertChangesToXML; - /*istanbul ignore start*/exports. /*istanbul ignore end*/canonicalize = _json.canonicalize; - - - -/***/ }), -/* 1 */ -/***/ (function(module, exports) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports['default'] = /*istanbul ignore end*/Diff; - function Diff() {} - - Diff.prototype = { - /*istanbul ignore start*/ /*istanbul ignore end*/diff: function diff(oldString, newString) { - /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - - var callback = options.callback; - if (typeof options === 'function') { - callback = options; - options = {}; - } - this.options = options; - - var self = this; - - function done(value) { - if (callback) { - setTimeout(function () { - callback(undefined, value); - }, 0); - return true; - } else { - return value; - } - } - - // Allow subclasses to massage the input prior to running - oldString = this.castInput(oldString); - newString = this.castInput(newString); - - oldString = this.removeEmpty(this.tokenize(oldString)); - newString = this.removeEmpty(this.tokenize(newString)); - - var newLen = newString.length, - oldLen = oldString.length; - var editLength = 1; - var maxEditLength = newLen + oldLen; - var bestPath = [{ newPos: -1, components: [] }]; - - // Seed editLength = 0, i.e. the content starts with the same values - var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); - if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) { - // Identity per the equality and tokenizer - return done([{ value: this.join(newString), count: newString.length }]); - } - - // Main worker method. checks all permutations of a given edit length for acceptance. - function execEditLength() { - for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) { - var basePath = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; - var addPath = bestPath[diagonalPath - 1], - removePath = bestPath[diagonalPath + 1], - _oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; - if (addPath) { - // No one else is going to attempt to use this value, clear it - bestPath[diagonalPath - 1] = undefined; - } - - var canAdd = addPath && addPath.newPos + 1 < newLen, - canRemove = removePath && 0 <= _oldPos && _oldPos < oldLen; - if (!canAdd && !canRemove) { - // If this path is a terminal then prune - bestPath[diagonalPath] = undefined; - continue; - } - - // Select the diagonal that we want to branch from. We select the prior - // path whose position in the new string is the farthest from the origin - // and does not pass the bounds of the diff graph - if (!canAdd || canRemove && addPath.newPos < removePath.newPos) { - basePath = clonePath(removePath); - self.pushComponent(basePath.components, undefined, true); - } else { - basePath = addPath; // No need to clone, we've pulled it from the list - basePath.newPos++; - self.pushComponent(basePath.components, true, undefined); - } - - _oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath); - - // If we have hit the end of both strings, then we are done - if (basePath.newPos + 1 >= newLen && _oldPos + 1 >= oldLen) { - return done(buildValues(self, basePath.components, newString, oldString, self.useLongestToken)); - } else { - // Otherwise track this path as a potential candidate and continue. - bestPath[diagonalPath] = basePath; - } - } - - editLength++; - } - - // Performs the length of edit iteration. Is a bit fugly as this has to support the - // sync and async mode which is never fun. Loops over execEditLength until a value - // is produced. - if (callback) { - (function exec() { - setTimeout(function () { - // This should not happen, but we want to be safe. - /* istanbul ignore next */ - if (editLength > maxEditLength) { - return callback(); - } - - if (!execEditLength()) { - exec(); - } - }, 0); - })(); - } else { - while (editLength <= maxEditLength) { - var ret = execEditLength(); - if (ret) { - return ret; - } - } - } - }, - /*istanbul ignore start*/ /*istanbul ignore end*/pushComponent: function pushComponent(components, added, removed) { - var last = components[components.length - 1]; - if (last && last.added === added && last.removed === removed) { - // We need to clone here as the component clone operation is just - // as shallow array clone - components[components.length - 1] = { count: last.count + 1, added: added, removed: removed }; - } else { - components.push({ count: 1, added: added, removed: removed }); - } - }, - /*istanbul ignore start*/ /*istanbul ignore end*/extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath) { - var newLen = newString.length, - oldLen = oldString.length, - newPos = basePath.newPos, - oldPos = newPos - diagonalPath, - commonCount = 0; - while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) { - newPos++; - oldPos++; - commonCount++; - } - - if (commonCount) { - basePath.components.push({ count: commonCount }); - } - - basePath.newPos = newPos; - return oldPos; - }, - /*istanbul ignore start*/ /*istanbul ignore end*/equals: function equals(left, right) { - return left === right || this.options.ignoreCase && left.toLowerCase() === right.toLowerCase(); - }, - /*istanbul ignore start*/ /*istanbul ignore end*/removeEmpty: function removeEmpty(array) { - var ret = []; - for (var i = 0; i < array.length; i++) { - if (array[i]) { - ret.push(array[i]); - } - } - return ret; - }, - /*istanbul ignore start*/ /*istanbul ignore end*/castInput: function castInput(value) { - return value; - }, - /*istanbul ignore start*/ /*istanbul ignore end*/tokenize: function tokenize(value) { - return value.split(''); - }, - /*istanbul ignore start*/ /*istanbul ignore end*/join: function join(chars) { - return chars.join(''); - } - }; - - function buildValues(diff, components, newString, oldString, useLongestToken) { - var componentPos = 0, - componentLen = components.length, - newPos = 0, - oldPos = 0; - - for (; componentPos < componentLen; componentPos++) { - var component = components[componentPos]; - if (!component.removed) { - if (!component.added && useLongestToken) { - var value = newString.slice(newPos, newPos + component.count); - value = value.map(function (value, i) { - var oldValue = oldString[oldPos + i]; - return oldValue.length > value.length ? oldValue : value; - }); - - component.value = diff.join(value); - } else { - component.value = diff.join(newString.slice(newPos, newPos + component.count)); - } - newPos += component.count; - - // Common case - if (!component.added) { - oldPos += component.count; - } - } else { - component.value = diff.join(oldString.slice(oldPos, oldPos + component.count)); - oldPos += component.count; - - // Reverse add and remove so removes are output first to match common convention - // The diffing algorithm is tied to add then remove output and this is the simplest - // route to get the desired output with minimal overhead. - if (componentPos && components[componentPos - 1].added) { - var tmp = components[componentPos - 1]; - components[componentPos - 1] = components[componentPos]; - components[componentPos] = tmp; - } - } - } - - // Special case handle for when one terminal is ignored. For this case we merge the - // terminal into the prior string and drop the change. - var lastComponent = components[componentLen - 1]; - if (componentLen > 1 && (lastComponent.added || lastComponent.removed) && diff.equals('', lastComponent.value)) { - components[componentLen - 2].value += lastComponent.value; - components.pop(); - } - - return components; - } - - function clonePath(path) { - return { newPos: path.newPos, components: path.components.slice(0) }; - } - - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports.characterDiff = undefined; - exports. /*istanbul ignore end*/diffChars = diffChars; - - var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - - /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - - /*istanbul ignore end*/var characterDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/characterDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); - function diffChars(oldStr, newStr, options) { - return characterDiff.diff(oldStr, newStr, options); - } - - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports.wordDiff = undefined; - exports. /*istanbul ignore end*/diffWords = diffWords; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffWordsWithSpace = diffWordsWithSpace; - - var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - - /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - - /*istanbul ignore end*/var /*istanbul ignore start*/_params = __webpack_require__(4) /*istanbul ignore end*/; - - /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - - /*istanbul ignore end*/ // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode - // - // Ranges and exceptions: - // Latin-1 Supplement, 0080–00FF - // - U+00D7 × Multiplication sign - // - U+00F7 ÷ Division sign - // Latin Extended-A, 0100–017F - // Latin Extended-B, 0180–024F - // IPA Extensions, 0250–02AF - // Spacing Modifier Letters, 02B0–02FF - // - U+02C7 ˇ ˇ Caron - // - U+02D8 ˘ ˘ Breve - // - U+02D9 ˙ ˙ Dot Above - // - U+02DA ˚ ˚ Ring Above - // - U+02DB ˛ ˛ Ogonek - // - U+02DC ˜ ˜ Small Tilde - // - U+02DD ˝ ˝ Double Acute Accent - // Latin Extended Additional, 1E00–1EFF - var extendedWordChars = /^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/; - - var reWhitespace = /\S/; - - var wordDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/wordDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); - wordDiff.equals = function (left, right) { - if (this.options.ignoreCase) { - left = left.toLowerCase(); - right = right.toLowerCase(); - } - return left === right || this.options.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right); - }; - wordDiff.tokenize = function (value) { - var tokens = value.split(/(\s+|\b)/); - - // Join the boundary splits that we do not consider to be boundaries. This is primarily the extended Latin character set. - for (var i = 0; i < tokens.length - 1; i++) { - // If we have an empty string in the next field and we have only word chars before and after, merge - if (!tokens[i + 1] && tokens[i + 2] && extendedWordChars.test(tokens[i]) && extendedWordChars.test(tokens[i + 2])) { - tokens[i] += tokens[i + 2]; - tokens.splice(i + 1, 2); - i--; - } - } - - return tokens; - }; - - function diffWords(oldStr, newStr, options) { - options = /*istanbul ignore start*/(0, _params.generateOptions) /*istanbul ignore end*/(options, { ignoreWhitespace: true }); - return wordDiff.diff(oldStr, newStr, options); - } - - function diffWordsWithSpace(oldStr, newStr, options) { - return wordDiff.diff(oldStr, newStr, options); - } - - - -/***/ }), -/* 4 */ -/***/ (function(module, exports) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports. /*istanbul ignore end*/generateOptions = generateOptions; - function generateOptions(options, defaults) { - if (typeof options === 'function') { - defaults.callback = options; - } else if (options) { - for (var name in options) { - /* istanbul ignore else */ - if (options.hasOwnProperty(name)) { - defaults[name] = options[name]; - } - } - } - return defaults; - } - - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports.lineDiff = undefined; - exports. /*istanbul ignore end*/diffLines = diffLines; - /*istanbul ignore start*/exports. /*istanbul ignore end*/diffTrimmedLines = diffTrimmedLines; - - var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - - /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - - /*istanbul ignore end*/var /*istanbul ignore start*/_params = __webpack_require__(4) /*istanbul ignore end*/; - - /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - - /*istanbul ignore end*/var lineDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/lineDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); - lineDiff.tokenize = function (value) { - var retLines = [], - linesAndNewlines = value.split(/(\n|\r\n)/); - - // Ignore the final empty token that occurs if the string ends with a new line - if (!linesAndNewlines[linesAndNewlines.length - 1]) { - linesAndNewlines.pop(); - } - - // Merge the content and line separators into single tokens - for (var i = 0; i < linesAndNewlines.length; i++) { - var line = linesAndNewlines[i]; - - if (i % 2 && !this.options.newlineIsToken) { - retLines[retLines.length - 1] += line; - } else { - if (this.options.ignoreWhitespace) { - line = line.trim(); - } - retLines.push(line); - } - } - - return retLines; - }; - - function diffLines(oldStr, newStr, callback) { - return lineDiff.diff(oldStr, newStr, callback); - } - function diffTrimmedLines(oldStr, newStr, callback) { - var options = /*istanbul ignore start*/(0, _params.generateOptions) /*istanbul ignore end*/(callback, { ignoreWhitespace: true }); - return lineDiff.diff(oldStr, newStr, options); - } - - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports.sentenceDiff = undefined; - exports. /*istanbul ignore end*/diffSentences = diffSentences; - - var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - - /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - - /*istanbul ignore end*/var sentenceDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/sentenceDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); - sentenceDiff.tokenize = function (value) { - return value.split(/(\S.+?[.!?])(?=\s+|$)/); - }; - - function diffSentences(oldStr, newStr, callback) { - return sentenceDiff.diff(oldStr, newStr, callback); - } - - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports.cssDiff = undefined; - exports. /*istanbul ignore end*/diffCss = diffCss; - - var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - - /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - - /*istanbul ignore end*/var cssDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/cssDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); - cssDiff.tokenize = function (value) { - return value.split(/([{}:;,]|\s+)/); - }; - - function diffCss(oldStr, newStr, callback) { - return cssDiff.diff(oldStr, newStr, callback); - } - - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports.jsonDiff = undefined; - - var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - - exports. /*istanbul ignore end*/diffJson = diffJson; - /*istanbul ignore start*/exports. /*istanbul ignore end*/canonicalize = canonicalize; - - var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - - /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - - /*istanbul ignore end*/var /*istanbul ignore start*/_line = __webpack_require__(5) /*istanbul ignore end*/; - - /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - - /*istanbul ignore end*/var objectPrototypeToString = Object.prototype.toString; - - var jsonDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/jsonDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); - // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a - // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output: - jsonDiff.useLongestToken = true; - - jsonDiff.tokenize = /*istanbul ignore start*/_line.lineDiff /*istanbul ignore end*/.tokenize; - jsonDiff.castInput = function (value) { - /*istanbul ignore start*/var /*istanbul ignore end*/undefinedReplacement = this.options.undefinedReplacement; - - - return typeof value === 'string' ? value : JSON.stringify(canonicalize(value), function (k, v) { - if (typeof v === 'undefined') { - return undefinedReplacement; - } - - return v; - }, ' '); - }; - jsonDiff.equals = function (left, right) { - return (/*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/.prototype.equals.call(jsonDiff, left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1')) - ); - }; - - function diffJson(oldObj, newObj, options) { - return jsonDiff.diff(oldObj, newObj, options); - } - - // This function handles the presence of circular references by bailing out when encountering an - // object that is already on the "stack" of items being processed. - function canonicalize(obj, stack, replacementStack) { - stack = stack || []; - replacementStack = replacementStack || []; - - var i = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; - - for (i = 0; i < stack.length; i += 1) { - if (stack[i] === obj) { - return replacementStack[i]; - } - } - - var canonicalizedObj = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; - - if ('[object Array]' === objectPrototypeToString.call(obj)) { - stack.push(obj); - canonicalizedObj = new Array(obj.length); - replacementStack.push(canonicalizedObj); - for (i = 0; i < obj.length; i += 1) { - canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack); - } - stack.pop(); - replacementStack.pop(); - return canonicalizedObj; - } - - if (obj && obj.toJSON) { - obj = obj.toJSON(); - } - - if ( /*istanbul ignore start*/(typeof /*istanbul ignore end*/obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && obj !== null) { - stack.push(obj); - canonicalizedObj = {}; - replacementStack.push(canonicalizedObj); - var sortedKeys = [], - key = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; - for (key in obj) { - /* istanbul ignore else */ - if (obj.hasOwnProperty(key)) { - sortedKeys.push(key); - } - } - sortedKeys.sort(); - for (i = 0; i < sortedKeys.length; i += 1) { - key = sortedKeys[i]; - canonicalizedObj[key] = canonicalize(obj[key], stack, replacementStack); - } - stack.pop(); - replacementStack.pop(); - } else { - canonicalizedObj = obj; - } - return canonicalizedObj; - } - - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports.arrayDiff = undefined; - exports. /*istanbul ignore end*/diffArrays = diffArrays; - - var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; - - /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - - /*istanbul ignore end*/var arrayDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/arrayDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); - arrayDiff.tokenize = arrayDiff.join = function (value) { - return value.slice(); - }; - - function diffArrays(oldArr, newArr, callback) { - return arrayDiff.diff(oldArr, newArr, callback); - } - - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports. /*istanbul ignore end*/applyPatch = applyPatch; - /*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatches = applyPatches; - - var /*istanbul ignore start*/_parse = __webpack_require__(11) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_distanceIterator = __webpack_require__(12) /*istanbul ignore end*/; - - /*istanbul ignore start*/var _distanceIterator2 = _interopRequireDefault(_distanceIterator); - - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } - - /*istanbul ignore end*/function applyPatch(source, uniDiff) { - /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - - if (typeof uniDiff === 'string') { - uniDiff = /*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(uniDiff); - } - - if (Array.isArray(uniDiff)) { - if (uniDiff.length > 1) { - throw new Error('applyPatch only works with a single input.'); - } - - uniDiff = uniDiff[0]; - } - - // Apply the diff to the input - var lines = source.split(/\r\n|[\n\v\f\r\x85]/), - delimiters = source.match(/\r\n|[\n\v\f\r\x85]/g) || [], - hunks = uniDiff.hunks, - compareLine = options.compareLine || function (lineNumber, line, operation, patchContent) /*istanbul ignore start*/{ - return (/*istanbul ignore end*/line === patchContent - ); - }, - errorCount = 0, - fuzzFactor = options.fuzzFactor || 0, - minLine = 0, - offset = 0, - removeEOFNL = /*istanbul ignore start*/void 0 /*istanbul ignore end*/, - addEOFNL = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; - - /** - * Checks if the hunk exactly fits on the provided location - */ - function hunkFits(hunk, toPos) { - for (var j = 0; j < hunk.lines.length; j++) { - var line = hunk.lines[j], - operation = line[0], - content = line.substr(1); - - if (operation === ' ' || operation === '-') { - // Context sanity check - if (!compareLine(toPos + 1, lines[toPos], operation, content)) { - errorCount++; - - if (errorCount > fuzzFactor) { - return false; - } - } - toPos++; - } - } - - return true; - } - - // Search best fit offsets for each hunk based on the previous ones - for (var i = 0; i < hunks.length; i++) { - var hunk = hunks[i], - maxLine = lines.length - hunk.oldLines, - localOffset = 0, - toPos = offset + hunk.oldStart - 1; - - var iterator = /*istanbul ignore start*/(0, _distanceIterator2['default']) /*istanbul ignore end*/(toPos, minLine, maxLine); - - for (; localOffset !== undefined; localOffset = iterator()) { - if (hunkFits(hunk, toPos + localOffset)) { - hunk.offset = offset += localOffset; - break; - } - } - - if (localOffset === undefined) { - return false; - } - - // Set lower text limit to end of the current hunk, so next ones don't try - // to fit over already patched text - minLine = hunk.offset + hunk.oldStart + hunk.oldLines; - } - - // Apply patch hunks - var diffOffset = 0; - for (var _i = 0; _i < hunks.length; _i++) { - var _hunk = hunks[_i], - _toPos = _hunk.oldStart + _hunk.offset + diffOffset - 1; - diffOffset += _hunk.newLines - _hunk.oldLines; - - if (_toPos < 0) { - // Creating a new file - _toPos = 0; - } - - for (var j = 0; j < _hunk.lines.length; j++) { - var line = _hunk.lines[j], - operation = line[0], - content = line.substr(1), - delimiter = _hunk.linedelimiters[j]; - - if (operation === ' ') { - _toPos++; - } else if (operation === '-') { - lines.splice(_toPos, 1); - delimiters.splice(_toPos, 1); - /* istanbul ignore else */ - } else if (operation === '+') { - lines.splice(_toPos, 0, content); - delimiters.splice(_toPos, 0, delimiter); - _toPos++; - } else if (operation === '\\') { - var previousOperation = _hunk.lines[j - 1] ? _hunk.lines[j - 1][0] : null; - if (previousOperation === '+') { - removeEOFNL = true; - } else if (previousOperation === '-') { - addEOFNL = true; - } - } - } - } - - // Handle EOFNL insertion/removal - if (removeEOFNL) { - while (!lines[lines.length - 1]) { - lines.pop(); - delimiters.pop(); - } - } else if (addEOFNL) { - lines.push(''); - delimiters.push('\n'); - } - for (var _k = 0; _k < lines.length - 1; _k++) { - lines[_k] = lines[_k] + delimiters[_k]; - } - return lines.join(''); - } - - // Wrapper that supports multiple file patches via callbacks. - function applyPatches(uniDiff, options) { - if (typeof uniDiff === 'string') { - uniDiff = /*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(uniDiff); - } - - var currentIndex = 0; - function processIndex() { - var index = uniDiff[currentIndex++]; - if (!index) { - return options.complete(); - } - - options.loadFile(index, function (err, data) { - if (err) { - return options.complete(err); - } - - var updatedContent = applyPatch(data, index, options); - options.patched(index, updatedContent, function (err) { - if (err) { - return options.complete(err); - } - - processIndex(); - }); - }); - } - processIndex(); - } - - - -/***/ }), -/* 11 */ -/***/ (function(module, exports) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports. /*istanbul ignore end*/parsePatch = parsePatch; - function parsePatch(uniDiff) { - /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - var diffstr = uniDiff.split(/\r\n|[\n\v\f\r\x85]/), - delimiters = uniDiff.match(/\r\n|[\n\v\f\r\x85]/g) || [], - list = [], - i = 0; - - function parseIndex() { - var index = {}; - list.push(index); - - // Parse diff metadata - while (i < diffstr.length) { - var line = diffstr[i]; - - // File header found, end parsing diff metadata - if (/^(\-\-\-|\+\+\+|@@)\s/.test(line)) { - break; - } - - // Diff index - var header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line); - if (header) { - index.index = header[1]; - } - - i++; - } - - // Parse file headers if they are defined. Unified diff requires them, but - // there's no technical issues to have an isolated hunk without file header - parseFileHeader(index); - parseFileHeader(index); - - // Parse hunks - index.hunks = []; - - while (i < diffstr.length) { - var _line = diffstr[i]; - - if (/^(Index:|diff|\-\-\-|\+\+\+)\s/.test(_line)) { - break; - } else if (/^@@/.test(_line)) { - index.hunks.push(parseHunk()); - } else if (_line && options.strict) { - // Ignore unexpected content unless in strict mode - throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(_line)); - } else { - i++; - } - } - } - - // Parses the --- and +++ headers, if none are found, no lines - // are consumed. - function parseFileHeader(index) { - var headerPattern = /^(---|\+\+\+)\s+([\S ]*)(?:\t(.*?)\s*)?$/; - var fileHeader = headerPattern.exec(diffstr[i]); - if (fileHeader) { - var keyPrefix = fileHeader[1] === '---' ? 'old' : 'new'; - var fileName = fileHeader[2].replace(/\\\\/g, '\\'); - if (/^".*"$/.test(fileName)) { - fileName = fileName.substr(1, fileName.length - 2); - } - index[keyPrefix + 'FileName'] = fileName; - index[keyPrefix + 'Header'] = fileHeader[3]; - - i++; - } - } - - // Parses a hunk - // This assumes that we are at the start of a hunk. - function parseHunk() { - var chunkHeaderIndex = i, - chunkHeaderLine = diffstr[i++], - chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/); - - var hunk = { - oldStart: +chunkHeader[1], - oldLines: +chunkHeader[2] || 1, - newStart: +chunkHeader[3], - newLines: +chunkHeader[4] || 1, - lines: [], - linedelimiters: [] - }; - - var addCount = 0, - removeCount = 0; - for (; i < diffstr.length; i++) { - // Lines starting with '---' could be mistaken for the "remove line" operation - // But they could be the header for the next file. Therefore prune such cases out. - if (diffstr[i].indexOf('--- ') === 0 && i + 2 < diffstr.length && diffstr[i + 1].indexOf('+++ ') === 0 && diffstr[i + 2].indexOf('@@') === 0) { - break; - } - var operation = diffstr[i][0]; - - if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') { - hunk.lines.push(diffstr[i]); - hunk.linedelimiters.push(delimiters[i] || '\n'); - - if (operation === '+') { - addCount++; - } else if (operation === '-') { - removeCount++; - } else if (operation === ' ') { - addCount++; - removeCount++; - } - } else { - break; - } - } - - // Handle the empty block count case - if (!addCount && hunk.newLines === 1) { - hunk.newLines = 0; - } - if (!removeCount && hunk.oldLines === 1) { - hunk.oldLines = 0; - } - - // Perform optional sanity checking - if (options.strict) { - if (addCount !== hunk.newLines) { - throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1)); - } - if (removeCount !== hunk.oldLines) { - throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1)); - } - } - - return hunk; - } - - while (i < diffstr.length) { - parseIndex(); - } - - return list; - } - - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - - /*istanbul ignore start*/"use strict"; - - exports.__esModule = true; - - exports["default"] = /*istanbul ignore end*/function (start, minLine, maxLine) { - var wantForward = true, - backwardExhausted = false, - forwardExhausted = false, - localOffset = 1; - - return function iterator() { - if (wantForward && !forwardExhausted) { - if (backwardExhausted) { - localOffset++; - } else { - wantForward = false; - } - - // Check if trying to fit beyond text length, and if not, check it fits - // after offset location (or desired location on first iteration) - if (start + localOffset <= maxLine) { - return localOffset; - } - - forwardExhausted = true; - } - - if (!backwardExhausted) { - if (!forwardExhausted) { - wantForward = true; - } - - // Check if trying to fit before text beginning, and if not, check it fits - // before offset location - if (minLine <= start - localOffset) { - return -localOffset++; - } - - backwardExhausted = true; - return iterator(); - } - - // We tried to fit hunk before text beginning and beyond text length, then - // hunk can't fit on the text. Return undefined - }; - }; - - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports. /*istanbul ignore end*/calcLineCount = calcLineCount; - /*istanbul ignore start*/exports. /*istanbul ignore end*/merge = merge; - - var /*istanbul ignore start*/_create = __webpack_require__(14) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_parse = __webpack_require__(11) /*istanbul ignore end*/; - - var /*istanbul ignore start*/_array = __webpack_require__(15) /*istanbul ignore end*/; - - /*istanbul ignore start*/function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - - /*istanbul ignore end*/function calcLineCount(hunk) { - var conflicted = false; - - hunk.oldLines = 0; - hunk.newLines = 0; - - hunk.lines.forEach(function (line) { - if (typeof line !== 'string') { - conflicted = true; - return; - } - - if (line[0] === '+' || line[0] === ' ') { - hunk.newLines++; - } - if (line[0] === '-' || line[0] === ' ') { - hunk.oldLines++; - } - }); - - if (conflicted) { - delete hunk.oldLines; - delete hunk.newLines; - } - } - - function merge(mine, theirs, base) { - mine = loadPatch(mine, base); - theirs = loadPatch(theirs, base); - - var ret = {}; - - // For index we just let it pass through as it doesn't have any necessary meaning. - // Leaving sanity checks on this to the API consumer that may know more about the - // meaning in their own context. - if (mine.index || theirs.index) { - ret.index = mine.index || theirs.index; - } - - if (mine.newFileName || theirs.newFileName) { - if (!fileNameChanged(mine)) { - // No header or no change in ours, use theirs (and ours if theirs does not exist) - ret.oldFileName = theirs.oldFileName || mine.oldFileName; - ret.newFileName = theirs.newFileName || mine.newFileName; - ret.oldHeader = theirs.oldHeader || mine.oldHeader; - ret.newHeader = theirs.newHeader || mine.newHeader; - } else if (!fileNameChanged(theirs)) { - // No header or no change in theirs, use ours - ret.oldFileName = mine.oldFileName; - ret.newFileName = mine.newFileName; - ret.oldHeader = mine.oldHeader; - ret.newHeader = mine.newHeader; - } else { - // Both changed... figure it out - ret.oldFileName = selectField(ret, mine.oldFileName, theirs.oldFileName); - ret.newFileName = selectField(ret, mine.newFileName, theirs.newFileName); - ret.oldHeader = selectField(ret, mine.oldHeader, theirs.oldHeader); - ret.newHeader = selectField(ret, mine.newHeader, theirs.newHeader); - } - } - - ret.hunks = []; - - var mineIndex = 0, - theirsIndex = 0, - mineOffset = 0, - theirsOffset = 0; - - while (mineIndex < mine.hunks.length || theirsIndex < theirs.hunks.length) { - var mineCurrent = mine.hunks[mineIndex] || { oldStart: Infinity }, - theirsCurrent = theirs.hunks[theirsIndex] || { oldStart: Infinity }; - - if (hunkBefore(mineCurrent, theirsCurrent)) { - // This patch does not overlap with any of the others, yay. - ret.hunks.push(cloneHunk(mineCurrent, mineOffset)); - mineIndex++; - theirsOffset += mineCurrent.newLines - mineCurrent.oldLines; - } else if (hunkBefore(theirsCurrent, mineCurrent)) { - // This patch does not overlap with any of the others, yay. - ret.hunks.push(cloneHunk(theirsCurrent, theirsOffset)); - theirsIndex++; - mineOffset += theirsCurrent.newLines - theirsCurrent.oldLines; - } else { - // Overlap, merge as best we can - var mergedHunk = { - oldStart: Math.min(mineCurrent.oldStart, theirsCurrent.oldStart), - oldLines: 0, - newStart: Math.min(mineCurrent.newStart + mineOffset, theirsCurrent.oldStart + theirsOffset), - newLines: 0, - lines: [] - }; - mergeLines(mergedHunk, mineCurrent.oldStart, mineCurrent.lines, theirsCurrent.oldStart, theirsCurrent.lines); - theirsIndex++; - mineIndex++; - - ret.hunks.push(mergedHunk); - } - } - - return ret; - } - - function loadPatch(param, base) { - if (typeof param === 'string') { - if (/^@@/m.test(param) || /^Index:/m.test(param)) { - return (/*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(param)[0] - ); - } - - if (!base) { - throw new Error('Must provide a base reference or pass in a patch'); - } - return (/*istanbul ignore start*/(0, _create.structuredPatch) /*istanbul ignore end*/(undefined, undefined, base, param) - ); - } - - return param; - } - - function fileNameChanged(patch) { - return patch.newFileName && patch.newFileName !== patch.oldFileName; - } - - function selectField(index, mine, theirs) { - if (mine === theirs) { - return mine; - } else { - index.conflict = true; - return { mine: mine, theirs: theirs }; - } - } - - function hunkBefore(test, check) { - return test.oldStart < check.oldStart && test.oldStart + test.oldLines < check.oldStart; - } - - function cloneHunk(hunk, offset) { - return { - oldStart: hunk.oldStart, oldLines: hunk.oldLines, - newStart: hunk.newStart + offset, newLines: hunk.newLines, - lines: hunk.lines - }; - } - - function mergeLines(hunk, mineOffset, mineLines, theirOffset, theirLines) { - // This will generally result in a conflicted hunk, but there are cases where the context - // is the only overlap where we can successfully merge the content here. - var mine = { offset: mineOffset, lines: mineLines, index: 0 }, - their = { offset: theirOffset, lines: theirLines, index: 0 }; - - // Handle any leading content - insertLeading(hunk, mine, their); - insertLeading(hunk, their, mine); - - // Now in the overlap content. Scan through and select the best changes from each. - while (mine.index < mine.lines.length && their.index < their.lines.length) { - var mineCurrent = mine.lines[mine.index], - theirCurrent = their.lines[their.index]; - - if ((mineCurrent[0] === '-' || mineCurrent[0] === '+') && (theirCurrent[0] === '-' || theirCurrent[0] === '+')) { - // Both modified ... - mutualChange(hunk, mine, their); - } else if (mineCurrent[0] === '+' && theirCurrent[0] === ' ') { - /*istanbul ignore start*/var _hunk$lines; - - /*istanbul ignore end*/ // Mine inserted - /*istanbul ignore start*/(_hunk$lines = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/collectChange(mine))); - } else if (theirCurrent[0] === '+' && mineCurrent[0] === ' ') { - /*istanbul ignore start*/var _hunk$lines2; - - /*istanbul ignore end*/ // Theirs inserted - /*istanbul ignore start*/(_hunk$lines2 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines2 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/collectChange(their))); - } else if (mineCurrent[0] === '-' && theirCurrent[0] === ' ') { - // Mine removed or edited - removal(hunk, mine, their); - } else if (theirCurrent[0] === '-' && mineCurrent[0] === ' ') { - // Their removed or edited - removal(hunk, their, mine, true); - } else if (mineCurrent === theirCurrent) { - // Context identity - hunk.lines.push(mineCurrent); - mine.index++; - their.index++; - } else { - // Context mismatch - conflict(hunk, collectChange(mine), collectChange(their)); - } - } - - // Now push anything that may be remaining - insertTrailing(hunk, mine); - insertTrailing(hunk, their); - - calcLineCount(hunk); - } - - function mutualChange(hunk, mine, their) { - var myChanges = collectChange(mine), - theirChanges = collectChange(their); - - if (allRemoves(myChanges) && allRemoves(theirChanges)) { - // Special case for remove changes that are supersets of one another - if ( /*istanbul ignore start*/(0, _array.arrayStartsWith) /*istanbul ignore end*/(myChanges, theirChanges) && skipRemoveSuperset(their, myChanges, myChanges.length - theirChanges.length)) { - /*istanbul ignore start*/var _hunk$lines3; - - /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines3 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines3 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/myChanges)); - return; - } else if ( /*istanbul ignore start*/(0, _array.arrayStartsWith) /*istanbul ignore end*/(theirChanges, myChanges) && skipRemoveSuperset(mine, theirChanges, theirChanges.length - myChanges.length)) { - /*istanbul ignore start*/var _hunk$lines4; - - /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines4 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines4 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/theirChanges)); - return; - } - } else if ( /*istanbul ignore start*/(0, _array.arrayEqual) /*istanbul ignore end*/(myChanges, theirChanges)) { - /*istanbul ignore start*/var _hunk$lines5; - - /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines5 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines5 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/myChanges)); - return; - } - - conflict(hunk, myChanges, theirChanges); - } - - function removal(hunk, mine, their, swap) { - var myChanges = collectChange(mine), - theirChanges = collectContext(their, myChanges); - if (theirChanges.merged) { - /*istanbul ignore start*/var _hunk$lines6; - - /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines6 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines6 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/theirChanges.merged)); - } else { - conflict(hunk, swap ? theirChanges : myChanges, swap ? myChanges : theirChanges); - } - } - - function conflict(hunk, mine, their) { - hunk.conflict = true; - hunk.lines.push({ - conflict: true, - mine: mine, - theirs: their - }); - } - - function insertLeading(hunk, insert, their) { - while (insert.offset < their.offset && insert.index < insert.lines.length) { - var line = insert.lines[insert.index++]; - hunk.lines.push(line); - insert.offset++; - } - } - function insertTrailing(hunk, insert) { - while (insert.index < insert.lines.length) { - var line = insert.lines[insert.index++]; - hunk.lines.push(line); - } - } - - function collectChange(state) { - var ret = [], - operation = state.lines[state.index][0]; - while (state.index < state.lines.length) { - var line = state.lines[state.index]; - - // Group additions that are immediately after subtractions and treat them as one "atomic" modify change. - if (operation === '-' && line[0] === '+') { - operation = '+'; - } - - if (operation === line[0]) { - ret.push(line); - state.index++; - } else { - break; - } - } - - return ret; - } - function collectContext(state, matchChanges) { - var changes = [], - merged = [], - matchIndex = 0, - contextChanges = false, - conflicted = false; - while (matchIndex < matchChanges.length && state.index < state.lines.length) { - var change = state.lines[state.index], - match = matchChanges[matchIndex]; - - // Once we've hit our add, then we are done - if (match[0] === '+') { - break; - } - - contextChanges = contextChanges || change[0] !== ' '; - - merged.push(match); - matchIndex++; - - // Consume any additions in the other block as a conflict to attempt - // to pull in the remaining context after this - if (change[0] === '+') { - conflicted = true; - - while (change[0] === '+') { - changes.push(change); - change = state.lines[++state.index]; - } - } - - if (match.substr(1) === change.substr(1)) { - changes.push(change); - state.index++; - } else { - conflicted = true; - } - } - - if ((matchChanges[matchIndex] || '')[0] === '+' && contextChanges) { - conflicted = true; - } - - if (conflicted) { - return changes; - } - - while (matchIndex < matchChanges.length) { - merged.push(matchChanges[matchIndex++]); - } - - return { - merged: merged, - changes: changes - }; - } - - function allRemoves(changes) { - return changes.reduce(function (prev, change) { - return prev && change[0] === '-'; - }, true); - } - function skipRemoveSuperset(state, removeChanges, delta) { - for (var i = 0; i < delta; i++) { - var changeContent = removeChanges[removeChanges.length - delta + i].substr(1); - if (state.lines[state.index + i] !== ' ' + changeContent) { - return false; - } - } - - state.index += delta; - return true; - } - - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports. /*istanbul ignore end*/structuredPatch = structuredPatch; - /*istanbul ignore start*/exports. /*istanbul ignore end*/createTwoFilesPatch = createTwoFilesPatch; - /*istanbul ignore start*/exports. /*istanbul ignore end*/createPatch = createPatch; - - var /*istanbul ignore start*/_line = __webpack_require__(5) /*istanbul ignore end*/; - - /*istanbul ignore start*/function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - - /*istanbul ignore end*/function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { - if (!options) { - options = {}; - } - if (typeof options.context === 'undefined') { - options.context = 4; - } - - var diff = /*istanbul ignore start*/(0, _line.diffLines) /*istanbul ignore end*/(oldStr, newStr, options); - diff.push({ value: '', lines: [] }); // Append an empty value to make cleanup easier - - function contextLines(lines) { - return lines.map(function (entry) { - return ' ' + entry; - }); - } - - var hunks = []; - var oldRangeStart = 0, - newRangeStart = 0, - curRange = [], - oldLine = 1, - newLine = 1; - - /*istanbul ignore start*/var _loop = function _loop( /*istanbul ignore end*/i) { - var current = diff[i], - lines = current.lines || current.value.replace(/\n$/, '').split('\n'); - current.lines = lines; - - if (current.added || current.removed) { - /*istanbul ignore start*/var _curRange; - - /*istanbul ignore end*/ // If we have previous context, start with that - if (!oldRangeStart) { - var prev = diff[i - 1]; - oldRangeStart = oldLine; - newRangeStart = newLine; - - if (prev) { - curRange = options.context > 0 ? contextLines(prev.lines.slice(-options.context)) : []; - oldRangeStart -= curRange.length; - newRangeStart -= curRange.length; - } - } - - // Output our changes - /*istanbul ignore start*/(_curRange = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/lines.map(function (entry) { - return (current.added ? '+' : '-') + entry; - }))); - - // Track the updated file position - if (current.added) { - newLine += lines.length; - } else { - oldLine += lines.length; - } - } else { - // Identical context lines. Track line changes - if (oldRangeStart) { - // Close out any changes that have been output (or join overlapping) - if (lines.length <= options.context * 2 && i < diff.length - 2) { - /*istanbul ignore start*/var _curRange2; - - /*istanbul ignore end*/ // Overlapping - /*istanbul ignore start*/(_curRange2 = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange2 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/contextLines(lines))); - } else { - /*istanbul ignore start*/var _curRange3; - - /*istanbul ignore end*/ // end the range and output - var contextSize = Math.min(lines.length, options.context); - /*istanbul ignore start*/(_curRange3 = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange3 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/contextLines(lines.slice(0, contextSize)))); - - var hunk = { - oldStart: oldRangeStart, - oldLines: oldLine - oldRangeStart + contextSize, - newStart: newRangeStart, - newLines: newLine - newRangeStart + contextSize, - lines: curRange - }; - if (i >= diff.length - 2 && lines.length <= options.context) { - // EOF is inside this hunk - var oldEOFNewline = /\n$/.test(oldStr); - var newEOFNewline = /\n$/.test(newStr); - if (lines.length == 0 && !oldEOFNewline) { - // special case: old has no eol and no trailing context; no-nl can end up before adds - curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file'); - } else if (!oldEOFNewline || !newEOFNewline) { - curRange.push('\\ No newline at end of file'); - } - } - hunks.push(hunk); - - oldRangeStart = 0; - newRangeStart = 0; - curRange = []; - } - } - oldLine += lines.length; - newLine += lines.length; - } - }; - - for (var i = 0; i < diff.length; i++) { - /*istanbul ignore start*/_loop( /*istanbul ignore end*/i); - } - - return { - oldFileName: oldFileName, newFileName: newFileName, - oldHeader: oldHeader, newHeader: newHeader, - hunks: hunks - }; - } - - function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { - var diff = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options); - - var ret = []; - if (oldFileName == newFileName) { - ret.push('Index: ' + oldFileName); - } - ret.push('==================================================================='); - ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader)); - ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader)); - - for (var i = 0; i < diff.hunks.length; i++) { - var hunk = diff.hunks[i]; - ret.push('@@ -' + hunk.oldStart + ',' + hunk.oldLines + ' +' + hunk.newStart + ',' + hunk.newLines + ' @@'); - ret.push.apply(ret, hunk.lines); - } - - return ret.join('\n') + '\n'; - } - - function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) { - return createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options); - } - - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - - /*istanbul ignore start*/"use strict"; - - exports.__esModule = true; - exports. /*istanbul ignore end*/arrayEqual = arrayEqual; - /*istanbul ignore start*/exports. /*istanbul ignore end*/arrayStartsWith = arrayStartsWith; - function arrayEqual(a, b) { - if (a.length !== b.length) { - return false; - } - - return arrayStartsWith(a, b); - } - - function arrayStartsWith(array, start) { - if (start.length > array.length) { - return false; - } - - for (var i = 0; i < start.length; i++) { - if (start[i] !== array[i]) { - return false; - } - } - - return true; - } - - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - - /*istanbul ignore start*/"use strict"; - - exports.__esModule = true; - exports. /*istanbul ignore end*/convertChangesToDMP = convertChangesToDMP; - // See: http://code.google.com/p/google-diff-match-patch/wiki/API - function convertChangesToDMP(changes) { - var ret = [], - change = /*istanbul ignore start*/void 0 /*istanbul ignore end*/, - operation = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; - for (var i = 0; i < changes.length; i++) { - change = changes[i]; - if (change.added) { - operation = 1; - } else if (change.removed) { - operation = -1; - } else { - operation = 0; - } - - ret.push([operation, change.value]); - } - return ret; - } - - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - - /*istanbul ignore start*/'use strict'; - - exports.__esModule = true; - exports. /*istanbul ignore end*/convertChangesToXML = convertChangesToXML; - function convertChangesToXML(changes) { - var ret = []; - for (var i = 0; i < changes.length; i++) { - var change = changes[i]; - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - - ret.push(escapeHTML(change.value)); - - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - } - return ret.join(''); - } - - function escapeHTML(s) { - var n = s; - n = n.replace(/&/g, '&'); - n = n.replace(//g, '>'); - n = n.replace(/"/g, '"'); - - return n; - } - - - -/***/ }) -/******/ ]) -}); -; -},{}],45:[function(require,module,exports){ -'use strict'; - -var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; - -module.exports = function (str) { - if (typeof str !== 'string') { - throw new TypeError('Expected a string'); - } - - return str.replace(matchOperatorsRe, '\\$&'); -}; - -},{}],46:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } else { - // At least give some kind of context to the user - var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); - err.context = er; - throw err; - } - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - } else if (isObject(handler)) { - args = Array.prototype.slice.call(arguments, 1); - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - - if (isFunction(evlistener)) - return 1; - else if (evlistener) - return evlistener.length; - } - return 0; -}; - -EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); -}; - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isUndefined(arg) { - return arg === void 0; -} - -},{}],47:[function(require,module,exports){ -(function (global){ -/*! https://mths.be/he v1.1.1 by @mathias | MIT license */ -;(function(root) { - - // Detect free variables `exports`. - var freeExports = typeof exports == 'object' && exports; - - // Detect free variable `module`. - var freeModule = typeof module == 'object' && module && - module.exports == freeExports && module; - - // Detect free variable `global`, from Node.js or Browserified code, - // and use it as `root`. - var freeGlobal = typeof global == 'object' && global; - if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { - root = freeGlobal; - } - - /*--------------------------------------------------------------------------*/ - - // All astral symbols. - var regexAstralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; - // All ASCII symbols (not just printable ASCII) except those listed in the - // first column of the overrides table. - // https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides - var regexAsciiWhitelist = /[\x01-\x7F]/g; - // All BMP symbols that are not ASCII newlines, printable ASCII symbols, or - // code points listed in the first column of the overrides table on - // https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides. - var regexBmpWhitelist = /[\x01-\t\x0B\f\x0E-\x1F\x7F\x81\x8D\x8F\x90\x9D\xA0-\uFFFF]/g; - - var regexEncodeNonAscii = /<\u20D2|=\u20E5|>\u20D2|\u205F\u200A|\u219D\u0338|\u2202\u0338|\u2220\u20D2|\u2229\uFE00|\u222A\uFE00|\u223C\u20D2|\u223D\u0331|\u223E\u0333|\u2242\u0338|\u224B\u0338|\u224D\u20D2|\u224E\u0338|\u224F\u0338|\u2250\u0338|\u2261\u20E5|\u2264\u20D2|\u2265\u20D2|\u2266\u0338|\u2267\u0338|\u2268\uFE00|\u2269\uFE00|\u226A\u0338|\u226A\u20D2|\u226B\u0338|\u226B\u20D2|\u227F\u0338|\u2282\u20D2|\u2283\u20D2|\u228A\uFE00|\u228B\uFE00|\u228F\u0338|\u2290\u0338|\u2293\uFE00|\u2294\uFE00|\u22B4\u20D2|\u22B5\u20D2|\u22D8\u0338|\u22D9\u0338|\u22DA\uFE00|\u22DB\uFE00|\u22F5\u0338|\u22F9\u0338|\u2933\u0338|\u29CF\u0338|\u29D0\u0338|\u2A6D\u0338|\u2A70\u0338|\u2A7D\u0338|\u2A7E\u0338|\u2AA1\u0338|\u2AA2\u0338|\u2AAC\uFE00|\u2AAD\uFE00|\u2AAF\u0338|\u2AB0\u0338|\u2AC5\u0338|\u2AC6\u0338|\u2ACB\uFE00|\u2ACC\uFE00|\u2AFD\u20E5|[\xA0-\u0113\u0116-\u0122\u0124-\u012B\u012E-\u014D\u0150-\u017E\u0192\u01B5\u01F5\u0237\u02C6\u02C7\u02D8-\u02DD\u0311\u0391-\u03A1\u03A3-\u03A9\u03B1-\u03C9\u03D1\u03D2\u03D5\u03D6\u03DC\u03DD\u03F0\u03F1\u03F5\u03F6\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E\u045F\u2002-\u2005\u2007-\u2010\u2013-\u2016\u2018-\u201A\u201C-\u201E\u2020-\u2022\u2025\u2026\u2030-\u2035\u2039\u203A\u203E\u2041\u2043\u2044\u204F\u2057\u205F-\u2063\u20AC\u20DB\u20DC\u2102\u2105\u210A-\u2113\u2115-\u211E\u2122\u2124\u2127-\u2129\u212C\u212D\u212F-\u2131\u2133-\u2138\u2145-\u2148\u2153-\u215E\u2190-\u219B\u219D-\u21A7\u21A9-\u21AE\u21B0-\u21B3\u21B5-\u21B7\u21BA-\u21DB\u21DD\u21E4\u21E5\u21F5\u21FD-\u2205\u2207-\u2209\u220B\u220C\u220F-\u2214\u2216-\u2218\u221A\u221D-\u2238\u223A-\u2257\u2259\u225A\u225C\u225F-\u2262\u2264-\u228B\u228D-\u229B\u229D-\u22A5\u22A7-\u22B0\u22B2-\u22BB\u22BD-\u22DB\u22DE-\u22E3\u22E6-\u22F7\u22F9-\u22FE\u2305\u2306\u2308-\u2310\u2312\u2313\u2315\u2316\u231C-\u231F\u2322\u2323\u232D\u232E\u2336\u233D\u233F\u237C\u23B0\u23B1\u23B4-\u23B6\u23DC-\u23DF\u23E2\u23E7\u2423\u24C8\u2500\u2502\u250C\u2510\u2514\u2518\u251C\u2524\u252C\u2534\u253C\u2550-\u256C\u2580\u2584\u2588\u2591-\u2593\u25A1\u25AA\u25AB\u25AD\u25AE\u25B1\u25B3-\u25B5\u25B8\u25B9\u25BD-\u25BF\u25C2\u25C3\u25CA\u25CB\u25EC\u25EF\u25F8-\u25FC\u2605\u2606\u260E\u2640\u2642\u2660\u2663\u2665\u2666\u266A\u266D-\u266F\u2713\u2717\u2720\u2736\u2758\u2772\u2773\u27C8\u27C9\u27E6-\u27ED\u27F5-\u27FA\u27FC\u27FF\u2902-\u2905\u290C-\u2913\u2916\u2919-\u2920\u2923-\u292A\u2933\u2935-\u2939\u293C\u293D\u2945\u2948-\u294B\u294E-\u2976\u2978\u2979\u297B-\u297F\u2985\u2986\u298B-\u2996\u299A\u299C\u299D\u29A4-\u29B7\u29B9\u29BB\u29BC\u29BE-\u29C5\u29C9\u29CD-\u29D0\u29DC-\u29DE\u29E3-\u29E5\u29EB\u29F4\u29F6\u2A00-\u2A02\u2A04\u2A06\u2A0C\u2A0D\u2A10-\u2A17\u2A22-\u2A27\u2A29\u2A2A\u2A2D-\u2A31\u2A33-\u2A3C\u2A3F\u2A40\u2A42-\u2A4D\u2A50\u2A53-\u2A58\u2A5A-\u2A5D\u2A5F\u2A66\u2A6A\u2A6D-\u2A75\u2A77-\u2A9A\u2A9D-\u2AA2\u2AA4-\u2AB0\u2AB3-\u2AC8\u2ACB\u2ACC\u2ACF-\u2ADB\u2AE4\u2AE6-\u2AE9\u2AEB-\u2AF3\u2AFD\uFB00-\uFB04]|\uD835[\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDCCF\uDD04\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDD6B]/g; - var encodeMap = {'\xAD':'shy','\u200C':'zwnj','\u200D':'zwj','\u200E':'lrm','\u2063':'ic','\u2062':'it','\u2061':'af','\u200F':'rlm','\u200B':'ZeroWidthSpace','\u2060':'NoBreak','\u0311':'DownBreve','\u20DB':'tdot','\u20DC':'DotDot','\t':'Tab','\n':'NewLine','\u2008':'puncsp','\u205F':'MediumSpace','\u2009':'thinsp','\u200A':'hairsp','\u2004':'emsp13','\u2002':'ensp','\u2005':'emsp14','\u2003':'emsp','\u2007':'numsp','\xA0':'nbsp','\u205F\u200A':'ThickSpace','\u203E':'oline','_':'lowbar','\u2010':'dash','\u2013':'ndash','\u2014':'mdash','\u2015':'horbar',',':'comma',';':'semi','\u204F':'bsemi',':':'colon','\u2A74':'Colone','!':'excl','\xA1':'iexcl','?':'quest','\xBF':'iquest','.':'period','\u2025':'nldr','\u2026':'mldr','\xB7':'middot','\'':'apos','\u2018':'lsquo','\u2019':'rsquo','\u201A':'sbquo','\u2039':'lsaquo','\u203A':'rsaquo','"':'quot','\u201C':'ldquo','\u201D':'rdquo','\u201E':'bdquo','\xAB':'laquo','\xBB':'raquo','(':'lpar',')':'rpar','[':'lsqb',']':'rsqb','{':'lcub','}':'rcub','\u2308':'lceil','\u2309':'rceil','\u230A':'lfloor','\u230B':'rfloor','\u2985':'lopar','\u2986':'ropar','\u298B':'lbrke','\u298C':'rbrke','\u298D':'lbrkslu','\u298E':'rbrksld','\u298F':'lbrksld','\u2990':'rbrkslu','\u2991':'langd','\u2992':'rangd','\u2993':'lparlt','\u2994':'rpargt','\u2995':'gtlPar','\u2996':'ltrPar','\u27E6':'lobrk','\u27E7':'robrk','\u27E8':'lang','\u27E9':'rang','\u27EA':'Lang','\u27EB':'Rang','\u27EC':'loang','\u27ED':'roang','\u2772':'lbbrk','\u2773':'rbbrk','\u2016':'Vert','\xA7':'sect','\xB6':'para','@':'commat','*':'ast','/':'sol','undefined':null,'&':'amp','#':'num','%':'percnt','\u2030':'permil','\u2031':'pertenk','\u2020':'dagger','\u2021':'Dagger','\u2022':'bull','\u2043':'hybull','\u2032':'prime','\u2033':'Prime','\u2034':'tprime','\u2057':'qprime','\u2035':'bprime','\u2041':'caret','`':'grave','\xB4':'acute','\u02DC':'tilde','^':'Hat','\xAF':'macr','\u02D8':'breve','\u02D9':'dot','\xA8':'die','\u02DA':'ring','\u02DD':'dblac','\xB8':'cedil','\u02DB':'ogon','\u02C6':'circ','\u02C7':'caron','\xB0':'deg','\xA9':'copy','\xAE':'reg','\u2117':'copysr','\u2118':'wp','\u211E':'rx','\u2127':'mho','\u2129':'iiota','\u2190':'larr','\u219A':'nlarr','\u2192':'rarr','\u219B':'nrarr','\u2191':'uarr','\u2193':'darr','\u2194':'harr','\u21AE':'nharr','\u2195':'varr','\u2196':'nwarr','\u2197':'nearr','\u2198':'searr','\u2199':'swarr','\u219D':'rarrw','\u219D\u0338':'nrarrw','\u219E':'Larr','\u219F':'Uarr','\u21A0':'Rarr','\u21A1':'Darr','\u21A2':'larrtl','\u21A3':'rarrtl','\u21A4':'mapstoleft','\u21A5':'mapstoup','\u21A6':'map','\u21A7':'mapstodown','\u21A9':'larrhk','\u21AA':'rarrhk','\u21AB':'larrlp','\u21AC':'rarrlp','\u21AD':'harrw','\u21B0':'lsh','\u21B1':'rsh','\u21B2':'ldsh','\u21B3':'rdsh','\u21B5':'crarr','\u21B6':'cularr','\u21B7':'curarr','\u21BA':'olarr','\u21BB':'orarr','\u21BC':'lharu','\u21BD':'lhard','\u21BE':'uharr','\u21BF':'uharl','\u21C0':'rharu','\u21C1':'rhard','\u21C2':'dharr','\u21C3':'dharl','\u21C4':'rlarr','\u21C5':'udarr','\u21C6':'lrarr','\u21C7':'llarr','\u21C8':'uuarr','\u21C9':'rrarr','\u21CA':'ddarr','\u21CB':'lrhar','\u21CC':'rlhar','\u21D0':'lArr','\u21CD':'nlArr','\u21D1':'uArr','\u21D2':'rArr','\u21CF':'nrArr','\u21D3':'dArr','\u21D4':'iff','\u21CE':'nhArr','\u21D5':'vArr','\u21D6':'nwArr','\u21D7':'neArr','\u21D8':'seArr','\u21D9':'swArr','\u21DA':'lAarr','\u21DB':'rAarr','\u21DD':'zigrarr','\u21E4':'larrb','\u21E5':'rarrb','\u21F5':'duarr','\u21FD':'loarr','\u21FE':'roarr','\u21FF':'hoarr','\u2200':'forall','\u2201':'comp','\u2202':'part','\u2202\u0338':'npart','\u2203':'exist','\u2204':'nexist','\u2205':'empty','\u2207':'Del','\u2208':'in','\u2209':'notin','\u220B':'ni','\u220C':'notni','\u03F6':'bepsi','\u220F':'prod','\u2210':'coprod','\u2211':'sum','+':'plus','\xB1':'pm','\xF7':'div','\xD7':'times','<':'lt','\u226E':'nlt','<\u20D2':'nvlt','=':'equals','\u2260':'ne','=\u20E5':'bne','\u2A75':'Equal','>':'gt','\u226F':'ngt','>\u20D2':'nvgt','\xAC':'not','|':'vert','\xA6':'brvbar','\u2212':'minus','\u2213':'mp','\u2214':'plusdo','\u2044':'frasl','\u2216':'setmn','\u2217':'lowast','\u2218':'compfn','\u221A':'Sqrt','\u221D':'prop','\u221E':'infin','\u221F':'angrt','\u2220':'ang','\u2220\u20D2':'nang','\u2221':'angmsd','\u2222':'angsph','\u2223':'mid','\u2224':'nmid','\u2225':'par','\u2226':'npar','\u2227':'and','\u2228':'or','\u2229':'cap','\u2229\uFE00':'caps','\u222A':'cup','\u222A\uFE00':'cups','\u222B':'int','\u222C':'Int','\u222D':'tint','\u2A0C':'qint','\u222E':'oint','\u222F':'Conint','\u2230':'Cconint','\u2231':'cwint','\u2232':'cwconint','\u2233':'awconint','\u2234':'there4','\u2235':'becaus','\u2236':'ratio','\u2237':'Colon','\u2238':'minusd','\u223A':'mDDot','\u223B':'homtht','\u223C':'sim','\u2241':'nsim','\u223C\u20D2':'nvsim','\u223D':'bsim','\u223D\u0331':'race','\u223E':'ac','\u223E\u0333':'acE','\u223F':'acd','\u2240':'wr','\u2242':'esim','\u2242\u0338':'nesim','\u2243':'sime','\u2244':'nsime','\u2245':'cong','\u2247':'ncong','\u2246':'simne','\u2248':'ap','\u2249':'nap','\u224A':'ape','\u224B':'apid','\u224B\u0338':'napid','\u224C':'bcong','\u224D':'CupCap','\u226D':'NotCupCap','\u224D\u20D2':'nvap','\u224E':'bump','\u224E\u0338':'nbump','\u224F':'bumpe','\u224F\u0338':'nbumpe','\u2250':'doteq','\u2250\u0338':'nedot','\u2251':'eDot','\u2252':'efDot','\u2253':'erDot','\u2254':'colone','\u2255':'ecolon','\u2256':'ecir','\u2257':'cire','\u2259':'wedgeq','\u225A':'veeeq','\u225C':'trie','\u225F':'equest','\u2261':'equiv','\u2262':'nequiv','\u2261\u20E5':'bnequiv','\u2264':'le','\u2270':'nle','\u2264\u20D2':'nvle','\u2265':'ge','\u2271':'nge','\u2265\u20D2':'nvge','\u2266':'lE','\u2266\u0338':'nlE','\u2267':'gE','\u2267\u0338':'ngE','\u2268\uFE00':'lvnE','\u2268':'lnE','\u2269':'gnE','\u2269\uFE00':'gvnE','\u226A':'ll','\u226A\u0338':'nLtv','\u226A\u20D2':'nLt','\u226B':'gg','\u226B\u0338':'nGtv','\u226B\u20D2':'nGt','\u226C':'twixt','\u2272':'lsim','\u2274':'nlsim','\u2273':'gsim','\u2275':'ngsim','\u2276':'lg','\u2278':'ntlg','\u2277':'gl','\u2279':'ntgl','\u227A':'pr','\u2280':'npr','\u227B':'sc','\u2281':'nsc','\u227C':'prcue','\u22E0':'nprcue','\u227D':'sccue','\u22E1':'nsccue','\u227E':'prsim','\u227F':'scsim','\u227F\u0338':'NotSucceedsTilde','\u2282':'sub','\u2284':'nsub','\u2282\u20D2':'vnsub','\u2283':'sup','\u2285':'nsup','\u2283\u20D2':'vnsup','\u2286':'sube','\u2288':'nsube','\u2287':'supe','\u2289':'nsupe','\u228A\uFE00':'vsubne','\u228A':'subne','\u228B\uFE00':'vsupne','\u228B':'supne','\u228D':'cupdot','\u228E':'uplus','\u228F':'sqsub','\u228F\u0338':'NotSquareSubset','\u2290':'sqsup','\u2290\u0338':'NotSquareSuperset','\u2291':'sqsube','\u22E2':'nsqsube','\u2292':'sqsupe','\u22E3':'nsqsupe','\u2293':'sqcap','\u2293\uFE00':'sqcaps','\u2294':'sqcup','\u2294\uFE00':'sqcups','\u2295':'oplus','\u2296':'ominus','\u2297':'otimes','\u2298':'osol','\u2299':'odot','\u229A':'ocir','\u229B':'oast','\u229D':'odash','\u229E':'plusb','\u229F':'minusb','\u22A0':'timesb','\u22A1':'sdotb','\u22A2':'vdash','\u22AC':'nvdash','\u22A3':'dashv','\u22A4':'top','\u22A5':'bot','\u22A7':'models','\u22A8':'vDash','\u22AD':'nvDash','\u22A9':'Vdash','\u22AE':'nVdash','\u22AA':'Vvdash','\u22AB':'VDash','\u22AF':'nVDash','\u22B0':'prurel','\u22B2':'vltri','\u22EA':'nltri','\u22B3':'vrtri','\u22EB':'nrtri','\u22B4':'ltrie','\u22EC':'nltrie','\u22B4\u20D2':'nvltrie','\u22B5':'rtrie','\u22ED':'nrtrie','\u22B5\u20D2':'nvrtrie','\u22B6':'origof','\u22B7':'imof','\u22B8':'mumap','\u22B9':'hercon','\u22BA':'intcal','\u22BB':'veebar','\u22BD':'barvee','\u22BE':'angrtvb','\u22BF':'lrtri','\u22C0':'Wedge','\u22C1':'Vee','\u22C2':'xcap','\u22C3':'xcup','\u22C4':'diam','\u22C5':'sdot','\u22C6':'Star','\u22C7':'divonx','\u22C8':'bowtie','\u22C9':'ltimes','\u22CA':'rtimes','\u22CB':'lthree','\u22CC':'rthree','\u22CD':'bsime','\u22CE':'cuvee','\u22CF':'cuwed','\u22D0':'Sub','\u22D1':'Sup','\u22D2':'Cap','\u22D3':'Cup','\u22D4':'fork','\u22D5':'epar','\u22D6':'ltdot','\u22D7':'gtdot','\u22D8':'Ll','\u22D8\u0338':'nLl','\u22D9':'Gg','\u22D9\u0338':'nGg','\u22DA\uFE00':'lesg','\u22DA':'leg','\u22DB':'gel','\u22DB\uFE00':'gesl','\u22DE':'cuepr','\u22DF':'cuesc','\u22E6':'lnsim','\u22E7':'gnsim','\u22E8':'prnsim','\u22E9':'scnsim','\u22EE':'vellip','\u22EF':'ctdot','\u22F0':'utdot','\u22F1':'dtdot','\u22F2':'disin','\u22F3':'isinsv','\u22F4':'isins','\u22F5':'isindot','\u22F5\u0338':'notindot','\u22F6':'notinvc','\u22F7':'notinvb','\u22F9':'isinE','\u22F9\u0338':'notinE','\u22FA':'nisd','\u22FB':'xnis','\u22FC':'nis','\u22FD':'notnivc','\u22FE':'notnivb','\u2305':'barwed','\u2306':'Barwed','\u230C':'drcrop','\u230D':'dlcrop','\u230E':'urcrop','\u230F':'ulcrop','\u2310':'bnot','\u2312':'profline','\u2313':'profsurf','\u2315':'telrec','\u2316':'target','\u231C':'ulcorn','\u231D':'urcorn','\u231E':'dlcorn','\u231F':'drcorn','\u2322':'frown','\u2323':'smile','\u232D':'cylcty','\u232E':'profalar','\u2336':'topbot','\u233D':'ovbar','\u233F':'solbar','\u237C':'angzarr','\u23B0':'lmoust','\u23B1':'rmoust','\u23B4':'tbrk','\u23B5':'bbrk','\u23B6':'bbrktbrk','\u23DC':'OverParenthesis','\u23DD':'UnderParenthesis','\u23DE':'OverBrace','\u23DF':'UnderBrace','\u23E2':'trpezium','\u23E7':'elinters','\u2423':'blank','\u2500':'boxh','\u2502':'boxv','\u250C':'boxdr','\u2510':'boxdl','\u2514':'boxur','\u2518':'boxul','\u251C':'boxvr','\u2524':'boxvl','\u252C':'boxhd','\u2534':'boxhu','\u253C':'boxvh','\u2550':'boxH','\u2551':'boxV','\u2552':'boxdR','\u2553':'boxDr','\u2554':'boxDR','\u2555':'boxdL','\u2556':'boxDl','\u2557':'boxDL','\u2558':'boxuR','\u2559':'boxUr','\u255A':'boxUR','\u255B':'boxuL','\u255C':'boxUl','\u255D':'boxUL','\u255E':'boxvR','\u255F':'boxVr','\u2560':'boxVR','\u2561':'boxvL','\u2562':'boxVl','\u2563':'boxVL','\u2564':'boxHd','\u2565':'boxhD','\u2566':'boxHD','\u2567':'boxHu','\u2568':'boxhU','\u2569':'boxHU','\u256A':'boxvH','\u256B':'boxVh','\u256C':'boxVH','\u2580':'uhblk','\u2584':'lhblk','\u2588':'block','\u2591':'blk14','\u2592':'blk12','\u2593':'blk34','\u25A1':'squ','\u25AA':'squf','\u25AB':'EmptyVerySmallSquare','\u25AD':'rect','\u25AE':'marker','\u25B1':'fltns','\u25B3':'xutri','\u25B4':'utrif','\u25B5':'utri','\u25B8':'rtrif','\u25B9':'rtri','\u25BD':'xdtri','\u25BE':'dtrif','\u25BF':'dtri','\u25C2':'ltrif','\u25C3':'ltri','\u25CA':'loz','\u25CB':'cir','\u25EC':'tridot','\u25EF':'xcirc','\u25F8':'ultri','\u25F9':'urtri','\u25FA':'lltri','\u25FB':'EmptySmallSquare','\u25FC':'FilledSmallSquare','\u2605':'starf','\u2606':'star','\u260E':'phone','\u2640':'female','\u2642':'male','\u2660':'spades','\u2663':'clubs','\u2665':'hearts','\u2666':'diams','\u266A':'sung','\u2713':'check','\u2717':'cross','\u2720':'malt','\u2736':'sext','\u2758':'VerticalSeparator','\u27C8':'bsolhsub','\u27C9':'suphsol','\u27F5':'xlarr','\u27F6':'xrarr','\u27F7':'xharr','\u27F8':'xlArr','\u27F9':'xrArr','\u27FA':'xhArr','\u27FC':'xmap','\u27FF':'dzigrarr','\u2902':'nvlArr','\u2903':'nvrArr','\u2904':'nvHarr','\u2905':'Map','\u290C':'lbarr','\u290D':'rbarr','\u290E':'lBarr','\u290F':'rBarr','\u2910':'RBarr','\u2911':'DDotrahd','\u2912':'UpArrowBar','\u2913':'DownArrowBar','\u2916':'Rarrtl','\u2919':'latail','\u291A':'ratail','\u291B':'lAtail','\u291C':'rAtail','\u291D':'larrfs','\u291E':'rarrfs','\u291F':'larrbfs','\u2920':'rarrbfs','\u2923':'nwarhk','\u2924':'nearhk','\u2925':'searhk','\u2926':'swarhk','\u2927':'nwnear','\u2928':'toea','\u2929':'tosa','\u292A':'swnwar','\u2933':'rarrc','\u2933\u0338':'nrarrc','\u2935':'cudarrr','\u2936':'ldca','\u2937':'rdca','\u2938':'cudarrl','\u2939':'larrpl','\u293C':'curarrm','\u293D':'cularrp','\u2945':'rarrpl','\u2948':'harrcir','\u2949':'Uarrocir','\u294A':'lurdshar','\u294B':'ldrushar','\u294E':'LeftRightVector','\u294F':'RightUpDownVector','\u2950':'DownLeftRightVector','\u2951':'LeftUpDownVector','\u2952':'LeftVectorBar','\u2953':'RightVectorBar','\u2954':'RightUpVectorBar','\u2955':'RightDownVectorBar','\u2956':'DownLeftVectorBar','\u2957':'DownRightVectorBar','\u2958':'LeftUpVectorBar','\u2959':'LeftDownVectorBar','\u295A':'LeftTeeVector','\u295B':'RightTeeVector','\u295C':'RightUpTeeVector','\u295D':'RightDownTeeVector','\u295E':'DownLeftTeeVector','\u295F':'DownRightTeeVector','\u2960':'LeftUpTeeVector','\u2961':'LeftDownTeeVector','\u2962':'lHar','\u2963':'uHar','\u2964':'rHar','\u2965':'dHar','\u2966':'luruhar','\u2967':'ldrdhar','\u2968':'ruluhar','\u2969':'rdldhar','\u296A':'lharul','\u296B':'llhard','\u296C':'rharul','\u296D':'lrhard','\u296E':'udhar','\u296F':'duhar','\u2970':'RoundImplies','\u2971':'erarr','\u2972':'simrarr','\u2973':'larrsim','\u2974':'rarrsim','\u2975':'rarrap','\u2976':'ltlarr','\u2978':'gtrarr','\u2979':'subrarr','\u297B':'suplarr','\u297C':'lfisht','\u297D':'rfisht','\u297E':'ufisht','\u297F':'dfisht','\u299A':'vzigzag','\u299C':'vangrt','\u299D':'angrtvbd','\u29A4':'ange','\u29A5':'range','\u29A6':'dwangle','\u29A7':'uwangle','\u29A8':'angmsdaa','\u29A9':'angmsdab','\u29AA':'angmsdac','\u29AB':'angmsdad','\u29AC':'angmsdae','\u29AD':'angmsdaf','\u29AE':'angmsdag','\u29AF':'angmsdah','\u29B0':'bemptyv','\u29B1':'demptyv','\u29B2':'cemptyv','\u29B3':'raemptyv','\u29B4':'laemptyv','\u29B5':'ohbar','\u29B6':'omid','\u29B7':'opar','\u29B9':'operp','\u29BB':'olcross','\u29BC':'odsold','\u29BE':'olcir','\u29BF':'ofcir','\u29C0':'olt','\u29C1':'ogt','\u29C2':'cirscir','\u29C3':'cirE','\u29C4':'solb','\u29C5':'bsolb','\u29C9':'boxbox','\u29CD':'trisb','\u29CE':'rtriltri','\u29CF':'LeftTriangleBar','\u29CF\u0338':'NotLeftTriangleBar','\u29D0':'RightTriangleBar','\u29D0\u0338':'NotRightTriangleBar','\u29DC':'iinfin','\u29DD':'infintie','\u29DE':'nvinfin','\u29E3':'eparsl','\u29E4':'smeparsl','\u29E5':'eqvparsl','\u29EB':'lozf','\u29F4':'RuleDelayed','\u29F6':'dsol','\u2A00':'xodot','\u2A01':'xoplus','\u2A02':'xotime','\u2A04':'xuplus','\u2A06':'xsqcup','\u2A0D':'fpartint','\u2A10':'cirfnint','\u2A11':'awint','\u2A12':'rppolint','\u2A13':'scpolint','\u2A14':'npolint','\u2A15':'pointint','\u2A16':'quatint','\u2A17':'intlarhk','\u2A22':'pluscir','\u2A23':'plusacir','\u2A24':'simplus','\u2A25':'plusdu','\u2A26':'plussim','\u2A27':'plustwo','\u2A29':'mcomma','\u2A2A':'minusdu','\u2A2D':'loplus','\u2A2E':'roplus','\u2A2F':'Cross','\u2A30':'timesd','\u2A31':'timesbar','\u2A33':'smashp','\u2A34':'lotimes','\u2A35':'rotimes','\u2A36':'otimesas','\u2A37':'Otimes','\u2A38':'odiv','\u2A39':'triplus','\u2A3A':'triminus','\u2A3B':'tritime','\u2A3C':'iprod','\u2A3F':'amalg','\u2A40':'capdot','\u2A42':'ncup','\u2A43':'ncap','\u2A44':'capand','\u2A45':'cupor','\u2A46':'cupcap','\u2A47':'capcup','\u2A48':'cupbrcap','\u2A49':'capbrcup','\u2A4A':'cupcup','\u2A4B':'capcap','\u2A4C':'ccups','\u2A4D':'ccaps','\u2A50':'ccupssm','\u2A53':'And','\u2A54':'Or','\u2A55':'andand','\u2A56':'oror','\u2A57':'orslope','\u2A58':'andslope','\u2A5A':'andv','\u2A5B':'orv','\u2A5C':'andd','\u2A5D':'ord','\u2A5F':'wedbar','\u2A66':'sdote','\u2A6A':'simdot','\u2A6D':'congdot','\u2A6D\u0338':'ncongdot','\u2A6E':'easter','\u2A6F':'apacir','\u2A70':'apE','\u2A70\u0338':'napE','\u2A71':'eplus','\u2A72':'pluse','\u2A73':'Esim','\u2A77':'eDDot','\u2A78':'equivDD','\u2A79':'ltcir','\u2A7A':'gtcir','\u2A7B':'ltquest','\u2A7C':'gtquest','\u2A7D':'les','\u2A7D\u0338':'nles','\u2A7E':'ges','\u2A7E\u0338':'nges','\u2A7F':'lesdot','\u2A80':'gesdot','\u2A81':'lesdoto','\u2A82':'gesdoto','\u2A83':'lesdotor','\u2A84':'gesdotol','\u2A85':'lap','\u2A86':'gap','\u2A87':'lne','\u2A88':'gne','\u2A89':'lnap','\u2A8A':'gnap','\u2A8B':'lEg','\u2A8C':'gEl','\u2A8D':'lsime','\u2A8E':'gsime','\u2A8F':'lsimg','\u2A90':'gsiml','\u2A91':'lgE','\u2A92':'glE','\u2A93':'lesges','\u2A94':'gesles','\u2A95':'els','\u2A96':'egs','\u2A97':'elsdot','\u2A98':'egsdot','\u2A99':'el','\u2A9A':'eg','\u2A9D':'siml','\u2A9E':'simg','\u2A9F':'simlE','\u2AA0':'simgE','\u2AA1':'LessLess','\u2AA1\u0338':'NotNestedLessLess','\u2AA2':'GreaterGreater','\u2AA2\u0338':'NotNestedGreaterGreater','\u2AA4':'glj','\u2AA5':'gla','\u2AA6':'ltcc','\u2AA7':'gtcc','\u2AA8':'lescc','\u2AA9':'gescc','\u2AAA':'smt','\u2AAB':'lat','\u2AAC':'smte','\u2AAC\uFE00':'smtes','\u2AAD':'late','\u2AAD\uFE00':'lates','\u2AAE':'bumpE','\u2AAF':'pre','\u2AAF\u0338':'npre','\u2AB0':'sce','\u2AB0\u0338':'nsce','\u2AB3':'prE','\u2AB4':'scE','\u2AB5':'prnE','\u2AB6':'scnE','\u2AB7':'prap','\u2AB8':'scap','\u2AB9':'prnap','\u2ABA':'scnap','\u2ABB':'Pr','\u2ABC':'Sc','\u2ABD':'subdot','\u2ABE':'supdot','\u2ABF':'subplus','\u2AC0':'supplus','\u2AC1':'submult','\u2AC2':'supmult','\u2AC3':'subedot','\u2AC4':'supedot','\u2AC5':'subE','\u2AC5\u0338':'nsubE','\u2AC6':'supE','\u2AC6\u0338':'nsupE','\u2AC7':'subsim','\u2AC8':'supsim','\u2ACB\uFE00':'vsubnE','\u2ACB':'subnE','\u2ACC\uFE00':'vsupnE','\u2ACC':'supnE','\u2ACF':'csub','\u2AD0':'csup','\u2AD1':'csube','\u2AD2':'csupe','\u2AD3':'subsup','\u2AD4':'supsub','\u2AD5':'subsub','\u2AD6':'supsup','\u2AD7':'suphsub','\u2AD8':'supdsub','\u2AD9':'forkv','\u2ADA':'topfork','\u2ADB':'mlcp','\u2AE4':'Dashv','\u2AE6':'Vdashl','\u2AE7':'Barv','\u2AE8':'vBar','\u2AE9':'vBarv','\u2AEB':'Vbar','\u2AEC':'Not','\u2AED':'bNot','\u2AEE':'rnmid','\u2AEF':'cirmid','\u2AF0':'midcir','\u2AF1':'topcir','\u2AF2':'nhpar','\u2AF3':'parsim','\u2AFD':'parsl','\u2AFD\u20E5':'nparsl','\u266D':'flat','\u266E':'natur','\u266F':'sharp','\xA4':'curren','\xA2':'cent','$':'dollar','\xA3':'pound','\xA5':'yen','\u20AC':'euro','\xB9':'sup1','\xBD':'half','\u2153':'frac13','\xBC':'frac14','\u2155':'frac15','\u2159':'frac16','\u215B':'frac18','\xB2':'sup2','\u2154':'frac23','\u2156':'frac25','\xB3':'sup3','\xBE':'frac34','\u2157':'frac35','\u215C':'frac38','\u2158':'frac45','\u215A':'frac56','\u215D':'frac58','\u215E':'frac78','\uD835\uDCB6':'ascr','\uD835\uDD52':'aopf','\uD835\uDD1E':'afr','\uD835\uDD38':'Aopf','\uD835\uDD04':'Afr','\uD835\uDC9C':'Ascr','\xAA':'ordf','\xE1':'aacute','\xC1':'Aacute','\xE0':'agrave','\xC0':'Agrave','\u0103':'abreve','\u0102':'Abreve','\xE2':'acirc','\xC2':'Acirc','\xE5':'aring','\xC5':'angst','\xE4':'auml','\xC4':'Auml','\xE3':'atilde','\xC3':'Atilde','\u0105':'aogon','\u0104':'Aogon','\u0101':'amacr','\u0100':'Amacr','\xE6':'aelig','\xC6':'AElig','\uD835\uDCB7':'bscr','\uD835\uDD53':'bopf','\uD835\uDD1F':'bfr','\uD835\uDD39':'Bopf','\u212C':'Bscr','\uD835\uDD05':'Bfr','\uD835\uDD20':'cfr','\uD835\uDCB8':'cscr','\uD835\uDD54':'copf','\u212D':'Cfr','\uD835\uDC9E':'Cscr','\u2102':'Copf','\u0107':'cacute','\u0106':'Cacute','\u0109':'ccirc','\u0108':'Ccirc','\u010D':'ccaron','\u010C':'Ccaron','\u010B':'cdot','\u010A':'Cdot','\xE7':'ccedil','\xC7':'Ccedil','\u2105':'incare','\uD835\uDD21':'dfr','\u2146':'dd','\uD835\uDD55':'dopf','\uD835\uDCB9':'dscr','\uD835\uDC9F':'Dscr','\uD835\uDD07':'Dfr','\u2145':'DD','\uD835\uDD3B':'Dopf','\u010F':'dcaron','\u010E':'Dcaron','\u0111':'dstrok','\u0110':'Dstrok','\xF0':'eth','\xD0':'ETH','\u2147':'ee','\u212F':'escr','\uD835\uDD22':'efr','\uD835\uDD56':'eopf','\u2130':'Escr','\uD835\uDD08':'Efr','\uD835\uDD3C':'Eopf','\xE9':'eacute','\xC9':'Eacute','\xE8':'egrave','\xC8':'Egrave','\xEA':'ecirc','\xCA':'Ecirc','\u011B':'ecaron','\u011A':'Ecaron','\xEB':'euml','\xCB':'Euml','\u0117':'edot','\u0116':'Edot','\u0119':'eogon','\u0118':'Eogon','\u0113':'emacr','\u0112':'Emacr','\uD835\uDD23':'ffr','\uD835\uDD57':'fopf','\uD835\uDCBB':'fscr','\uD835\uDD09':'Ffr','\uD835\uDD3D':'Fopf','\u2131':'Fscr','\uFB00':'fflig','\uFB03':'ffilig','\uFB04':'ffllig','\uFB01':'filig','fj':'fjlig','\uFB02':'fllig','\u0192':'fnof','\u210A':'gscr','\uD835\uDD58':'gopf','\uD835\uDD24':'gfr','\uD835\uDCA2':'Gscr','\uD835\uDD3E':'Gopf','\uD835\uDD0A':'Gfr','\u01F5':'gacute','\u011F':'gbreve','\u011E':'Gbreve','\u011D':'gcirc','\u011C':'Gcirc','\u0121':'gdot','\u0120':'Gdot','\u0122':'Gcedil','\uD835\uDD25':'hfr','\u210E':'planckh','\uD835\uDCBD':'hscr','\uD835\uDD59':'hopf','\u210B':'Hscr','\u210C':'Hfr','\u210D':'Hopf','\u0125':'hcirc','\u0124':'Hcirc','\u210F':'hbar','\u0127':'hstrok','\u0126':'Hstrok','\uD835\uDD5A':'iopf','\uD835\uDD26':'ifr','\uD835\uDCBE':'iscr','\u2148':'ii','\uD835\uDD40':'Iopf','\u2110':'Iscr','\u2111':'Im','\xED':'iacute','\xCD':'Iacute','\xEC':'igrave','\xCC':'Igrave','\xEE':'icirc','\xCE':'Icirc','\xEF':'iuml','\xCF':'Iuml','\u0129':'itilde','\u0128':'Itilde','\u0130':'Idot','\u012F':'iogon','\u012E':'Iogon','\u012B':'imacr','\u012A':'Imacr','\u0133':'ijlig','\u0132':'IJlig','\u0131':'imath','\uD835\uDCBF':'jscr','\uD835\uDD5B':'jopf','\uD835\uDD27':'jfr','\uD835\uDCA5':'Jscr','\uD835\uDD0D':'Jfr','\uD835\uDD41':'Jopf','\u0135':'jcirc','\u0134':'Jcirc','\u0237':'jmath','\uD835\uDD5C':'kopf','\uD835\uDCC0':'kscr','\uD835\uDD28':'kfr','\uD835\uDCA6':'Kscr','\uD835\uDD42':'Kopf','\uD835\uDD0E':'Kfr','\u0137':'kcedil','\u0136':'Kcedil','\uD835\uDD29':'lfr','\uD835\uDCC1':'lscr','\u2113':'ell','\uD835\uDD5D':'lopf','\u2112':'Lscr','\uD835\uDD0F':'Lfr','\uD835\uDD43':'Lopf','\u013A':'lacute','\u0139':'Lacute','\u013E':'lcaron','\u013D':'Lcaron','\u013C':'lcedil','\u013B':'Lcedil','\u0142':'lstrok','\u0141':'Lstrok','\u0140':'lmidot','\u013F':'Lmidot','\uD835\uDD2A':'mfr','\uD835\uDD5E':'mopf','\uD835\uDCC2':'mscr','\uD835\uDD10':'Mfr','\uD835\uDD44':'Mopf','\u2133':'Mscr','\uD835\uDD2B':'nfr','\uD835\uDD5F':'nopf','\uD835\uDCC3':'nscr','\u2115':'Nopf','\uD835\uDCA9':'Nscr','\uD835\uDD11':'Nfr','\u0144':'nacute','\u0143':'Nacute','\u0148':'ncaron','\u0147':'Ncaron','\xF1':'ntilde','\xD1':'Ntilde','\u0146':'ncedil','\u0145':'Ncedil','\u2116':'numero','\u014B':'eng','\u014A':'ENG','\uD835\uDD60':'oopf','\uD835\uDD2C':'ofr','\u2134':'oscr','\uD835\uDCAA':'Oscr','\uD835\uDD12':'Ofr','\uD835\uDD46':'Oopf','\xBA':'ordm','\xF3':'oacute','\xD3':'Oacute','\xF2':'ograve','\xD2':'Ograve','\xF4':'ocirc','\xD4':'Ocirc','\xF6':'ouml','\xD6':'Ouml','\u0151':'odblac','\u0150':'Odblac','\xF5':'otilde','\xD5':'Otilde','\xF8':'oslash','\xD8':'Oslash','\u014D':'omacr','\u014C':'Omacr','\u0153':'oelig','\u0152':'OElig','\uD835\uDD2D':'pfr','\uD835\uDCC5':'pscr','\uD835\uDD61':'popf','\u2119':'Popf','\uD835\uDD13':'Pfr','\uD835\uDCAB':'Pscr','\uD835\uDD62':'qopf','\uD835\uDD2E':'qfr','\uD835\uDCC6':'qscr','\uD835\uDCAC':'Qscr','\uD835\uDD14':'Qfr','\u211A':'Qopf','\u0138':'kgreen','\uD835\uDD2F':'rfr','\uD835\uDD63':'ropf','\uD835\uDCC7':'rscr','\u211B':'Rscr','\u211C':'Re','\u211D':'Ropf','\u0155':'racute','\u0154':'Racute','\u0159':'rcaron','\u0158':'Rcaron','\u0157':'rcedil','\u0156':'Rcedil','\uD835\uDD64':'sopf','\uD835\uDCC8':'sscr','\uD835\uDD30':'sfr','\uD835\uDD4A':'Sopf','\uD835\uDD16':'Sfr','\uD835\uDCAE':'Sscr','\u24C8':'oS','\u015B':'sacute','\u015A':'Sacute','\u015D':'scirc','\u015C':'Scirc','\u0161':'scaron','\u0160':'Scaron','\u015F':'scedil','\u015E':'Scedil','\xDF':'szlig','\uD835\uDD31':'tfr','\uD835\uDCC9':'tscr','\uD835\uDD65':'topf','\uD835\uDCAF':'Tscr','\uD835\uDD17':'Tfr','\uD835\uDD4B':'Topf','\u0165':'tcaron','\u0164':'Tcaron','\u0163':'tcedil','\u0162':'Tcedil','\u2122':'trade','\u0167':'tstrok','\u0166':'Tstrok','\uD835\uDCCA':'uscr','\uD835\uDD66':'uopf','\uD835\uDD32':'ufr','\uD835\uDD4C':'Uopf','\uD835\uDD18':'Ufr','\uD835\uDCB0':'Uscr','\xFA':'uacute','\xDA':'Uacute','\xF9':'ugrave','\xD9':'Ugrave','\u016D':'ubreve','\u016C':'Ubreve','\xFB':'ucirc','\xDB':'Ucirc','\u016F':'uring','\u016E':'Uring','\xFC':'uuml','\xDC':'Uuml','\u0171':'udblac','\u0170':'Udblac','\u0169':'utilde','\u0168':'Utilde','\u0173':'uogon','\u0172':'Uogon','\u016B':'umacr','\u016A':'Umacr','\uD835\uDD33':'vfr','\uD835\uDD67':'vopf','\uD835\uDCCB':'vscr','\uD835\uDD19':'Vfr','\uD835\uDD4D':'Vopf','\uD835\uDCB1':'Vscr','\uD835\uDD68':'wopf','\uD835\uDCCC':'wscr','\uD835\uDD34':'wfr','\uD835\uDCB2':'Wscr','\uD835\uDD4E':'Wopf','\uD835\uDD1A':'Wfr','\u0175':'wcirc','\u0174':'Wcirc','\uD835\uDD35':'xfr','\uD835\uDCCD':'xscr','\uD835\uDD69':'xopf','\uD835\uDD4F':'Xopf','\uD835\uDD1B':'Xfr','\uD835\uDCB3':'Xscr','\uD835\uDD36':'yfr','\uD835\uDCCE':'yscr','\uD835\uDD6A':'yopf','\uD835\uDCB4':'Yscr','\uD835\uDD1C':'Yfr','\uD835\uDD50':'Yopf','\xFD':'yacute','\xDD':'Yacute','\u0177':'ycirc','\u0176':'Ycirc','\xFF':'yuml','\u0178':'Yuml','\uD835\uDCCF':'zscr','\uD835\uDD37':'zfr','\uD835\uDD6B':'zopf','\u2128':'Zfr','\u2124':'Zopf','\uD835\uDCB5':'Zscr','\u017A':'zacute','\u0179':'Zacute','\u017E':'zcaron','\u017D':'Zcaron','\u017C':'zdot','\u017B':'Zdot','\u01B5':'imped','\xFE':'thorn','\xDE':'THORN','\u0149':'napos','\u03B1':'alpha','\u0391':'Alpha','\u03B2':'beta','\u0392':'Beta','\u03B3':'gamma','\u0393':'Gamma','\u03B4':'delta','\u0394':'Delta','\u03B5':'epsi','\u03F5':'epsiv','\u0395':'Epsilon','\u03DD':'gammad','\u03DC':'Gammad','\u03B6':'zeta','\u0396':'Zeta','\u03B7':'eta','\u0397':'Eta','\u03B8':'theta','\u03D1':'thetav','\u0398':'Theta','\u03B9':'iota','\u0399':'Iota','\u03BA':'kappa','\u03F0':'kappav','\u039A':'Kappa','\u03BB':'lambda','\u039B':'Lambda','\u03BC':'mu','\xB5':'micro','\u039C':'Mu','\u03BD':'nu','\u039D':'Nu','\u03BE':'xi','\u039E':'Xi','\u03BF':'omicron','\u039F':'Omicron','\u03C0':'pi','\u03D6':'piv','\u03A0':'Pi','\u03C1':'rho','\u03F1':'rhov','\u03A1':'Rho','\u03C3':'sigma','\u03A3':'Sigma','\u03C2':'sigmaf','\u03C4':'tau','\u03A4':'Tau','\u03C5':'upsi','\u03A5':'Upsilon','\u03D2':'Upsi','\u03C6':'phi','\u03D5':'phiv','\u03A6':'Phi','\u03C7':'chi','\u03A7':'Chi','\u03C8':'psi','\u03A8':'Psi','\u03C9':'omega','\u03A9':'ohm','\u0430':'acy','\u0410':'Acy','\u0431':'bcy','\u0411':'Bcy','\u0432':'vcy','\u0412':'Vcy','\u0433':'gcy','\u0413':'Gcy','\u0453':'gjcy','\u0403':'GJcy','\u0434':'dcy','\u0414':'Dcy','\u0452':'djcy','\u0402':'DJcy','\u0435':'iecy','\u0415':'IEcy','\u0451':'iocy','\u0401':'IOcy','\u0454':'jukcy','\u0404':'Jukcy','\u0436':'zhcy','\u0416':'ZHcy','\u0437':'zcy','\u0417':'Zcy','\u0455':'dscy','\u0405':'DScy','\u0438':'icy','\u0418':'Icy','\u0456':'iukcy','\u0406':'Iukcy','\u0457':'yicy','\u0407':'YIcy','\u0439':'jcy','\u0419':'Jcy','\u0458':'jsercy','\u0408':'Jsercy','\u043A':'kcy','\u041A':'Kcy','\u045C':'kjcy','\u040C':'KJcy','\u043B':'lcy','\u041B':'Lcy','\u0459':'ljcy','\u0409':'LJcy','\u043C':'mcy','\u041C':'Mcy','\u043D':'ncy','\u041D':'Ncy','\u045A':'njcy','\u040A':'NJcy','\u043E':'ocy','\u041E':'Ocy','\u043F':'pcy','\u041F':'Pcy','\u0440':'rcy','\u0420':'Rcy','\u0441':'scy','\u0421':'Scy','\u0442':'tcy','\u0422':'Tcy','\u045B':'tshcy','\u040B':'TSHcy','\u0443':'ucy','\u0423':'Ucy','\u045E':'ubrcy','\u040E':'Ubrcy','\u0444':'fcy','\u0424':'Fcy','\u0445':'khcy','\u0425':'KHcy','\u0446':'tscy','\u0426':'TScy','\u0447':'chcy','\u0427':'CHcy','\u045F':'dzcy','\u040F':'DZcy','\u0448':'shcy','\u0428':'SHcy','\u0449':'shchcy','\u0429':'SHCHcy','\u044A':'hardcy','\u042A':'HARDcy','\u044B':'ycy','\u042B':'Ycy','\u044C':'softcy','\u042C':'SOFTcy','\u044D':'ecy','\u042D':'Ecy','\u044E':'yucy','\u042E':'YUcy','\u044F':'yacy','\u042F':'YAcy','\u2135':'aleph','\u2136':'beth','\u2137':'gimel','\u2138':'daleth'}; - - var regexEscape = /["&'<>`]/g; - var escapeMap = { - '"': '"', - '&': '&', - '\'': ''', - '<': '<', - // See https://mathiasbynens.be/notes/ambiguous-ampersands: in HTML, the - // following is not strictly necessary unless it’s part of a tag or an - // unquoted attribute value. We’re only escaping it to support those - // situations, and for XML support. - '>': '>', - // In Internet Explorer ≤ 8, the backtick character can be used - // to break out of (un)quoted attribute values or HTML comments. - // See http://html5sec.org/#102, http://html5sec.org/#108, and - // http://html5sec.org/#133. - '`': '`' - }; - - var regexInvalidEntity = /&#(?:[xX][^a-fA-F0-9]|[^0-9xX])/; - var regexInvalidRawCodePoint = /[\0-\x08\x0B\x0E-\x1F\x7F-\x9F\uFDD0-\uFDEF\uFFFE\uFFFF]|[\uD83F\uD87F\uD8BF\uD8FF\uD93F\uD97F\uD9BF\uD9FF\uDA3F\uDA7F\uDABF\uDAFF\uDB3F\uDB7F\uDBBF\uDBFF][\uDFFE\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; - var regexDecode = /&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+);|&(Aacute|Agrave|Atilde|Ccedil|Eacute|Egrave|Iacute|Igrave|Ntilde|Oacute|Ograve|Oslash|Otilde|Uacute|Ugrave|Yacute|aacute|agrave|atilde|brvbar|ccedil|curren|divide|eacute|egrave|frac12|frac14|frac34|iacute|igrave|iquest|middot|ntilde|oacute|ograve|oslash|otilde|plusmn|uacute|ugrave|yacute|AElig|Acirc|Aring|Ecirc|Icirc|Ocirc|THORN|Ucirc|acirc|acute|aelig|aring|cedil|ecirc|icirc|iexcl|laquo|micro|ocirc|pound|raquo|szlig|thorn|times|ucirc|Auml|COPY|Euml|Iuml|Ouml|QUOT|Uuml|auml|cent|copy|euml|iuml|macr|nbsp|ordf|ordm|ouml|para|quot|sect|sup1|sup2|sup3|uuml|yuml|AMP|ETH|REG|amp|deg|eth|not|reg|shy|uml|yen|GT|LT|gt|lt)([=a-zA-Z0-9])?/g; - var decodeMap = {'aacute':'\xE1','Aacute':'\xC1','abreve':'\u0103','Abreve':'\u0102','ac':'\u223E','acd':'\u223F','acE':'\u223E\u0333','acirc':'\xE2','Acirc':'\xC2','acute':'\xB4','acy':'\u0430','Acy':'\u0410','aelig':'\xE6','AElig':'\xC6','af':'\u2061','afr':'\uD835\uDD1E','Afr':'\uD835\uDD04','agrave':'\xE0','Agrave':'\xC0','alefsym':'\u2135','aleph':'\u2135','alpha':'\u03B1','Alpha':'\u0391','amacr':'\u0101','Amacr':'\u0100','amalg':'\u2A3F','amp':'&','AMP':'&','and':'\u2227','And':'\u2A53','andand':'\u2A55','andd':'\u2A5C','andslope':'\u2A58','andv':'\u2A5A','ang':'\u2220','ange':'\u29A4','angle':'\u2220','angmsd':'\u2221','angmsdaa':'\u29A8','angmsdab':'\u29A9','angmsdac':'\u29AA','angmsdad':'\u29AB','angmsdae':'\u29AC','angmsdaf':'\u29AD','angmsdag':'\u29AE','angmsdah':'\u29AF','angrt':'\u221F','angrtvb':'\u22BE','angrtvbd':'\u299D','angsph':'\u2222','angst':'\xC5','angzarr':'\u237C','aogon':'\u0105','Aogon':'\u0104','aopf':'\uD835\uDD52','Aopf':'\uD835\uDD38','ap':'\u2248','apacir':'\u2A6F','ape':'\u224A','apE':'\u2A70','apid':'\u224B','apos':'\'','ApplyFunction':'\u2061','approx':'\u2248','approxeq':'\u224A','aring':'\xE5','Aring':'\xC5','ascr':'\uD835\uDCB6','Ascr':'\uD835\uDC9C','Assign':'\u2254','ast':'*','asymp':'\u2248','asympeq':'\u224D','atilde':'\xE3','Atilde':'\xC3','auml':'\xE4','Auml':'\xC4','awconint':'\u2233','awint':'\u2A11','backcong':'\u224C','backepsilon':'\u03F6','backprime':'\u2035','backsim':'\u223D','backsimeq':'\u22CD','Backslash':'\u2216','Barv':'\u2AE7','barvee':'\u22BD','barwed':'\u2305','Barwed':'\u2306','barwedge':'\u2305','bbrk':'\u23B5','bbrktbrk':'\u23B6','bcong':'\u224C','bcy':'\u0431','Bcy':'\u0411','bdquo':'\u201E','becaus':'\u2235','because':'\u2235','Because':'\u2235','bemptyv':'\u29B0','bepsi':'\u03F6','bernou':'\u212C','Bernoullis':'\u212C','beta':'\u03B2','Beta':'\u0392','beth':'\u2136','between':'\u226C','bfr':'\uD835\uDD1F','Bfr':'\uD835\uDD05','bigcap':'\u22C2','bigcirc':'\u25EF','bigcup':'\u22C3','bigodot':'\u2A00','bigoplus':'\u2A01','bigotimes':'\u2A02','bigsqcup':'\u2A06','bigstar':'\u2605','bigtriangledown':'\u25BD','bigtriangleup':'\u25B3','biguplus':'\u2A04','bigvee':'\u22C1','bigwedge':'\u22C0','bkarow':'\u290D','blacklozenge':'\u29EB','blacksquare':'\u25AA','blacktriangle':'\u25B4','blacktriangledown':'\u25BE','blacktriangleleft':'\u25C2','blacktriangleright':'\u25B8','blank':'\u2423','blk12':'\u2592','blk14':'\u2591','blk34':'\u2593','block':'\u2588','bne':'=\u20E5','bnequiv':'\u2261\u20E5','bnot':'\u2310','bNot':'\u2AED','bopf':'\uD835\uDD53','Bopf':'\uD835\uDD39','bot':'\u22A5','bottom':'\u22A5','bowtie':'\u22C8','boxbox':'\u29C9','boxdl':'\u2510','boxdL':'\u2555','boxDl':'\u2556','boxDL':'\u2557','boxdr':'\u250C','boxdR':'\u2552','boxDr':'\u2553','boxDR':'\u2554','boxh':'\u2500','boxH':'\u2550','boxhd':'\u252C','boxhD':'\u2565','boxHd':'\u2564','boxHD':'\u2566','boxhu':'\u2534','boxhU':'\u2568','boxHu':'\u2567','boxHU':'\u2569','boxminus':'\u229F','boxplus':'\u229E','boxtimes':'\u22A0','boxul':'\u2518','boxuL':'\u255B','boxUl':'\u255C','boxUL':'\u255D','boxur':'\u2514','boxuR':'\u2558','boxUr':'\u2559','boxUR':'\u255A','boxv':'\u2502','boxV':'\u2551','boxvh':'\u253C','boxvH':'\u256A','boxVh':'\u256B','boxVH':'\u256C','boxvl':'\u2524','boxvL':'\u2561','boxVl':'\u2562','boxVL':'\u2563','boxvr':'\u251C','boxvR':'\u255E','boxVr':'\u255F','boxVR':'\u2560','bprime':'\u2035','breve':'\u02D8','Breve':'\u02D8','brvbar':'\xA6','bscr':'\uD835\uDCB7','Bscr':'\u212C','bsemi':'\u204F','bsim':'\u223D','bsime':'\u22CD','bsol':'\\','bsolb':'\u29C5','bsolhsub':'\u27C8','bull':'\u2022','bullet':'\u2022','bump':'\u224E','bumpe':'\u224F','bumpE':'\u2AAE','bumpeq':'\u224F','Bumpeq':'\u224E','cacute':'\u0107','Cacute':'\u0106','cap':'\u2229','Cap':'\u22D2','capand':'\u2A44','capbrcup':'\u2A49','capcap':'\u2A4B','capcup':'\u2A47','capdot':'\u2A40','CapitalDifferentialD':'\u2145','caps':'\u2229\uFE00','caret':'\u2041','caron':'\u02C7','Cayleys':'\u212D','ccaps':'\u2A4D','ccaron':'\u010D','Ccaron':'\u010C','ccedil':'\xE7','Ccedil':'\xC7','ccirc':'\u0109','Ccirc':'\u0108','Cconint':'\u2230','ccups':'\u2A4C','ccupssm':'\u2A50','cdot':'\u010B','Cdot':'\u010A','cedil':'\xB8','Cedilla':'\xB8','cemptyv':'\u29B2','cent':'\xA2','centerdot':'\xB7','CenterDot':'\xB7','cfr':'\uD835\uDD20','Cfr':'\u212D','chcy':'\u0447','CHcy':'\u0427','check':'\u2713','checkmark':'\u2713','chi':'\u03C7','Chi':'\u03A7','cir':'\u25CB','circ':'\u02C6','circeq':'\u2257','circlearrowleft':'\u21BA','circlearrowright':'\u21BB','circledast':'\u229B','circledcirc':'\u229A','circleddash':'\u229D','CircleDot':'\u2299','circledR':'\xAE','circledS':'\u24C8','CircleMinus':'\u2296','CirclePlus':'\u2295','CircleTimes':'\u2297','cire':'\u2257','cirE':'\u29C3','cirfnint':'\u2A10','cirmid':'\u2AEF','cirscir':'\u29C2','ClockwiseContourIntegral':'\u2232','CloseCurlyDoubleQuote':'\u201D','CloseCurlyQuote':'\u2019','clubs':'\u2663','clubsuit':'\u2663','colon':':','Colon':'\u2237','colone':'\u2254','Colone':'\u2A74','coloneq':'\u2254','comma':',','commat':'@','comp':'\u2201','compfn':'\u2218','complement':'\u2201','complexes':'\u2102','cong':'\u2245','congdot':'\u2A6D','Congruent':'\u2261','conint':'\u222E','Conint':'\u222F','ContourIntegral':'\u222E','copf':'\uD835\uDD54','Copf':'\u2102','coprod':'\u2210','Coproduct':'\u2210','copy':'\xA9','COPY':'\xA9','copysr':'\u2117','CounterClockwiseContourIntegral':'\u2233','crarr':'\u21B5','cross':'\u2717','Cross':'\u2A2F','cscr':'\uD835\uDCB8','Cscr':'\uD835\uDC9E','csub':'\u2ACF','csube':'\u2AD1','csup':'\u2AD0','csupe':'\u2AD2','ctdot':'\u22EF','cudarrl':'\u2938','cudarrr':'\u2935','cuepr':'\u22DE','cuesc':'\u22DF','cularr':'\u21B6','cularrp':'\u293D','cup':'\u222A','Cup':'\u22D3','cupbrcap':'\u2A48','cupcap':'\u2A46','CupCap':'\u224D','cupcup':'\u2A4A','cupdot':'\u228D','cupor':'\u2A45','cups':'\u222A\uFE00','curarr':'\u21B7','curarrm':'\u293C','curlyeqprec':'\u22DE','curlyeqsucc':'\u22DF','curlyvee':'\u22CE','curlywedge':'\u22CF','curren':'\xA4','curvearrowleft':'\u21B6','curvearrowright':'\u21B7','cuvee':'\u22CE','cuwed':'\u22CF','cwconint':'\u2232','cwint':'\u2231','cylcty':'\u232D','dagger':'\u2020','Dagger':'\u2021','daleth':'\u2138','darr':'\u2193','dArr':'\u21D3','Darr':'\u21A1','dash':'\u2010','dashv':'\u22A3','Dashv':'\u2AE4','dbkarow':'\u290F','dblac':'\u02DD','dcaron':'\u010F','Dcaron':'\u010E','dcy':'\u0434','Dcy':'\u0414','dd':'\u2146','DD':'\u2145','ddagger':'\u2021','ddarr':'\u21CA','DDotrahd':'\u2911','ddotseq':'\u2A77','deg':'\xB0','Del':'\u2207','delta':'\u03B4','Delta':'\u0394','demptyv':'\u29B1','dfisht':'\u297F','dfr':'\uD835\uDD21','Dfr':'\uD835\uDD07','dHar':'\u2965','dharl':'\u21C3','dharr':'\u21C2','DiacriticalAcute':'\xB4','DiacriticalDot':'\u02D9','DiacriticalDoubleAcute':'\u02DD','DiacriticalGrave':'`','DiacriticalTilde':'\u02DC','diam':'\u22C4','diamond':'\u22C4','Diamond':'\u22C4','diamondsuit':'\u2666','diams':'\u2666','die':'\xA8','DifferentialD':'\u2146','digamma':'\u03DD','disin':'\u22F2','div':'\xF7','divide':'\xF7','divideontimes':'\u22C7','divonx':'\u22C7','djcy':'\u0452','DJcy':'\u0402','dlcorn':'\u231E','dlcrop':'\u230D','dollar':'$','dopf':'\uD835\uDD55','Dopf':'\uD835\uDD3B','dot':'\u02D9','Dot':'\xA8','DotDot':'\u20DC','doteq':'\u2250','doteqdot':'\u2251','DotEqual':'\u2250','dotminus':'\u2238','dotplus':'\u2214','dotsquare':'\u22A1','doublebarwedge':'\u2306','DoubleContourIntegral':'\u222F','DoubleDot':'\xA8','DoubleDownArrow':'\u21D3','DoubleLeftArrow':'\u21D0','DoubleLeftRightArrow':'\u21D4','DoubleLeftTee':'\u2AE4','DoubleLongLeftArrow':'\u27F8','DoubleLongLeftRightArrow':'\u27FA','DoubleLongRightArrow':'\u27F9','DoubleRightArrow':'\u21D2','DoubleRightTee':'\u22A8','DoubleUpArrow':'\u21D1','DoubleUpDownArrow':'\u21D5','DoubleVerticalBar':'\u2225','downarrow':'\u2193','Downarrow':'\u21D3','DownArrow':'\u2193','DownArrowBar':'\u2913','DownArrowUpArrow':'\u21F5','DownBreve':'\u0311','downdownarrows':'\u21CA','downharpoonleft':'\u21C3','downharpoonright':'\u21C2','DownLeftRightVector':'\u2950','DownLeftTeeVector':'\u295E','DownLeftVector':'\u21BD','DownLeftVectorBar':'\u2956','DownRightTeeVector':'\u295F','DownRightVector':'\u21C1','DownRightVectorBar':'\u2957','DownTee':'\u22A4','DownTeeArrow':'\u21A7','drbkarow':'\u2910','drcorn':'\u231F','drcrop':'\u230C','dscr':'\uD835\uDCB9','Dscr':'\uD835\uDC9F','dscy':'\u0455','DScy':'\u0405','dsol':'\u29F6','dstrok':'\u0111','Dstrok':'\u0110','dtdot':'\u22F1','dtri':'\u25BF','dtrif':'\u25BE','duarr':'\u21F5','duhar':'\u296F','dwangle':'\u29A6','dzcy':'\u045F','DZcy':'\u040F','dzigrarr':'\u27FF','eacute':'\xE9','Eacute':'\xC9','easter':'\u2A6E','ecaron':'\u011B','Ecaron':'\u011A','ecir':'\u2256','ecirc':'\xEA','Ecirc':'\xCA','ecolon':'\u2255','ecy':'\u044D','Ecy':'\u042D','eDDot':'\u2A77','edot':'\u0117','eDot':'\u2251','Edot':'\u0116','ee':'\u2147','efDot':'\u2252','efr':'\uD835\uDD22','Efr':'\uD835\uDD08','eg':'\u2A9A','egrave':'\xE8','Egrave':'\xC8','egs':'\u2A96','egsdot':'\u2A98','el':'\u2A99','Element':'\u2208','elinters':'\u23E7','ell':'\u2113','els':'\u2A95','elsdot':'\u2A97','emacr':'\u0113','Emacr':'\u0112','empty':'\u2205','emptyset':'\u2205','EmptySmallSquare':'\u25FB','emptyv':'\u2205','EmptyVerySmallSquare':'\u25AB','emsp':'\u2003','emsp13':'\u2004','emsp14':'\u2005','eng':'\u014B','ENG':'\u014A','ensp':'\u2002','eogon':'\u0119','Eogon':'\u0118','eopf':'\uD835\uDD56','Eopf':'\uD835\uDD3C','epar':'\u22D5','eparsl':'\u29E3','eplus':'\u2A71','epsi':'\u03B5','epsilon':'\u03B5','Epsilon':'\u0395','epsiv':'\u03F5','eqcirc':'\u2256','eqcolon':'\u2255','eqsim':'\u2242','eqslantgtr':'\u2A96','eqslantless':'\u2A95','Equal':'\u2A75','equals':'=','EqualTilde':'\u2242','equest':'\u225F','Equilibrium':'\u21CC','equiv':'\u2261','equivDD':'\u2A78','eqvparsl':'\u29E5','erarr':'\u2971','erDot':'\u2253','escr':'\u212F','Escr':'\u2130','esdot':'\u2250','esim':'\u2242','Esim':'\u2A73','eta':'\u03B7','Eta':'\u0397','eth':'\xF0','ETH':'\xD0','euml':'\xEB','Euml':'\xCB','euro':'\u20AC','excl':'!','exist':'\u2203','Exists':'\u2203','expectation':'\u2130','exponentiale':'\u2147','ExponentialE':'\u2147','fallingdotseq':'\u2252','fcy':'\u0444','Fcy':'\u0424','female':'\u2640','ffilig':'\uFB03','fflig':'\uFB00','ffllig':'\uFB04','ffr':'\uD835\uDD23','Ffr':'\uD835\uDD09','filig':'\uFB01','FilledSmallSquare':'\u25FC','FilledVerySmallSquare':'\u25AA','fjlig':'fj','flat':'\u266D','fllig':'\uFB02','fltns':'\u25B1','fnof':'\u0192','fopf':'\uD835\uDD57','Fopf':'\uD835\uDD3D','forall':'\u2200','ForAll':'\u2200','fork':'\u22D4','forkv':'\u2AD9','Fouriertrf':'\u2131','fpartint':'\u2A0D','frac12':'\xBD','frac13':'\u2153','frac14':'\xBC','frac15':'\u2155','frac16':'\u2159','frac18':'\u215B','frac23':'\u2154','frac25':'\u2156','frac34':'\xBE','frac35':'\u2157','frac38':'\u215C','frac45':'\u2158','frac56':'\u215A','frac58':'\u215D','frac78':'\u215E','frasl':'\u2044','frown':'\u2322','fscr':'\uD835\uDCBB','Fscr':'\u2131','gacute':'\u01F5','gamma':'\u03B3','Gamma':'\u0393','gammad':'\u03DD','Gammad':'\u03DC','gap':'\u2A86','gbreve':'\u011F','Gbreve':'\u011E','Gcedil':'\u0122','gcirc':'\u011D','Gcirc':'\u011C','gcy':'\u0433','Gcy':'\u0413','gdot':'\u0121','Gdot':'\u0120','ge':'\u2265','gE':'\u2267','gel':'\u22DB','gEl':'\u2A8C','geq':'\u2265','geqq':'\u2267','geqslant':'\u2A7E','ges':'\u2A7E','gescc':'\u2AA9','gesdot':'\u2A80','gesdoto':'\u2A82','gesdotol':'\u2A84','gesl':'\u22DB\uFE00','gesles':'\u2A94','gfr':'\uD835\uDD24','Gfr':'\uD835\uDD0A','gg':'\u226B','Gg':'\u22D9','ggg':'\u22D9','gimel':'\u2137','gjcy':'\u0453','GJcy':'\u0403','gl':'\u2277','gla':'\u2AA5','glE':'\u2A92','glj':'\u2AA4','gnap':'\u2A8A','gnapprox':'\u2A8A','gne':'\u2A88','gnE':'\u2269','gneq':'\u2A88','gneqq':'\u2269','gnsim':'\u22E7','gopf':'\uD835\uDD58','Gopf':'\uD835\uDD3E','grave':'`','GreaterEqual':'\u2265','GreaterEqualLess':'\u22DB','GreaterFullEqual':'\u2267','GreaterGreater':'\u2AA2','GreaterLess':'\u2277','GreaterSlantEqual':'\u2A7E','GreaterTilde':'\u2273','gscr':'\u210A','Gscr':'\uD835\uDCA2','gsim':'\u2273','gsime':'\u2A8E','gsiml':'\u2A90','gt':'>','Gt':'\u226B','GT':'>','gtcc':'\u2AA7','gtcir':'\u2A7A','gtdot':'\u22D7','gtlPar':'\u2995','gtquest':'\u2A7C','gtrapprox':'\u2A86','gtrarr':'\u2978','gtrdot':'\u22D7','gtreqless':'\u22DB','gtreqqless':'\u2A8C','gtrless':'\u2277','gtrsim':'\u2273','gvertneqq':'\u2269\uFE00','gvnE':'\u2269\uFE00','Hacek':'\u02C7','hairsp':'\u200A','half':'\xBD','hamilt':'\u210B','hardcy':'\u044A','HARDcy':'\u042A','harr':'\u2194','hArr':'\u21D4','harrcir':'\u2948','harrw':'\u21AD','Hat':'^','hbar':'\u210F','hcirc':'\u0125','Hcirc':'\u0124','hearts':'\u2665','heartsuit':'\u2665','hellip':'\u2026','hercon':'\u22B9','hfr':'\uD835\uDD25','Hfr':'\u210C','HilbertSpace':'\u210B','hksearow':'\u2925','hkswarow':'\u2926','hoarr':'\u21FF','homtht':'\u223B','hookleftarrow':'\u21A9','hookrightarrow':'\u21AA','hopf':'\uD835\uDD59','Hopf':'\u210D','horbar':'\u2015','HorizontalLine':'\u2500','hscr':'\uD835\uDCBD','Hscr':'\u210B','hslash':'\u210F','hstrok':'\u0127','Hstrok':'\u0126','HumpDownHump':'\u224E','HumpEqual':'\u224F','hybull':'\u2043','hyphen':'\u2010','iacute':'\xED','Iacute':'\xCD','ic':'\u2063','icirc':'\xEE','Icirc':'\xCE','icy':'\u0438','Icy':'\u0418','Idot':'\u0130','iecy':'\u0435','IEcy':'\u0415','iexcl':'\xA1','iff':'\u21D4','ifr':'\uD835\uDD26','Ifr':'\u2111','igrave':'\xEC','Igrave':'\xCC','ii':'\u2148','iiiint':'\u2A0C','iiint':'\u222D','iinfin':'\u29DC','iiota':'\u2129','ijlig':'\u0133','IJlig':'\u0132','Im':'\u2111','imacr':'\u012B','Imacr':'\u012A','image':'\u2111','ImaginaryI':'\u2148','imagline':'\u2110','imagpart':'\u2111','imath':'\u0131','imof':'\u22B7','imped':'\u01B5','Implies':'\u21D2','in':'\u2208','incare':'\u2105','infin':'\u221E','infintie':'\u29DD','inodot':'\u0131','int':'\u222B','Int':'\u222C','intcal':'\u22BA','integers':'\u2124','Integral':'\u222B','intercal':'\u22BA','Intersection':'\u22C2','intlarhk':'\u2A17','intprod':'\u2A3C','InvisibleComma':'\u2063','InvisibleTimes':'\u2062','iocy':'\u0451','IOcy':'\u0401','iogon':'\u012F','Iogon':'\u012E','iopf':'\uD835\uDD5A','Iopf':'\uD835\uDD40','iota':'\u03B9','Iota':'\u0399','iprod':'\u2A3C','iquest':'\xBF','iscr':'\uD835\uDCBE','Iscr':'\u2110','isin':'\u2208','isindot':'\u22F5','isinE':'\u22F9','isins':'\u22F4','isinsv':'\u22F3','isinv':'\u2208','it':'\u2062','itilde':'\u0129','Itilde':'\u0128','iukcy':'\u0456','Iukcy':'\u0406','iuml':'\xEF','Iuml':'\xCF','jcirc':'\u0135','Jcirc':'\u0134','jcy':'\u0439','Jcy':'\u0419','jfr':'\uD835\uDD27','Jfr':'\uD835\uDD0D','jmath':'\u0237','jopf':'\uD835\uDD5B','Jopf':'\uD835\uDD41','jscr':'\uD835\uDCBF','Jscr':'\uD835\uDCA5','jsercy':'\u0458','Jsercy':'\u0408','jukcy':'\u0454','Jukcy':'\u0404','kappa':'\u03BA','Kappa':'\u039A','kappav':'\u03F0','kcedil':'\u0137','Kcedil':'\u0136','kcy':'\u043A','Kcy':'\u041A','kfr':'\uD835\uDD28','Kfr':'\uD835\uDD0E','kgreen':'\u0138','khcy':'\u0445','KHcy':'\u0425','kjcy':'\u045C','KJcy':'\u040C','kopf':'\uD835\uDD5C','Kopf':'\uD835\uDD42','kscr':'\uD835\uDCC0','Kscr':'\uD835\uDCA6','lAarr':'\u21DA','lacute':'\u013A','Lacute':'\u0139','laemptyv':'\u29B4','lagran':'\u2112','lambda':'\u03BB','Lambda':'\u039B','lang':'\u27E8','Lang':'\u27EA','langd':'\u2991','langle':'\u27E8','lap':'\u2A85','Laplacetrf':'\u2112','laquo':'\xAB','larr':'\u2190','lArr':'\u21D0','Larr':'\u219E','larrb':'\u21E4','larrbfs':'\u291F','larrfs':'\u291D','larrhk':'\u21A9','larrlp':'\u21AB','larrpl':'\u2939','larrsim':'\u2973','larrtl':'\u21A2','lat':'\u2AAB','latail':'\u2919','lAtail':'\u291B','late':'\u2AAD','lates':'\u2AAD\uFE00','lbarr':'\u290C','lBarr':'\u290E','lbbrk':'\u2772','lbrace':'{','lbrack':'[','lbrke':'\u298B','lbrksld':'\u298F','lbrkslu':'\u298D','lcaron':'\u013E','Lcaron':'\u013D','lcedil':'\u013C','Lcedil':'\u013B','lceil':'\u2308','lcub':'{','lcy':'\u043B','Lcy':'\u041B','ldca':'\u2936','ldquo':'\u201C','ldquor':'\u201E','ldrdhar':'\u2967','ldrushar':'\u294B','ldsh':'\u21B2','le':'\u2264','lE':'\u2266','LeftAngleBracket':'\u27E8','leftarrow':'\u2190','Leftarrow':'\u21D0','LeftArrow':'\u2190','LeftArrowBar':'\u21E4','LeftArrowRightArrow':'\u21C6','leftarrowtail':'\u21A2','LeftCeiling':'\u2308','LeftDoubleBracket':'\u27E6','LeftDownTeeVector':'\u2961','LeftDownVector':'\u21C3','LeftDownVectorBar':'\u2959','LeftFloor':'\u230A','leftharpoondown':'\u21BD','leftharpoonup':'\u21BC','leftleftarrows':'\u21C7','leftrightarrow':'\u2194','Leftrightarrow':'\u21D4','LeftRightArrow':'\u2194','leftrightarrows':'\u21C6','leftrightharpoons':'\u21CB','leftrightsquigarrow':'\u21AD','LeftRightVector':'\u294E','LeftTee':'\u22A3','LeftTeeArrow':'\u21A4','LeftTeeVector':'\u295A','leftthreetimes':'\u22CB','LeftTriangle':'\u22B2','LeftTriangleBar':'\u29CF','LeftTriangleEqual':'\u22B4','LeftUpDownVector':'\u2951','LeftUpTeeVector':'\u2960','LeftUpVector':'\u21BF','LeftUpVectorBar':'\u2958','LeftVector':'\u21BC','LeftVectorBar':'\u2952','leg':'\u22DA','lEg':'\u2A8B','leq':'\u2264','leqq':'\u2266','leqslant':'\u2A7D','les':'\u2A7D','lescc':'\u2AA8','lesdot':'\u2A7F','lesdoto':'\u2A81','lesdotor':'\u2A83','lesg':'\u22DA\uFE00','lesges':'\u2A93','lessapprox':'\u2A85','lessdot':'\u22D6','lesseqgtr':'\u22DA','lesseqqgtr':'\u2A8B','LessEqualGreater':'\u22DA','LessFullEqual':'\u2266','LessGreater':'\u2276','lessgtr':'\u2276','LessLess':'\u2AA1','lesssim':'\u2272','LessSlantEqual':'\u2A7D','LessTilde':'\u2272','lfisht':'\u297C','lfloor':'\u230A','lfr':'\uD835\uDD29','Lfr':'\uD835\uDD0F','lg':'\u2276','lgE':'\u2A91','lHar':'\u2962','lhard':'\u21BD','lharu':'\u21BC','lharul':'\u296A','lhblk':'\u2584','ljcy':'\u0459','LJcy':'\u0409','ll':'\u226A','Ll':'\u22D8','llarr':'\u21C7','llcorner':'\u231E','Lleftarrow':'\u21DA','llhard':'\u296B','lltri':'\u25FA','lmidot':'\u0140','Lmidot':'\u013F','lmoust':'\u23B0','lmoustache':'\u23B0','lnap':'\u2A89','lnapprox':'\u2A89','lne':'\u2A87','lnE':'\u2268','lneq':'\u2A87','lneqq':'\u2268','lnsim':'\u22E6','loang':'\u27EC','loarr':'\u21FD','lobrk':'\u27E6','longleftarrow':'\u27F5','Longleftarrow':'\u27F8','LongLeftArrow':'\u27F5','longleftrightarrow':'\u27F7','Longleftrightarrow':'\u27FA','LongLeftRightArrow':'\u27F7','longmapsto':'\u27FC','longrightarrow':'\u27F6','Longrightarrow':'\u27F9','LongRightArrow':'\u27F6','looparrowleft':'\u21AB','looparrowright':'\u21AC','lopar':'\u2985','lopf':'\uD835\uDD5D','Lopf':'\uD835\uDD43','loplus':'\u2A2D','lotimes':'\u2A34','lowast':'\u2217','lowbar':'_','LowerLeftArrow':'\u2199','LowerRightArrow':'\u2198','loz':'\u25CA','lozenge':'\u25CA','lozf':'\u29EB','lpar':'(','lparlt':'\u2993','lrarr':'\u21C6','lrcorner':'\u231F','lrhar':'\u21CB','lrhard':'\u296D','lrm':'\u200E','lrtri':'\u22BF','lsaquo':'\u2039','lscr':'\uD835\uDCC1','Lscr':'\u2112','lsh':'\u21B0','Lsh':'\u21B0','lsim':'\u2272','lsime':'\u2A8D','lsimg':'\u2A8F','lsqb':'[','lsquo':'\u2018','lsquor':'\u201A','lstrok':'\u0142','Lstrok':'\u0141','lt':'<','Lt':'\u226A','LT':'<','ltcc':'\u2AA6','ltcir':'\u2A79','ltdot':'\u22D6','lthree':'\u22CB','ltimes':'\u22C9','ltlarr':'\u2976','ltquest':'\u2A7B','ltri':'\u25C3','ltrie':'\u22B4','ltrif':'\u25C2','ltrPar':'\u2996','lurdshar':'\u294A','luruhar':'\u2966','lvertneqq':'\u2268\uFE00','lvnE':'\u2268\uFE00','macr':'\xAF','male':'\u2642','malt':'\u2720','maltese':'\u2720','map':'\u21A6','Map':'\u2905','mapsto':'\u21A6','mapstodown':'\u21A7','mapstoleft':'\u21A4','mapstoup':'\u21A5','marker':'\u25AE','mcomma':'\u2A29','mcy':'\u043C','Mcy':'\u041C','mdash':'\u2014','mDDot':'\u223A','measuredangle':'\u2221','MediumSpace':'\u205F','Mellintrf':'\u2133','mfr':'\uD835\uDD2A','Mfr':'\uD835\uDD10','mho':'\u2127','micro':'\xB5','mid':'\u2223','midast':'*','midcir':'\u2AF0','middot':'\xB7','minus':'\u2212','minusb':'\u229F','minusd':'\u2238','minusdu':'\u2A2A','MinusPlus':'\u2213','mlcp':'\u2ADB','mldr':'\u2026','mnplus':'\u2213','models':'\u22A7','mopf':'\uD835\uDD5E','Mopf':'\uD835\uDD44','mp':'\u2213','mscr':'\uD835\uDCC2','Mscr':'\u2133','mstpos':'\u223E','mu':'\u03BC','Mu':'\u039C','multimap':'\u22B8','mumap':'\u22B8','nabla':'\u2207','nacute':'\u0144','Nacute':'\u0143','nang':'\u2220\u20D2','nap':'\u2249','napE':'\u2A70\u0338','napid':'\u224B\u0338','napos':'\u0149','napprox':'\u2249','natur':'\u266E','natural':'\u266E','naturals':'\u2115','nbsp':'\xA0','nbump':'\u224E\u0338','nbumpe':'\u224F\u0338','ncap':'\u2A43','ncaron':'\u0148','Ncaron':'\u0147','ncedil':'\u0146','Ncedil':'\u0145','ncong':'\u2247','ncongdot':'\u2A6D\u0338','ncup':'\u2A42','ncy':'\u043D','Ncy':'\u041D','ndash':'\u2013','ne':'\u2260','nearhk':'\u2924','nearr':'\u2197','neArr':'\u21D7','nearrow':'\u2197','nedot':'\u2250\u0338','NegativeMediumSpace':'\u200B','NegativeThickSpace':'\u200B','NegativeThinSpace':'\u200B','NegativeVeryThinSpace':'\u200B','nequiv':'\u2262','nesear':'\u2928','nesim':'\u2242\u0338','NestedGreaterGreater':'\u226B','NestedLessLess':'\u226A','NewLine':'\n','nexist':'\u2204','nexists':'\u2204','nfr':'\uD835\uDD2B','Nfr':'\uD835\uDD11','nge':'\u2271','ngE':'\u2267\u0338','ngeq':'\u2271','ngeqq':'\u2267\u0338','ngeqslant':'\u2A7E\u0338','nges':'\u2A7E\u0338','nGg':'\u22D9\u0338','ngsim':'\u2275','ngt':'\u226F','nGt':'\u226B\u20D2','ngtr':'\u226F','nGtv':'\u226B\u0338','nharr':'\u21AE','nhArr':'\u21CE','nhpar':'\u2AF2','ni':'\u220B','nis':'\u22FC','nisd':'\u22FA','niv':'\u220B','njcy':'\u045A','NJcy':'\u040A','nlarr':'\u219A','nlArr':'\u21CD','nldr':'\u2025','nle':'\u2270','nlE':'\u2266\u0338','nleftarrow':'\u219A','nLeftarrow':'\u21CD','nleftrightarrow':'\u21AE','nLeftrightarrow':'\u21CE','nleq':'\u2270','nleqq':'\u2266\u0338','nleqslant':'\u2A7D\u0338','nles':'\u2A7D\u0338','nless':'\u226E','nLl':'\u22D8\u0338','nlsim':'\u2274','nlt':'\u226E','nLt':'\u226A\u20D2','nltri':'\u22EA','nltrie':'\u22EC','nLtv':'\u226A\u0338','nmid':'\u2224','NoBreak':'\u2060','NonBreakingSpace':'\xA0','nopf':'\uD835\uDD5F','Nopf':'\u2115','not':'\xAC','Not':'\u2AEC','NotCongruent':'\u2262','NotCupCap':'\u226D','NotDoubleVerticalBar':'\u2226','NotElement':'\u2209','NotEqual':'\u2260','NotEqualTilde':'\u2242\u0338','NotExists':'\u2204','NotGreater':'\u226F','NotGreaterEqual':'\u2271','NotGreaterFullEqual':'\u2267\u0338','NotGreaterGreater':'\u226B\u0338','NotGreaterLess':'\u2279','NotGreaterSlantEqual':'\u2A7E\u0338','NotGreaterTilde':'\u2275','NotHumpDownHump':'\u224E\u0338','NotHumpEqual':'\u224F\u0338','notin':'\u2209','notindot':'\u22F5\u0338','notinE':'\u22F9\u0338','notinva':'\u2209','notinvb':'\u22F7','notinvc':'\u22F6','NotLeftTriangle':'\u22EA','NotLeftTriangleBar':'\u29CF\u0338','NotLeftTriangleEqual':'\u22EC','NotLess':'\u226E','NotLessEqual':'\u2270','NotLessGreater':'\u2278','NotLessLess':'\u226A\u0338','NotLessSlantEqual':'\u2A7D\u0338','NotLessTilde':'\u2274','NotNestedGreaterGreater':'\u2AA2\u0338','NotNestedLessLess':'\u2AA1\u0338','notni':'\u220C','notniva':'\u220C','notnivb':'\u22FE','notnivc':'\u22FD','NotPrecedes':'\u2280','NotPrecedesEqual':'\u2AAF\u0338','NotPrecedesSlantEqual':'\u22E0','NotReverseElement':'\u220C','NotRightTriangle':'\u22EB','NotRightTriangleBar':'\u29D0\u0338','NotRightTriangleEqual':'\u22ED','NotSquareSubset':'\u228F\u0338','NotSquareSubsetEqual':'\u22E2','NotSquareSuperset':'\u2290\u0338','NotSquareSupersetEqual':'\u22E3','NotSubset':'\u2282\u20D2','NotSubsetEqual':'\u2288','NotSucceeds':'\u2281','NotSucceedsEqual':'\u2AB0\u0338','NotSucceedsSlantEqual':'\u22E1','NotSucceedsTilde':'\u227F\u0338','NotSuperset':'\u2283\u20D2','NotSupersetEqual':'\u2289','NotTilde':'\u2241','NotTildeEqual':'\u2244','NotTildeFullEqual':'\u2247','NotTildeTilde':'\u2249','NotVerticalBar':'\u2224','npar':'\u2226','nparallel':'\u2226','nparsl':'\u2AFD\u20E5','npart':'\u2202\u0338','npolint':'\u2A14','npr':'\u2280','nprcue':'\u22E0','npre':'\u2AAF\u0338','nprec':'\u2280','npreceq':'\u2AAF\u0338','nrarr':'\u219B','nrArr':'\u21CF','nrarrc':'\u2933\u0338','nrarrw':'\u219D\u0338','nrightarrow':'\u219B','nRightarrow':'\u21CF','nrtri':'\u22EB','nrtrie':'\u22ED','nsc':'\u2281','nsccue':'\u22E1','nsce':'\u2AB0\u0338','nscr':'\uD835\uDCC3','Nscr':'\uD835\uDCA9','nshortmid':'\u2224','nshortparallel':'\u2226','nsim':'\u2241','nsime':'\u2244','nsimeq':'\u2244','nsmid':'\u2224','nspar':'\u2226','nsqsube':'\u22E2','nsqsupe':'\u22E3','nsub':'\u2284','nsube':'\u2288','nsubE':'\u2AC5\u0338','nsubset':'\u2282\u20D2','nsubseteq':'\u2288','nsubseteqq':'\u2AC5\u0338','nsucc':'\u2281','nsucceq':'\u2AB0\u0338','nsup':'\u2285','nsupe':'\u2289','nsupE':'\u2AC6\u0338','nsupset':'\u2283\u20D2','nsupseteq':'\u2289','nsupseteqq':'\u2AC6\u0338','ntgl':'\u2279','ntilde':'\xF1','Ntilde':'\xD1','ntlg':'\u2278','ntriangleleft':'\u22EA','ntrianglelefteq':'\u22EC','ntriangleright':'\u22EB','ntrianglerighteq':'\u22ED','nu':'\u03BD','Nu':'\u039D','num':'#','numero':'\u2116','numsp':'\u2007','nvap':'\u224D\u20D2','nvdash':'\u22AC','nvDash':'\u22AD','nVdash':'\u22AE','nVDash':'\u22AF','nvge':'\u2265\u20D2','nvgt':'>\u20D2','nvHarr':'\u2904','nvinfin':'\u29DE','nvlArr':'\u2902','nvle':'\u2264\u20D2','nvlt':'<\u20D2','nvltrie':'\u22B4\u20D2','nvrArr':'\u2903','nvrtrie':'\u22B5\u20D2','nvsim':'\u223C\u20D2','nwarhk':'\u2923','nwarr':'\u2196','nwArr':'\u21D6','nwarrow':'\u2196','nwnear':'\u2927','oacute':'\xF3','Oacute':'\xD3','oast':'\u229B','ocir':'\u229A','ocirc':'\xF4','Ocirc':'\xD4','ocy':'\u043E','Ocy':'\u041E','odash':'\u229D','odblac':'\u0151','Odblac':'\u0150','odiv':'\u2A38','odot':'\u2299','odsold':'\u29BC','oelig':'\u0153','OElig':'\u0152','ofcir':'\u29BF','ofr':'\uD835\uDD2C','Ofr':'\uD835\uDD12','ogon':'\u02DB','ograve':'\xF2','Ograve':'\xD2','ogt':'\u29C1','ohbar':'\u29B5','ohm':'\u03A9','oint':'\u222E','olarr':'\u21BA','olcir':'\u29BE','olcross':'\u29BB','oline':'\u203E','olt':'\u29C0','omacr':'\u014D','Omacr':'\u014C','omega':'\u03C9','Omega':'\u03A9','omicron':'\u03BF','Omicron':'\u039F','omid':'\u29B6','ominus':'\u2296','oopf':'\uD835\uDD60','Oopf':'\uD835\uDD46','opar':'\u29B7','OpenCurlyDoubleQuote':'\u201C','OpenCurlyQuote':'\u2018','operp':'\u29B9','oplus':'\u2295','or':'\u2228','Or':'\u2A54','orarr':'\u21BB','ord':'\u2A5D','order':'\u2134','orderof':'\u2134','ordf':'\xAA','ordm':'\xBA','origof':'\u22B6','oror':'\u2A56','orslope':'\u2A57','orv':'\u2A5B','oS':'\u24C8','oscr':'\u2134','Oscr':'\uD835\uDCAA','oslash':'\xF8','Oslash':'\xD8','osol':'\u2298','otilde':'\xF5','Otilde':'\xD5','otimes':'\u2297','Otimes':'\u2A37','otimesas':'\u2A36','ouml':'\xF6','Ouml':'\xD6','ovbar':'\u233D','OverBar':'\u203E','OverBrace':'\u23DE','OverBracket':'\u23B4','OverParenthesis':'\u23DC','par':'\u2225','para':'\xB6','parallel':'\u2225','parsim':'\u2AF3','parsl':'\u2AFD','part':'\u2202','PartialD':'\u2202','pcy':'\u043F','Pcy':'\u041F','percnt':'%','period':'.','permil':'\u2030','perp':'\u22A5','pertenk':'\u2031','pfr':'\uD835\uDD2D','Pfr':'\uD835\uDD13','phi':'\u03C6','Phi':'\u03A6','phiv':'\u03D5','phmmat':'\u2133','phone':'\u260E','pi':'\u03C0','Pi':'\u03A0','pitchfork':'\u22D4','piv':'\u03D6','planck':'\u210F','planckh':'\u210E','plankv':'\u210F','plus':'+','plusacir':'\u2A23','plusb':'\u229E','pluscir':'\u2A22','plusdo':'\u2214','plusdu':'\u2A25','pluse':'\u2A72','PlusMinus':'\xB1','plusmn':'\xB1','plussim':'\u2A26','plustwo':'\u2A27','pm':'\xB1','Poincareplane':'\u210C','pointint':'\u2A15','popf':'\uD835\uDD61','Popf':'\u2119','pound':'\xA3','pr':'\u227A','Pr':'\u2ABB','prap':'\u2AB7','prcue':'\u227C','pre':'\u2AAF','prE':'\u2AB3','prec':'\u227A','precapprox':'\u2AB7','preccurlyeq':'\u227C','Precedes':'\u227A','PrecedesEqual':'\u2AAF','PrecedesSlantEqual':'\u227C','PrecedesTilde':'\u227E','preceq':'\u2AAF','precnapprox':'\u2AB9','precneqq':'\u2AB5','precnsim':'\u22E8','precsim':'\u227E','prime':'\u2032','Prime':'\u2033','primes':'\u2119','prnap':'\u2AB9','prnE':'\u2AB5','prnsim':'\u22E8','prod':'\u220F','Product':'\u220F','profalar':'\u232E','profline':'\u2312','profsurf':'\u2313','prop':'\u221D','Proportion':'\u2237','Proportional':'\u221D','propto':'\u221D','prsim':'\u227E','prurel':'\u22B0','pscr':'\uD835\uDCC5','Pscr':'\uD835\uDCAB','psi':'\u03C8','Psi':'\u03A8','puncsp':'\u2008','qfr':'\uD835\uDD2E','Qfr':'\uD835\uDD14','qint':'\u2A0C','qopf':'\uD835\uDD62','Qopf':'\u211A','qprime':'\u2057','qscr':'\uD835\uDCC6','Qscr':'\uD835\uDCAC','quaternions':'\u210D','quatint':'\u2A16','quest':'?','questeq':'\u225F','quot':'"','QUOT':'"','rAarr':'\u21DB','race':'\u223D\u0331','racute':'\u0155','Racute':'\u0154','radic':'\u221A','raemptyv':'\u29B3','rang':'\u27E9','Rang':'\u27EB','rangd':'\u2992','range':'\u29A5','rangle':'\u27E9','raquo':'\xBB','rarr':'\u2192','rArr':'\u21D2','Rarr':'\u21A0','rarrap':'\u2975','rarrb':'\u21E5','rarrbfs':'\u2920','rarrc':'\u2933','rarrfs':'\u291E','rarrhk':'\u21AA','rarrlp':'\u21AC','rarrpl':'\u2945','rarrsim':'\u2974','rarrtl':'\u21A3','Rarrtl':'\u2916','rarrw':'\u219D','ratail':'\u291A','rAtail':'\u291C','ratio':'\u2236','rationals':'\u211A','rbarr':'\u290D','rBarr':'\u290F','RBarr':'\u2910','rbbrk':'\u2773','rbrace':'}','rbrack':']','rbrke':'\u298C','rbrksld':'\u298E','rbrkslu':'\u2990','rcaron':'\u0159','Rcaron':'\u0158','rcedil':'\u0157','Rcedil':'\u0156','rceil':'\u2309','rcub':'}','rcy':'\u0440','Rcy':'\u0420','rdca':'\u2937','rdldhar':'\u2969','rdquo':'\u201D','rdquor':'\u201D','rdsh':'\u21B3','Re':'\u211C','real':'\u211C','realine':'\u211B','realpart':'\u211C','reals':'\u211D','rect':'\u25AD','reg':'\xAE','REG':'\xAE','ReverseElement':'\u220B','ReverseEquilibrium':'\u21CB','ReverseUpEquilibrium':'\u296F','rfisht':'\u297D','rfloor':'\u230B','rfr':'\uD835\uDD2F','Rfr':'\u211C','rHar':'\u2964','rhard':'\u21C1','rharu':'\u21C0','rharul':'\u296C','rho':'\u03C1','Rho':'\u03A1','rhov':'\u03F1','RightAngleBracket':'\u27E9','rightarrow':'\u2192','Rightarrow':'\u21D2','RightArrow':'\u2192','RightArrowBar':'\u21E5','RightArrowLeftArrow':'\u21C4','rightarrowtail':'\u21A3','RightCeiling':'\u2309','RightDoubleBracket':'\u27E7','RightDownTeeVector':'\u295D','RightDownVector':'\u21C2','RightDownVectorBar':'\u2955','RightFloor':'\u230B','rightharpoondown':'\u21C1','rightharpoonup':'\u21C0','rightleftarrows':'\u21C4','rightleftharpoons':'\u21CC','rightrightarrows':'\u21C9','rightsquigarrow':'\u219D','RightTee':'\u22A2','RightTeeArrow':'\u21A6','RightTeeVector':'\u295B','rightthreetimes':'\u22CC','RightTriangle':'\u22B3','RightTriangleBar':'\u29D0','RightTriangleEqual':'\u22B5','RightUpDownVector':'\u294F','RightUpTeeVector':'\u295C','RightUpVector':'\u21BE','RightUpVectorBar':'\u2954','RightVector':'\u21C0','RightVectorBar':'\u2953','ring':'\u02DA','risingdotseq':'\u2253','rlarr':'\u21C4','rlhar':'\u21CC','rlm':'\u200F','rmoust':'\u23B1','rmoustache':'\u23B1','rnmid':'\u2AEE','roang':'\u27ED','roarr':'\u21FE','robrk':'\u27E7','ropar':'\u2986','ropf':'\uD835\uDD63','Ropf':'\u211D','roplus':'\u2A2E','rotimes':'\u2A35','RoundImplies':'\u2970','rpar':')','rpargt':'\u2994','rppolint':'\u2A12','rrarr':'\u21C9','Rrightarrow':'\u21DB','rsaquo':'\u203A','rscr':'\uD835\uDCC7','Rscr':'\u211B','rsh':'\u21B1','Rsh':'\u21B1','rsqb':']','rsquo':'\u2019','rsquor':'\u2019','rthree':'\u22CC','rtimes':'\u22CA','rtri':'\u25B9','rtrie':'\u22B5','rtrif':'\u25B8','rtriltri':'\u29CE','RuleDelayed':'\u29F4','ruluhar':'\u2968','rx':'\u211E','sacute':'\u015B','Sacute':'\u015A','sbquo':'\u201A','sc':'\u227B','Sc':'\u2ABC','scap':'\u2AB8','scaron':'\u0161','Scaron':'\u0160','sccue':'\u227D','sce':'\u2AB0','scE':'\u2AB4','scedil':'\u015F','Scedil':'\u015E','scirc':'\u015D','Scirc':'\u015C','scnap':'\u2ABA','scnE':'\u2AB6','scnsim':'\u22E9','scpolint':'\u2A13','scsim':'\u227F','scy':'\u0441','Scy':'\u0421','sdot':'\u22C5','sdotb':'\u22A1','sdote':'\u2A66','searhk':'\u2925','searr':'\u2198','seArr':'\u21D8','searrow':'\u2198','sect':'\xA7','semi':';','seswar':'\u2929','setminus':'\u2216','setmn':'\u2216','sext':'\u2736','sfr':'\uD835\uDD30','Sfr':'\uD835\uDD16','sfrown':'\u2322','sharp':'\u266F','shchcy':'\u0449','SHCHcy':'\u0429','shcy':'\u0448','SHcy':'\u0428','ShortDownArrow':'\u2193','ShortLeftArrow':'\u2190','shortmid':'\u2223','shortparallel':'\u2225','ShortRightArrow':'\u2192','ShortUpArrow':'\u2191','shy':'\xAD','sigma':'\u03C3','Sigma':'\u03A3','sigmaf':'\u03C2','sigmav':'\u03C2','sim':'\u223C','simdot':'\u2A6A','sime':'\u2243','simeq':'\u2243','simg':'\u2A9E','simgE':'\u2AA0','siml':'\u2A9D','simlE':'\u2A9F','simne':'\u2246','simplus':'\u2A24','simrarr':'\u2972','slarr':'\u2190','SmallCircle':'\u2218','smallsetminus':'\u2216','smashp':'\u2A33','smeparsl':'\u29E4','smid':'\u2223','smile':'\u2323','smt':'\u2AAA','smte':'\u2AAC','smtes':'\u2AAC\uFE00','softcy':'\u044C','SOFTcy':'\u042C','sol':'/','solb':'\u29C4','solbar':'\u233F','sopf':'\uD835\uDD64','Sopf':'\uD835\uDD4A','spades':'\u2660','spadesuit':'\u2660','spar':'\u2225','sqcap':'\u2293','sqcaps':'\u2293\uFE00','sqcup':'\u2294','sqcups':'\u2294\uFE00','Sqrt':'\u221A','sqsub':'\u228F','sqsube':'\u2291','sqsubset':'\u228F','sqsubseteq':'\u2291','sqsup':'\u2290','sqsupe':'\u2292','sqsupset':'\u2290','sqsupseteq':'\u2292','squ':'\u25A1','square':'\u25A1','Square':'\u25A1','SquareIntersection':'\u2293','SquareSubset':'\u228F','SquareSubsetEqual':'\u2291','SquareSuperset':'\u2290','SquareSupersetEqual':'\u2292','SquareUnion':'\u2294','squarf':'\u25AA','squf':'\u25AA','srarr':'\u2192','sscr':'\uD835\uDCC8','Sscr':'\uD835\uDCAE','ssetmn':'\u2216','ssmile':'\u2323','sstarf':'\u22C6','star':'\u2606','Star':'\u22C6','starf':'\u2605','straightepsilon':'\u03F5','straightphi':'\u03D5','strns':'\xAF','sub':'\u2282','Sub':'\u22D0','subdot':'\u2ABD','sube':'\u2286','subE':'\u2AC5','subedot':'\u2AC3','submult':'\u2AC1','subne':'\u228A','subnE':'\u2ACB','subplus':'\u2ABF','subrarr':'\u2979','subset':'\u2282','Subset':'\u22D0','subseteq':'\u2286','subseteqq':'\u2AC5','SubsetEqual':'\u2286','subsetneq':'\u228A','subsetneqq':'\u2ACB','subsim':'\u2AC7','subsub':'\u2AD5','subsup':'\u2AD3','succ':'\u227B','succapprox':'\u2AB8','succcurlyeq':'\u227D','Succeeds':'\u227B','SucceedsEqual':'\u2AB0','SucceedsSlantEqual':'\u227D','SucceedsTilde':'\u227F','succeq':'\u2AB0','succnapprox':'\u2ABA','succneqq':'\u2AB6','succnsim':'\u22E9','succsim':'\u227F','SuchThat':'\u220B','sum':'\u2211','Sum':'\u2211','sung':'\u266A','sup':'\u2283','Sup':'\u22D1','sup1':'\xB9','sup2':'\xB2','sup3':'\xB3','supdot':'\u2ABE','supdsub':'\u2AD8','supe':'\u2287','supE':'\u2AC6','supedot':'\u2AC4','Superset':'\u2283','SupersetEqual':'\u2287','suphsol':'\u27C9','suphsub':'\u2AD7','suplarr':'\u297B','supmult':'\u2AC2','supne':'\u228B','supnE':'\u2ACC','supplus':'\u2AC0','supset':'\u2283','Supset':'\u22D1','supseteq':'\u2287','supseteqq':'\u2AC6','supsetneq':'\u228B','supsetneqq':'\u2ACC','supsim':'\u2AC8','supsub':'\u2AD4','supsup':'\u2AD6','swarhk':'\u2926','swarr':'\u2199','swArr':'\u21D9','swarrow':'\u2199','swnwar':'\u292A','szlig':'\xDF','Tab':'\t','target':'\u2316','tau':'\u03C4','Tau':'\u03A4','tbrk':'\u23B4','tcaron':'\u0165','Tcaron':'\u0164','tcedil':'\u0163','Tcedil':'\u0162','tcy':'\u0442','Tcy':'\u0422','tdot':'\u20DB','telrec':'\u2315','tfr':'\uD835\uDD31','Tfr':'\uD835\uDD17','there4':'\u2234','therefore':'\u2234','Therefore':'\u2234','theta':'\u03B8','Theta':'\u0398','thetasym':'\u03D1','thetav':'\u03D1','thickapprox':'\u2248','thicksim':'\u223C','ThickSpace':'\u205F\u200A','thinsp':'\u2009','ThinSpace':'\u2009','thkap':'\u2248','thksim':'\u223C','thorn':'\xFE','THORN':'\xDE','tilde':'\u02DC','Tilde':'\u223C','TildeEqual':'\u2243','TildeFullEqual':'\u2245','TildeTilde':'\u2248','times':'\xD7','timesb':'\u22A0','timesbar':'\u2A31','timesd':'\u2A30','tint':'\u222D','toea':'\u2928','top':'\u22A4','topbot':'\u2336','topcir':'\u2AF1','topf':'\uD835\uDD65','Topf':'\uD835\uDD4B','topfork':'\u2ADA','tosa':'\u2929','tprime':'\u2034','trade':'\u2122','TRADE':'\u2122','triangle':'\u25B5','triangledown':'\u25BF','triangleleft':'\u25C3','trianglelefteq':'\u22B4','triangleq':'\u225C','triangleright':'\u25B9','trianglerighteq':'\u22B5','tridot':'\u25EC','trie':'\u225C','triminus':'\u2A3A','TripleDot':'\u20DB','triplus':'\u2A39','trisb':'\u29CD','tritime':'\u2A3B','trpezium':'\u23E2','tscr':'\uD835\uDCC9','Tscr':'\uD835\uDCAF','tscy':'\u0446','TScy':'\u0426','tshcy':'\u045B','TSHcy':'\u040B','tstrok':'\u0167','Tstrok':'\u0166','twixt':'\u226C','twoheadleftarrow':'\u219E','twoheadrightarrow':'\u21A0','uacute':'\xFA','Uacute':'\xDA','uarr':'\u2191','uArr':'\u21D1','Uarr':'\u219F','Uarrocir':'\u2949','ubrcy':'\u045E','Ubrcy':'\u040E','ubreve':'\u016D','Ubreve':'\u016C','ucirc':'\xFB','Ucirc':'\xDB','ucy':'\u0443','Ucy':'\u0423','udarr':'\u21C5','udblac':'\u0171','Udblac':'\u0170','udhar':'\u296E','ufisht':'\u297E','ufr':'\uD835\uDD32','Ufr':'\uD835\uDD18','ugrave':'\xF9','Ugrave':'\xD9','uHar':'\u2963','uharl':'\u21BF','uharr':'\u21BE','uhblk':'\u2580','ulcorn':'\u231C','ulcorner':'\u231C','ulcrop':'\u230F','ultri':'\u25F8','umacr':'\u016B','Umacr':'\u016A','uml':'\xA8','UnderBar':'_','UnderBrace':'\u23DF','UnderBracket':'\u23B5','UnderParenthesis':'\u23DD','Union':'\u22C3','UnionPlus':'\u228E','uogon':'\u0173','Uogon':'\u0172','uopf':'\uD835\uDD66','Uopf':'\uD835\uDD4C','uparrow':'\u2191','Uparrow':'\u21D1','UpArrow':'\u2191','UpArrowBar':'\u2912','UpArrowDownArrow':'\u21C5','updownarrow':'\u2195','Updownarrow':'\u21D5','UpDownArrow':'\u2195','UpEquilibrium':'\u296E','upharpoonleft':'\u21BF','upharpoonright':'\u21BE','uplus':'\u228E','UpperLeftArrow':'\u2196','UpperRightArrow':'\u2197','upsi':'\u03C5','Upsi':'\u03D2','upsih':'\u03D2','upsilon':'\u03C5','Upsilon':'\u03A5','UpTee':'\u22A5','UpTeeArrow':'\u21A5','upuparrows':'\u21C8','urcorn':'\u231D','urcorner':'\u231D','urcrop':'\u230E','uring':'\u016F','Uring':'\u016E','urtri':'\u25F9','uscr':'\uD835\uDCCA','Uscr':'\uD835\uDCB0','utdot':'\u22F0','utilde':'\u0169','Utilde':'\u0168','utri':'\u25B5','utrif':'\u25B4','uuarr':'\u21C8','uuml':'\xFC','Uuml':'\xDC','uwangle':'\u29A7','vangrt':'\u299C','varepsilon':'\u03F5','varkappa':'\u03F0','varnothing':'\u2205','varphi':'\u03D5','varpi':'\u03D6','varpropto':'\u221D','varr':'\u2195','vArr':'\u21D5','varrho':'\u03F1','varsigma':'\u03C2','varsubsetneq':'\u228A\uFE00','varsubsetneqq':'\u2ACB\uFE00','varsupsetneq':'\u228B\uFE00','varsupsetneqq':'\u2ACC\uFE00','vartheta':'\u03D1','vartriangleleft':'\u22B2','vartriangleright':'\u22B3','vBar':'\u2AE8','Vbar':'\u2AEB','vBarv':'\u2AE9','vcy':'\u0432','Vcy':'\u0412','vdash':'\u22A2','vDash':'\u22A8','Vdash':'\u22A9','VDash':'\u22AB','Vdashl':'\u2AE6','vee':'\u2228','Vee':'\u22C1','veebar':'\u22BB','veeeq':'\u225A','vellip':'\u22EE','verbar':'|','Verbar':'\u2016','vert':'|','Vert':'\u2016','VerticalBar':'\u2223','VerticalLine':'|','VerticalSeparator':'\u2758','VerticalTilde':'\u2240','VeryThinSpace':'\u200A','vfr':'\uD835\uDD33','Vfr':'\uD835\uDD19','vltri':'\u22B2','vnsub':'\u2282\u20D2','vnsup':'\u2283\u20D2','vopf':'\uD835\uDD67','Vopf':'\uD835\uDD4D','vprop':'\u221D','vrtri':'\u22B3','vscr':'\uD835\uDCCB','Vscr':'\uD835\uDCB1','vsubne':'\u228A\uFE00','vsubnE':'\u2ACB\uFE00','vsupne':'\u228B\uFE00','vsupnE':'\u2ACC\uFE00','Vvdash':'\u22AA','vzigzag':'\u299A','wcirc':'\u0175','Wcirc':'\u0174','wedbar':'\u2A5F','wedge':'\u2227','Wedge':'\u22C0','wedgeq':'\u2259','weierp':'\u2118','wfr':'\uD835\uDD34','Wfr':'\uD835\uDD1A','wopf':'\uD835\uDD68','Wopf':'\uD835\uDD4E','wp':'\u2118','wr':'\u2240','wreath':'\u2240','wscr':'\uD835\uDCCC','Wscr':'\uD835\uDCB2','xcap':'\u22C2','xcirc':'\u25EF','xcup':'\u22C3','xdtri':'\u25BD','xfr':'\uD835\uDD35','Xfr':'\uD835\uDD1B','xharr':'\u27F7','xhArr':'\u27FA','xi':'\u03BE','Xi':'\u039E','xlarr':'\u27F5','xlArr':'\u27F8','xmap':'\u27FC','xnis':'\u22FB','xodot':'\u2A00','xopf':'\uD835\uDD69','Xopf':'\uD835\uDD4F','xoplus':'\u2A01','xotime':'\u2A02','xrarr':'\u27F6','xrArr':'\u27F9','xscr':'\uD835\uDCCD','Xscr':'\uD835\uDCB3','xsqcup':'\u2A06','xuplus':'\u2A04','xutri':'\u25B3','xvee':'\u22C1','xwedge':'\u22C0','yacute':'\xFD','Yacute':'\xDD','yacy':'\u044F','YAcy':'\u042F','ycirc':'\u0177','Ycirc':'\u0176','ycy':'\u044B','Ycy':'\u042B','yen':'\xA5','yfr':'\uD835\uDD36','Yfr':'\uD835\uDD1C','yicy':'\u0457','YIcy':'\u0407','yopf':'\uD835\uDD6A','Yopf':'\uD835\uDD50','yscr':'\uD835\uDCCE','Yscr':'\uD835\uDCB4','yucy':'\u044E','YUcy':'\u042E','yuml':'\xFF','Yuml':'\u0178','zacute':'\u017A','Zacute':'\u0179','zcaron':'\u017E','Zcaron':'\u017D','zcy':'\u0437','Zcy':'\u0417','zdot':'\u017C','Zdot':'\u017B','zeetrf':'\u2128','ZeroWidthSpace':'\u200B','zeta':'\u03B6','Zeta':'\u0396','zfr':'\uD835\uDD37','Zfr':'\u2128','zhcy':'\u0436','ZHcy':'\u0416','zigrarr':'\u21DD','zopf':'\uD835\uDD6B','Zopf':'\u2124','zscr':'\uD835\uDCCF','Zscr':'\uD835\uDCB5','zwj':'\u200D','zwnj':'\u200C'}; - var decodeMapLegacy = {'aacute':'\xE1','Aacute':'\xC1','acirc':'\xE2','Acirc':'\xC2','acute':'\xB4','aelig':'\xE6','AElig':'\xC6','agrave':'\xE0','Agrave':'\xC0','amp':'&','AMP':'&','aring':'\xE5','Aring':'\xC5','atilde':'\xE3','Atilde':'\xC3','auml':'\xE4','Auml':'\xC4','brvbar':'\xA6','ccedil':'\xE7','Ccedil':'\xC7','cedil':'\xB8','cent':'\xA2','copy':'\xA9','COPY':'\xA9','curren':'\xA4','deg':'\xB0','divide':'\xF7','eacute':'\xE9','Eacute':'\xC9','ecirc':'\xEA','Ecirc':'\xCA','egrave':'\xE8','Egrave':'\xC8','eth':'\xF0','ETH':'\xD0','euml':'\xEB','Euml':'\xCB','frac12':'\xBD','frac14':'\xBC','frac34':'\xBE','gt':'>','GT':'>','iacute':'\xED','Iacute':'\xCD','icirc':'\xEE','Icirc':'\xCE','iexcl':'\xA1','igrave':'\xEC','Igrave':'\xCC','iquest':'\xBF','iuml':'\xEF','Iuml':'\xCF','laquo':'\xAB','lt':'<','LT':'<','macr':'\xAF','micro':'\xB5','middot':'\xB7','nbsp':'\xA0','not':'\xAC','ntilde':'\xF1','Ntilde':'\xD1','oacute':'\xF3','Oacute':'\xD3','ocirc':'\xF4','Ocirc':'\xD4','ograve':'\xF2','Ograve':'\xD2','ordf':'\xAA','ordm':'\xBA','oslash':'\xF8','Oslash':'\xD8','otilde':'\xF5','Otilde':'\xD5','ouml':'\xF6','Ouml':'\xD6','para':'\xB6','plusmn':'\xB1','pound':'\xA3','quot':'"','QUOT':'"','raquo':'\xBB','reg':'\xAE','REG':'\xAE','sect':'\xA7','shy':'\xAD','sup1':'\xB9','sup2':'\xB2','sup3':'\xB3','szlig':'\xDF','thorn':'\xFE','THORN':'\xDE','times':'\xD7','uacute':'\xFA','Uacute':'\xDA','ucirc':'\xFB','Ucirc':'\xDB','ugrave':'\xF9','Ugrave':'\xD9','uml':'\xA8','uuml':'\xFC','Uuml':'\xDC','yacute':'\xFD','Yacute':'\xDD','yen':'\xA5','yuml':'\xFF'}; - var decodeMapNumeric = {'0':'\uFFFD','128':'\u20AC','130':'\u201A','131':'\u0192','132':'\u201E','133':'\u2026','134':'\u2020','135':'\u2021','136':'\u02C6','137':'\u2030','138':'\u0160','139':'\u2039','140':'\u0152','142':'\u017D','145':'\u2018','146':'\u2019','147':'\u201C','148':'\u201D','149':'\u2022','150':'\u2013','151':'\u2014','152':'\u02DC','153':'\u2122','154':'\u0161','155':'\u203A','156':'\u0153','158':'\u017E','159':'\u0178'}; - var invalidReferenceCodePoints = [1,2,3,4,5,6,7,8,11,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,64976,64977,64978,64979,64980,64981,64982,64983,64984,64985,64986,64987,64988,64989,64990,64991,64992,64993,64994,64995,64996,64997,64998,64999,65000,65001,65002,65003,65004,65005,65006,65007,65534,65535,131070,131071,196606,196607,262142,262143,327678,327679,393214,393215,458750,458751,524286,524287,589822,589823,655358,655359,720894,720895,786430,786431,851966,851967,917502,917503,983038,983039,1048574,1048575,1114110,1114111]; - - /*--------------------------------------------------------------------------*/ - - var stringFromCharCode = String.fromCharCode; - - var object = {}; - var hasOwnProperty = object.hasOwnProperty; - var has = function(object, propertyName) { - return hasOwnProperty.call(object, propertyName); - }; - - var contains = function(array, value) { - var index = -1; - var length = array.length; - while (++index < length) { - if (array[index] == value) { - return true; - } - } - return false; - }; - - var merge = function(options, defaults) { - if (!options) { - return defaults; - } - var result = {}; - var key; - for (key in defaults) { - // A `hasOwnProperty` check is not needed here, since only recognized - // option names are used anyway. Any others are ignored. - result[key] = has(options, key) ? options[key] : defaults[key]; - } - return result; - }; - - // Modified version of `ucs2encode`; see https://mths.be/punycode. - var codePointToSymbol = function(codePoint, strict) { - var output = ''; - if ((codePoint >= 0xD800 && codePoint <= 0xDFFF) || codePoint > 0x10FFFF) { - // See issue #4: - // “Otherwise, if the number is in the range 0xD800 to 0xDFFF or is - // greater than 0x10FFFF, then this is a parse error. Return a U+FFFD - // REPLACEMENT CHARACTER.” - if (strict) { - parseError('character reference outside the permissible Unicode range'); - } - return '\uFFFD'; - } - if (has(decodeMapNumeric, codePoint)) { - if (strict) { - parseError('disallowed character reference'); - } - return decodeMapNumeric[codePoint]; - } - if (strict && contains(invalidReferenceCodePoints, codePoint)) { - parseError('disallowed character reference'); - } - if (codePoint > 0xFFFF) { - codePoint -= 0x10000; - output += stringFromCharCode(codePoint >>> 10 & 0x3FF | 0xD800); - codePoint = 0xDC00 | codePoint & 0x3FF; - } - output += stringFromCharCode(codePoint); - return output; - }; - - var hexEscape = function(codePoint) { - return '&#x' + codePoint.toString(16).toUpperCase() + ';'; - }; - - var decEscape = function(codePoint) { - return '&#' + codePoint + ';'; - }; - - var parseError = function(message) { - throw Error('Parse error: ' + message); - }; - - /*--------------------------------------------------------------------------*/ - - var encode = function(string, options) { - options = merge(options, encode.options); - var strict = options.strict; - if (strict && regexInvalidRawCodePoint.test(string)) { - parseError('forbidden code point'); - } - var encodeEverything = options.encodeEverything; - var useNamedReferences = options.useNamedReferences; - var allowUnsafeSymbols = options.allowUnsafeSymbols; - var escapeCodePoint = options.decimal ? decEscape : hexEscape; - - var escapeBmpSymbol = function(symbol) { - return escapeCodePoint(symbol.charCodeAt(0)); - }; - - if (encodeEverything) { - // Encode ASCII symbols. - string = string.replace(regexAsciiWhitelist, function(symbol) { - // Use named references if requested & possible. - if (useNamedReferences && has(encodeMap, symbol)) { - return '&' + encodeMap[symbol] + ';'; - } - return escapeBmpSymbol(symbol); - }); - // Shorten a few escapes that represent two symbols, of which at least one - // is within the ASCII range. - if (useNamedReferences) { - string = string - .replace(/>\u20D2/g, '>⃒') - .replace(/<\u20D2/g, '<⃒') - .replace(/fj/g, 'fj'); - } - // Encode non-ASCII symbols. - if (useNamedReferences) { - // Encode non-ASCII symbols that can be replaced with a named reference. - string = string.replace(regexEncodeNonAscii, function(string) { - // Note: there is no need to check `has(encodeMap, string)` here. - return '&' + encodeMap[string] + ';'; - }); - } - // Note: any remaining non-ASCII symbols are handled outside of the `if`. - } else if (useNamedReferences) { - // Apply named character references. - // Encode `<>"'&` using named character references. - if (!allowUnsafeSymbols) { - string = string.replace(regexEscape, function(string) { - return '&' + encodeMap[string] + ';'; // no need to check `has()` here - }); - } - // Shorten escapes that represent two symbols, of which at least one is - // `<>"'&`. - string = string - .replace(/>\u20D2/g, '>⃒') - .replace(/<\u20D2/g, '<⃒'); - // Encode non-ASCII symbols that can be replaced with a named reference. - string = string.replace(regexEncodeNonAscii, function(string) { - // Note: there is no need to check `has(encodeMap, string)` here. - return '&' + encodeMap[string] + ';'; - }); - } else if (!allowUnsafeSymbols) { - // Encode `<>"'&` using hexadecimal escapes, now that they’re not handled - // using named character references. - string = string.replace(regexEscape, escapeBmpSymbol); - } - return string - // Encode astral symbols. - .replace(regexAstralSymbols, function($0) { - // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae - var high = $0.charCodeAt(0); - var low = $0.charCodeAt(1); - var codePoint = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000; - return escapeCodePoint(codePoint); - }) - // Encode any remaining BMP symbols that are not printable ASCII symbols - // using a hexadecimal escape. - .replace(regexBmpWhitelist, escapeBmpSymbol); - }; - // Expose default options (so they can be overridden globally). - encode.options = { - 'allowUnsafeSymbols': false, - 'encodeEverything': false, - 'strict': false, - 'useNamedReferences': false, - 'decimal' : false - }; - - var decode = function(html, options) { - options = merge(options, decode.options); - var strict = options.strict; - if (strict && regexInvalidEntity.test(html)) { - parseError('malformed character reference'); - } - return html.replace(regexDecode, function($0, $1, $2, $3, $4, $5, $6, $7) { - var codePoint; - var semicolon; - var decDigits; - var hexDigits; - var reference; - var next; - if ($1) { - // Decode decimal escapes, e.g. `𝌆`. - decDigits = $1; - semicolon = $2; - if (strict && !semicolon) { - parseError('character reference was not terminated by a semicolon'); - } - codePoint = parseInt(decDigits, 10); - return codePointToSymbol(codePoint, strict); - } - if ($3) { - // Decode hexadecimal escapes, e.g. `𝌆`. - hexDigits = $3; - semicolon = $4; - if (strict && !semicolon) { - parseError('character reference was not terminated by a semicolon'); - } - codePoint = parseInt(hexDigits, 16); - return codePointToSymbol(codePoint, strict); - } - if ($5) { - // Decode named character references with trailing `;`, e.g. `©`. - reference = $5; - if (has(decodeMap, reference)) { - return decodeMap[reference]; - } else { - // Ambiguous ampersand. https://mths.be/notes/ambiguous-ampersands - if (strict) { - parseError( - 'named character reference was not terminated by a semicolon' - ); - } - return $0; - } - } - // If we’re still here, it’s a legacy reference for sure. No need for an - // extra `if` check. - // Decode named character references without trailing `;`, e.g. `&` - // This is only a parse error if it gets converted to `&`, or if it is - // followed by `=` in an attribute context. - reference = $6; - next = $7; - if (next && options.isAttributeValue) { - if (strict && next == '=') { - parseError('`&` did not start a character reference'); - } - return $0; - } else { - if (strict) { - parseError( - 'named character reference was not terminated by a semicolon' - ); - } - // Note: there is no need to check `has(decodeMapLegacy, reference)`. - return decodeMapLegacy[reference] + (next || ''); - } - }); - }; - // Expose default options (so they can be overridden globally). - decode.options = { - 'isAttributeValue': false, - 'strict': false - }; - - var escape = function(string) { - return string.replace(regexEscape, function($0) { - // Note: there is no need to check `has(escapeMap, $0)` here. - return escapeMap[$0]; - }); - }; - - /*--------------------------------------------------------------------------*/ - - var he = { - 'version': '1.1.1', - 'encode': encode, - 'decode': decode, - 'escape': escape, - 'unescape': decode - }; - - // Some AMD build optimizers, like r.js, check for specific condition patterns - // like the following: - if ( - false - ) { - define(function() { - return he; - }); - } else if (freeExports && !freeExports.nodeType) { - if (freeModule) { // in Node.js, io.js, or RingoJS v0.8.0+ - freeModule.exports = he; - } else { // in Narwhal or RingoJS v0.7.0- - for (var key in he) { - has(he, key) && (freeExports[key] = he[key]); - } - } - } else { // in Rhino or a web browser - root.he = he; - } - -}(this)); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],48:[function(require,module,exports){ -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} - -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 -} - -},{}],49:[function(require,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } -} - -},{}],50:[function(require,module,exports){ -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT - */ - -// The _isBuffer check is for Safari 5-7 support, because it's missing -// Object.prototype.constructor. Remove this eventually -module.exports = function (obj) { - return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) -} - -function isBuffer (obj) { - return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} - -// For Node v0.10 support. Remove this eventually. -function isSlowBuffer (obj) { - return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) -} - -},{}],51:[function(require,module,exports){ -var toString = {}.toString; - -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; - -},{}],52:[function(require,module,exports){ -(function (process){ -var path = require('path'); -var fs = require('fs'); -var _0777 = parseInt('0777', 8); - -module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; - -function mkdirP (p, opts, f, made) { - if (typeof opts === 'function') { - f = opts; - opts = {}; - } - else if (!opts || typeof opts !== 'object') { - opts = { mode: opts }; - } - - var mode = opts.mode; - var xfs = opts.fs || fs; - - if (mode === undefined) { - mode = _0777 & (~process.umask()); - } - if (!made) made = null; - - var cb = f || function () {}; - p = path.resolve(p); - - xfs.mkdir(p, mode, function (er) { - if (!er) { - made = made || p; - return cb(null, made); - } - switch (er.code) { - case 'ENOENT': - mkdirP(path.dirname(p), opts, function (er, made) { - if (er) cb(er, made); - else mkdirP(p, opts, cb, made); - }); - break; - - // In the case of any other error, just see if there's a dir - // there already. If so, then hooray! If not, then something - // is borked. - default: - xfs.stat(p, function (er2, stat) { - // if the stat fails, then that's super weird. - // let the original error be the failure reason. - if (er2 || !stat.isDirectory()) cb(er, made) - else cb(null, made); - }); - break; - } - }); -} - -mkdirP.sync = function sync (p, opts, made) { - if (!opts || typeof opts !== 'object') { - opts = { mode: opts }; - } - - var mode = opts.mode; - var xfs = opts.fs || fs; - - if (mode === undefined) { - mode = _0777 & (~process.umask()); - } - if (!made) made = null; - - p = path.resolve(p); - - try { - xfs.mkdirSync(p, mode); - made = made || p; - } - catch (err0) { - switch (err0.code) { - case 'ENOENT' : - made = sync(path.dirname(p), opts, made); - sync(p, opts, made); - break; - - // In the case of any other error, just see if there's a dir - // there already. If so, then hooray! If not, then something - // is borked. - default: - var stat; - try { - stat = xfs.statSync(p); - } - catch (err1) { - throw err0; - } - if (!stat.isDirectory()) throw err0; - break; - } - } - - return made; -}; - -}).call(this,require('_process')) -},{"_process":55,"fs":40,"path":40}],53:[function(require,module,exports){ -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public - */ - -module.exports = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; - } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; -} - -/** - * Pluralization helper. - */ - -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; -} - -},{}],54:[function(require,module,exports){ -(function (process){ -'use strict'; - -if (!process.version || - process.version.indexOf('v0.') === 0 || - process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) { - module.exports = nextTick; -} else { - module.exports = process.nextTick; -} - -function nextTick(fn, arg1, arg2, arg3) { - if (typeof fn !== 'function') { - throw new TypeError('"callback" argument must be a function'); - } - var len = arguments.length; - var args, i; - switch (len) { - case 0: - case 1: - return process.nextTick(fn); - case 2: - return process.nextTick(function afterTickOne() { - fn.call(null, arg1); - }); - case 3: - return process.nextTick(function afterTickTwo() { - fn.call(null, arg1, arg2); - }); - case 4: - return process.nextTick(function afterTickThree() { - fn.call(null, arg1, arg2, arg3); - }); - default: - args = new Array(len - 1); - i = 0; - while (i < args.length) { - args[i++] = arguments[i]; - } - return process.nextTick(function afterTick() { - fn.apply(null, args); - }); - } -} - -}).call(this,require('_process')) -},{"_process":55}],55:[function(require,module,exports){ -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - -},{}],56:[function(require,module,exports){ -module.exports = require('./lib/_stream_duplex.js'); - -},{"./lib/_stream_duplex.js":57}],57:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a duplex stream is just a stream that is both readable and writable. -// Since JS doesn't have multiple prototypal inheritance, this class -// prototypally inherits from Readable, and then parasitically from -// Writable. - -'use strict'; - -/**/ - -var processNextTick = require('process-nextick-args'); -/**/ - -/**/ -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - keys.push(key); - }return keys; -}; -/**/ - -module.exports = Duplex; - -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ - -var Readable = require('./_stream_readable'); -var Writable = require('./_stream_writable'); - -util.inherits(Duplex, Readable); - -var keys = objectKeys(Writable.prototype); -for (var v = 0; v < keys.length; v++) { - var method = keys[v]; - if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; -} - -function Duplex(options) { - if (!(this instanceof Duplex)) return new Duplex(options); - - Readable.call(this, options); - Writable.call(this, options); - - if (options && options.readable === false) this.readable = false; - - if (options && options.writable === false) this.writable = false; - - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; - - this.once('end', onend); -} - -// the no-half-open enforcer -function onend() { - // if we allow half-open state, or if the writable side ended, - // then we're ok. - if (this.allowHalfOpen || this._writableState.ended) return; - - // no more data can be written. - // But allow more writes to happen in this tick. - processNextTick(onEndNT, this); -} - -function onEndNT(self) { - self.end(); -} - -Object.defineProperty(Duplex.prototype, 'destroyed', { - get: function () { - if (this._readableState === undefined || this._writableState === undefined) { - return false; - } - return this._readableState.destroyed && this._writableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (this._readableState === undefined || this._writableState === undefined) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - this._writableState.destroyed = value; - } -}); - -Duplex.prototype._destroy = function (err, cb) { - this.push(null); - this.end(); - - processNextTick(cb, err); -}; - -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} -},{"./_stream_readable":59,"./_stream_writable":61,"core-util-is":41,"inherits":49,"process-nextick-args":54}],58:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a passthrough stream. -// basically just the most minimal sort of Transform stream. -// Every written chunk gets output as-is. - -'use strict'; - -module.exports = PassThrough; - -var Transform = require('./_stream_transform'); - -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ - -util.inherits(PassThrough, Transform); - -function PassThrough(options) { - if (!(this instanceof PassThrough)) return new PassThrough(options); - - Transform.call(this, options); -} - -PassThrough.prototype._transform = function (chunk, encoding, cb) { - cb(null, chunk); -}; -},{"./_stream_transform":60,"core-util-is":41,"inherits":49}],59:[function(require,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -/**/ - -var processNextTick = require('process-nextick-args'); -/**/ - -module.exports = Readable; - -/**/ -var isArray = require('isarray'); -/**/ - -/**/ -var Duplex; -/**/ - -Readable.ReadableState = ReadableState; - -/**/ -var EE = require('events').EventEmitter; - -var EElistenerCount = function (emitter, type) { - return emitter.listeners(type).length; -}; -/**/ - -/**/ -var Stream = require('./internal/streams/stream'); -/**/ - -// TODO(bmeurer): Change this back to const once hole checks are -// properly optimized away early in Ignition+TurboFan. -/**/ -var Buffer = require('safe-buffer').Buffer; -var OurUint8Array = global.Uint8Array || function () {}; -function _uint8ArrayToBuffer(chunk) { - return Buffer.from(chunk); -} -function _isUint8Array(obj) { - return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; -} -/**/ - -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ - -/**/ -var debugUtil = require('util'); -var debug = void 0; -if (debugUtil && debugUtil.debuglog) { - debug = debugUtil.debuglog('stream'); -} else { - debug = function () {}; -} -/**/ - -var BufferList = require('./internal/streams/BufferList'); -var destroyImpl = require('./internal/streams/destroy'); -var StringDecoder; - -util.inherits(Readable, Stream); - -var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; - -function prependListener(emitter, event, fn) { - // Sadly this is not cacheable as some libraries bundle their own - // event emitter implementation with them. - if (typeof emitter.prependListener === 'function') { - return emitter.prependListener(event, fn); - } else { - // This is a hack to make sure that our error handler is attached before any - // userland ones. NEVER DO THIS. This is here only because this code needs - // to continue to work with older versions of Node.js that do not include - // the prependListener() method. The goal is to eventually remove this hack. - if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; - } -} - -function ReadableState(options, stream) { - Duplex = Duplex || require('./_stream_duplex'); - - options = options || {}; - - // object stream flag. Used to make read(n) ignore n and to - // make all the buffer merging and length checks go away - this.objectMode = !!options.objectMode; - - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode; - - // the point at which it stops calling _read() to fill the buffer - // Note: 0 is a valid value, means "don't call _read preemptively ever" - var hwm = options.highWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; - - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); - - // A linked list is used to store data chunks instead of an array because the - // linked list can remove elements from the beginning faster than - // array.shift() - this.buffer = new BufferList(); - this.length = 0; - this.pipes = null; - this.pipesCount = 0; - this.flowing = null; - this.ended = false; - this.endEmitted = false; - this.reading = false; - - // a flag to be able to tell if the event 'readable'/'data' is emitted - // immediately, or on a later tick. We set this to true at first, because - // any actions that shouldn't happen until "later" should generally also - // not happen before the first read call. - this.sync = true; - - // whenever we return null, then we set a flag to say - // that we're awaiting a 'readable' event emission. - this.needReadable = false; - this.emittedReadable = false; - this.readableListening = false; - this.resumeScheduled = false; - - // has it been destroyed - this.destroyed = false; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // the number of writers that are awaiting a drain event in .pipe()s - this.awaitDrain = 0; - - // if true, a maybeReadMore has been scheduled - this.readingMore = false; - - this.decoder = null; - this.encoding = null; - if (options.encoding) { - if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; - this.decoder = new StringDecoder(options.encoding); - this.encoding = options.encoding; - } -} - -function Readable(options) { - Duplex = Duplex || require('./_stream_duplex'); - - if (!(this instanceof Readable)) return new Readable(options); - - this._readableState = new ReadableState(options, this); - - // legacy - this.readable = true; - - if (options) { - if (typeof options.read === 'function') this._read = options.read; - - if (typeof options.destroy === 'function') this._destroy = options.destroy; - } - - Stream.call(this); -} - -Object.defineProperty(Readable.prototype, 'destroyed', { - get: function () { - if (this._readableState === undefined) { - return false; - } - return this._readableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (!this._readableState) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - } -}); - -Readable.prototype.destroy = destroyImpl.destroy; -Readable.prototype._undestroy = destroyImpl.undestroy; -Readable.prototype._destroy = function (err, cb) { - this.push(null); - cb(err); -}; - -// Manually shove something into the read() buffer. -// This returns true if the highWaterMark has not been hit yet, -// similar to how Writable.write() returns true if you should -// write() some more. -Readable.prototype.push = function (chunk, encoding) { - var state = this._readableState; - var skipChunkCheck; - - if (!state.objectMode) { - if (typeof chunk === 'string') { - encoding = encoding || state.defaultEncoding; - if (encoding !== state.encoding) { - chunk = Buffer.from(chunk, encoding); - encoding = ''; - } - skipChunkCheck = true; - } - } else { - skipChunkCheck = true; - } - - return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); -}; - -// Unshift should *always* be something directly out of read() -Readable.prototype.unshift = function (chunk) { - return readableAddChunk(this, chunk, null, true, false); -}; - -function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { - var state = stream._readableState; - if (chunk === null) { - state.reading = false; - onEofChunk(stream, state); - } else { - var er; - if (!skipChunkCheck) er = chunkInvalid(state, chunk); - if (er) { - stream.emit('error', er); - } else if (state.objectMode || chunk && chunk.length > 0) { - if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { - chunk = _uint8ArrayToBuffer(chunk); - } - - if (addToFront) { - if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true); - } else if (state.ended) { - stream.emit('error', new Error('stream.push() after EOF')); - } else { - state.reading = false; - if (state.decoder && !encoding) { - chunk = state.decoder.write(chunk); - if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); - } else { - addChunk(stream, state, chunk, false); - } - } - } else if (!addToFront) { - state.reading = false; - } - } - - return needMoreData(state); -} - -function addChunk(stream, state, chunk, addToFront) { - if (state.flowing && state.length === 0 && !state.sync) { - stream.emit('data', chunk); - stream.read(0); - } else { - // update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); - - if (state.needReadable) emitReadable(stream); - } - maybeReadMore(stream, state); -} - -function chunkInvalid(state, chunk) { - var er; - if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - return er; -} - -// if it's past the high water mark, we can push in some more. -// Also, if we have no data yet, we can stand some -// more bytes. This is to work around cases where hwm=0, -// such as the repl. Also, if the push() triggered a -// readable event, and the user called read(largeNumber) such that -// needReadable was set, then we ought to push more, so that another -// 'readable' event will be triggered. -function needMoreData(state) { - return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); -} - -Readable.prototype.isPaused = function () { - return this._readableState.flowing === false; -}; - -// backwards compatibility. -Readable.prototype.setEncoding = function (enc) { - if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; - this._readableState.decoder = new StringDecoder(enc); - this._readableState.encoding = enc; - return this; -}; - -// Don't raise the hwm > 8MB -var MAX_HWM = 0x800000; -function computeNewHighWaterMark(n) { - if (n >= MAX_HWM) { - n = MAX_HWM; - } else { - // Get the next highest power of 2 to prevent increasing hwm excessively in - // tiny amounts - n--; - n |= n >>> 1; - n |= n >>> 2; - n |= n >>> 4; - n |= n >>> 8; - n |= n >>> 16; - n++; - } - return n; -} - -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function howMuchToRead(n, state) { - if (n <= 0 || state.length === 0 && state.ended) return 0; - if (state.objectMode) return 1; - if (n !== n) { - // Only flow one buffer at a time - if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; - } - // If we're asking for more than the current hwm, then raise the hwm. - if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); - if (n <= state.length) return n; - // Don't have enough - if (!state.ended) { - state.needReadable = true; - return 0; - } - return state.length; -} - -// you can override either this method, or the async _read(n) below. -Readable.prototype.read = function (n) { - debug('read', n); - n = parseInt(n, 10); - var state = this._readableState; - var nOrig = n; - - if (n !== 0) state.emittedReadable = false; - - // if we're doing read(0) to trigger a readable event, but we - // already have a bunch of data in the buffer, then just trigger - // the 'readable' event and move on. - if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) { - debug('read: emitReadable', state.length, state.ended); - if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); - return null; - } - - n = howMuchToRead(n, state); - - // if we've ended, and we're now clear, then finish it up. - if (n === 0 && state.ended) { - if (state.length === 0) endReadable(this); - return null; - } - - // All the actual chunk generation logic needs to be - // *below* the call to _read. The reason is that in certain - // synthetic stream cases, such as passthrough streams, _read - // may be a completely synchronous operation which may change - // the state of the read buffer, providing enough data when - // before there was *not* enough. - // - // So, the steps are: - // 1. Figure out what the state of things will be after we do - // a read from the buffer. - // - // 2. If that resulting state will trigger a _read, then call _read. - // Note that this may be asynchronous, or synchronous. Yes, it is - // deeply ugly to write APIs this way, but that still doesn't mean - // that the Readable class should behave improperly, as streams are - // designed to be sync/async agnostic. - // Take note if the _read call is sync or async (ie, if the read call - // has returned yet), so that we know whether or not it's safe to emit - // 'readable' etc. - // - // 3. Actually pull the requested chunks out of the buffer and return. - - // if we need a readable event, then we need to do some reading. - var doRead = state.needReadable; - debug('need readable', doRead); - - // if we currently have less than the highWaterMark, then also read some - if (state.length === 0 || state.length - n < state.highWaterMark) { - doRead = true; - debug('length less than watermark', doRead); - } - - // however, if we've ended, then there's no point, and if we're already - // reading, then it's unnecessary. - if (state.ended || state.reading) { - doRead = false; - debug('reading or ended', doRead); - } else if (doRead) { - debug('do read'); - state.reading = true; - state.sync = true; - // if the length is currently zero, then we *need* a readable event. - if (state.length === 0) state.needReadable = true; - // call internal read method - this._read(state.highWaterMark); - state.sync = false; - // If _read pushed data synchronously, then `reading` will be false, - // and we need to re-evaluate how much data we can return to the user. - if (!state.reading) n = howMuchToRead(nOrig, state); - } - - var ret; - if (n > 0) ret = fromList(n, state);else ret = null; - - if (ret === null) { - state.needReadable = true; - n = 0; - } else { - state.length -= n; - } - - if (state.length === 0) { - // If we have nothing in the buffer, then we want to know - // as soon as we *do* get something into the buffer. - if (!state.ended) state.needReadable = true; - - // If we tried to read() past the EOF, then emit end on the next tick. - if (nOrig !== n && state.ended) endReadable(this); - } - - if (ret !== null) this.emit('data', ret); - - return ret; -}; - -function onEofChunk(stream, state) { - if (state.ended) return; - if (state.decoder) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) { - state.buffer.push(chunk); - state.length += state.objectMode ? 1 : chunk.length; - } - } - state.ended = true; - - // emit 'readable' now to make sure it gets picked up. - emitReadable(stream); -} - -// Don't emit readable right away in sync mode, because this can trigger -// another read() call => stack overflow. This way, it might trigger -// a nextTick recursion warning, but that's not so bad. -function emitReadable(stream) { - var state = stream._readableState; - state.needReadable = false; - if (!state.emittedReadable) { - debug('emitReadable', state.flowing); - state.emittedReadable = true; - if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream); - } -} - -function emitReadable_(stream) { - debug('emit readable'); - stream.emit('readable'); - flow(stream); -} - -// at this point, the user has presumably seen the 'readable' event, -// and called read() to consume some data. that may have triggered -// in turn another _read(n) call, in which case reading = true if -// it's in progress. -// However, if we're not ended, or reading, and the length < hwm, -// then go ahead and try to read some more preemptively. -function maybeReadMore(stream, state) { - if (!state.readingMore) { - state.readingMore = true; - processNextTick(maybeReadMore_, stream, state); - } -} - -function maybeReadMore_(stream, state) { - var len = state.length; - while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) { - debug('maybeReadMore read 0'); - stream.read(0); - if (len === state.length) - // didn't get any data, stop spinning. - break;else len = state.length; - } - state.readingMore = false; -} - -// abstract method. to be overridden in specific implementation classes. -// call cb(er, data) where data is <= n in length. -// for virtual (non-string, non-buffer) streams, "length" is somewhat -// arbitrary, and perhaps not very meaningful. -Readable.prototype._read = function (n) { - this.emit('error', new Error('_read() is not implemented')); -}; - -Readable.prototype.pipe = function (dest, pipeOpts) { - var src = this; - var state = this._readableState; - - switch (state.pipesCount) { - case 0: - state.pipes = dest; - break; - case 1: - state.pipes = [state.pipes, dest]; - break; - default: - state.pipes.push(dest); - break; - } - state.pipesCount += 1; - debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); - - var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; - - var endFn = doEnd ? onend : unpipe; - if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn); - - dest.on('unpipe', onunpipe); - function onunpipe(readable, unpipeInfo) { - debug('onunpipe'); - if (readable === src) { - if (unpipeInfo && unpipeInfo.hasUnpiped === false) { - unpipeInfo.hasUnpiped = true; - cleanup(); - } - } - } - - function onend() { - debug('onend'); - dest.end(); - } - - // when the dest drains, it reduces the awaitDrain counter - // on the source. This would be more elegant with a .once() - // handler in flow(), but adding and removing repeatedly is - // too slow. - var ondrain = pipeOnDrain(src); - dest.on('drain', ondrain); - - var cleanedUp = false; - function cleanup() { - debug('cleanup'); - // cleanup event handlers once the pipe is broken - dest.removeListener('close', onclose); - dest.removeListener('finish', onfinish); - dest.removeListener('drain', ondrain); - dest.removeListener('error', onerror); - dest.removeListener('unpipe', onunpipe); - src.removeListener('end', onend); - src.removeListener('end', unpipe); - src.removeListener('data', ondata); - - cleanedUp = true; - - // if the reader is waiting for a drain event from this - // specific writer, then it would cause it to never start - // flowing again. - // So, if this is awaiting a drain, then we just call it now. - // If we don't know, then assume that we are waiting for one. - if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); - } - - // If the user pushes more data while we're writing to dest then we'll end up - // in ondata again. However, we only want to increase awaitDrain once because - // dest will only emit one 'drain' event for the multiple writes. - // => Introduce a guard on increasing awaitDrain. - var increasedAwaitDrain = false; - src.on('data', ondata); - function ondata(chunk) { - debug('ondata'); - increasedAwaitDrain = false; - var ret = dest.write(chunk); - if (false === ret && !increasedAwaitDrain) { - // If the user unpiped during `dest.write()`, it is possible - // to get stuck in a permanently paused state if that write - // also returned false. - // => Check whether `dest` is still a piping destination. - if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { - debug('false write response, pause', src._readableState.awaitDrain); - src._readableState.awaitDrain++; - increasedAwaitDrain = true; - } - src.pause(); - } - } - - // if the dest has an error, then stop piping into it. - // however, don't suppress the throwing behavior for this. - function onerror(er) { - debug('onerror', er); - unpipe(); - dest.removeListener('error', onerror); - if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er); - } - - // Make sure our error handler is attached before userland ones. - prependListener(dest, 'error', onerror); - - // Both close and finish should trigger unpipe, but only once. - function onclose() { - dest.removeListener('finish', onfinish); - unpipe(); - } - dest.once('close', onclose); - function onfinish() { - debug('onfinish'); - dest.removeListener('close', onclose); - unpipe(); - } - dest.once('finish', onfinish); - - function unpipe() { - debug('unpipe'); - src.unpipe(dest); - } - - // tell the dest that it's being piped to - dest.emit('pipe', src); - - // start the flow if it hasn't been started already. - if (!state.flowing) { - debug('pipe resume'); - src.resume(); - } - - return dest; -}; - -function pipeOnDrain(src) { - return function () { - var state = src._readableState; - debug('pipeOnDrain', state.awaitDrain); - if (state.awaitDrain) state.awaitDrain--; - if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { - state.flowing = true; - flow(src); - } - }; -} - -Readable.prototype.unpipe = function (dest) { - var state = this._readableState; - var unpipeInfo = { hasUnpiped: false }; - - // if we're not piping anywhere, then do nothing. - if (state.pipesCount === 0) return this; - - // just one destination. most common case. - if (state.pipesCount === 1) { - // passed in one, but it's not the right one. - if (dest && dest !== state.pipes) return this; - - if (!dest) dest = state.pipes; - - // got a match. - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - if (dest) dest.emit('unpipe', this, unpipeInfo); - return this; - } - - // slow case. multiple pipe destinations. - - if (!dest) { - // remove all. - var dests = state.pipes; - var len = state.pipesCount; - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - - for (var i = 0; i < len; i++) { - dests[i].emit('unpipe', this, unpipeInfo); - }return this; - } - - // try to find the right one. - var index = indexOf(state.pipes, dest); - if (index === -1) return this; - - state.pipes.splice(index, 1); - state.pipesCount -= 1; - if (state.pipesCount === 1) state.pipes = state.pipes[0]; - - dest.emit('unpipe', this, unpipeInfo); - - return this; -}; - -// set up data events if they are asked for -// Ensure readable listeners eventually get something -Readable.prototype.on = function (ev, fn) { - var res = Stream.prototype.on.call(this, ev, fn); - - if (ev === 'data') { - // Start flowing on next tick if stream isn't explicitly paused - if (this._readableState.flowing !== false) this.resume(); - } else if (ev === 'readable') { - var state = this._readableState; - if (!state.endEmitted && !state.readableListening) { - state.readableListening = state.needReadable = true; - state.emittedReadable = false; - if (!state.reading) { - processNextTick(nReadingNextTick, this); - } else if (state.length) { - emitReadable(this); - } - } - } - - return res; -}; -Readable.prototype.addListener = Readable.prototype.on; - -function nReadingNextTick(self) { - debug('readable nexttick read 0'); - self.read(0); -} - -// pause() and resume() are remnants of the legacy readable stream API -// If the user uses them, then switch into old mode. -Readable.prototype.resume = function () { - var state = this._readableState; - if (!state.flowing) { - debug('resume'); - state.flowing = true; - resume(this, state); - } - return this; -}; - -function resume(stream, state) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - processNextTick(resume_, stream, state); - } -} - -function resume_(stream, state) { - if (!state.reading) { - debug('resume read 0'); - stream.read(0); - } - - state.resumeScheduled = false; - state.awaitDrain = 0; - stream.emit('resume'); - flow(stream); - if (state.flowing && !state.reading) stream.read(0); -} - -Readable.prototype.pause = function () { - debug('call pause flowing=%j', this._readableState.flowing); - if (false !== this._readableState.flowing) { - debug('pause'); - this._readableState.flowing = false; - this.emit('pause'); - } - return this; -}; - -function flow(stream) { - var state = stream._readableState; - debug('flow', state.flowing); - while (state.flowing && stream.read() !== null) {} -} - -// wrap an old-style stream as the async data source. -// This is *not* part of the readable stream interface. -// It is an ugly unfortunate mess of history. -Readable.prototype.wrap = function (stream) { - var state = this._readableState; - var paused = false; - - var self = this; - stream.on('end', function () { - debug('wrapped end'); - if (state.decoder && !state.ended) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) self.push(chunk); - } - - self.push(null); - }); - - stream.on('data', function (chunk) { - debug('wrapped data'); - if (state.decoder) chunk = state.decoder.write(chunk); - - // don't skip over falsy values in objectMode - if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; - - var ret = self.push(chunk); - if (!ret) { - paused = true; - stream.pause(); - } - }); - - // proxy all the other methods. - // important when wrapping filters and duplexes. - for (var i in stream) { - if (this[i] === undefined && typeof stream[i] === 'function') { - this[i] = function (method) { - return function () { - return stream[method].apply(stream, arguments); - }; - }(i); - } - } - - // proxy certain important events. - for (var n = 0; n < kProxyEvents.length; n++) { - stream.on(kProxyEvents[n], self.emit.bind(self, kProxyEvents[n])); - } - - // when we try to consume some more bytes, simply unpause the - // underlying stream. - self._read = function (n) { - debug('wrapped _read', n); - if (paused) { - paused = false; - stream.resume(); - } - }; - - return self; -}; - -// exposed for testing purposes only. -Readable._fromList = fromList; - -// Pluck off n bytes from an array of buffers. -// Length is the combined lengths of all the buffers in the list. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromList(n, state) { - // nothing buffered - if (state.length === 0) return null; - - var ret; - if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { - // read it all, truncate the list - if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length); - state.buffer.clear(); - } else { - // read part of list - ret = fromListPartial(n, state.buffer, state.decoder); - } - - return ret; -} - -// Extracts only enough buffered data to satisfy the amount requested. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromListPartial(n, list, hasStrings) { - var ret; - if (n < list.head.data.length) { - // slice is the same for buffers and strings - ret = list.head.data.slice(0, n); - list.head.data = list.head.data.slice(n); - } else if (n === list.head.data.length) { - // first chunk is a perfect match - ret = list.shift(); - } else { - // result spans more than one buffer - ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list); - } - return ret; -} - -// Copies a specified amount of characters from the list of buffered data -// chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBufferString(n, list) { - var p = list.head; - var c = 1; - var ret = p.data; - n -= ret.length; - while (p = p.next) { - var str = p.data; - var nb = n > str.length ? str.length : n; - if (nb === str.length) ret += str;else ret += str.slice(0, n); - n -= nb; - if (n === 0) { - if (nb === str.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = str.slice(nb); - } - break; - } - ++c; - } - list.length -= c; - return ret; -} - -// Copies a specified amount of bytes from the list of buffered data chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBuffer(n, list) { - var ret = Buffer.allocUnsafe(n); - var p = list.head; - var c = 1; - p.data.copy(ret); - n -= p.data.length; - while (p = p.next) { - var buf = p.data; - var nb = n > buf.length ? buf.length : n; - buf.copy(ret, ret.length - n, 0, nb); - n -= nb; - if (n === 0) { - if (nb === buf.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = buf.slice(nb); - } - break; - } - ++c; - } - list.length -= c; - return ret; -} - -function endReadable(stream) { - var state = stream._readableState; - - // If we get here before consuming all the bytes, then that is a - // bug in node. Should never happen. - if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream'); - - if (!state.endEmitted) { - state.ended = true; - processNextTick(endReadableNT, state, stream); - } -} - -function endReadableNT(state, stream) { - // Check that we didn't get one last unshift. - if (!state.endEmitted && state.length === 0) { - state.endEmitted = true; - stream.readable = false; - stream.emit('end'); - } -} - -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} - -function indexOf(xs, x) { - for (var i = 0, l = xs.length; i < l; i++) { - if (xs[i] === x) return i; - } - return -1; -} -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./_stream_duplex":57,"./internal/streams/BufferList":62,"./internal/streams/destroy":63,"./internal/streams/stream":64,"_process":55,"core-util-is":41,"events":46,"inherits":49,"isarray":51,"process-nextick-args":54,"safe-buffer":69,"string_decoder/":71,"util":38}],60:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a transform stream is a readable/writable stream where you do -// something with the data. Sometimes it's called a "filter", -// but that's not a great name for it, since that implies a thing where -// some bits pass through, and others are simply ignored. (That would -// be a valid example of a transform, of course.) -// -// While the output is causally related to the input, it's not a -// necessarily symmetric or synchronous transformation. For example, -// a zlib stream might take multiple plain-text writes(), and then -// emit a single compressed chunk some time in the future. -// -// Here's how this works: -// -// The Transform stream has all the aspects of the readable and writable -// stream classes. When you write(chunk), that calls _write(chunk,cb) -// internally, and returns false if there's a lot of pending writes -// buffered up. When you call read(), that calls _read(n) until -// there's enough pending readable data buffered up. -// -// In a transform stream, the written data is placed in a buffer. When -// _read(n) is called, it transforms the queued up data, calling the -// buffered _write cb's as it consumes chunks. If consuming a single -// written chunk would result in multiple output chunks, then the first -// outputted bit calls the readcb, and subsequent chunks just go into -// the read buffer, and will cause it to emit 'readable' if necessary. -// -// This way, back-pressure is actually determined by the reading side, -// since _read has to be called to start processing a new chunk. However, -// a pathological inflate type of transform can cause excessive buffering -// here. For example, imagine a stream where every byte of input is -// interpreted as an integer from 0-255, and then results in that many -// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in -// 1kb of data being output. In this case, you could write a very small -// amount of input, and end up with a very large amount of output. In -// such a pathological inflating mechanism, there'd be no way to tell -// the system to stop doing the transform. A single 4MB write could -// cause the system to run out of memory. -// -// However, even in such a pathological case, only a single written chunk -// would be consumed, and then the rest would wait (un-transformed) until -// the results of the previous transformed chunk were consumed. - -'use strict'; - -module.exports = Transform; - -var Duplex = require('./_stream_duplex'); - -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ - -util.inherits(Transform, Duplex); - -function TransformState(stream) { - this.afterTransform = function (er, data) { - return afterTransform(stream, er, data); - }; - - this.needTransform = false; - this.transforming = false; - this.writecb = null; - this.writechunk = null; - this.writeencoding = null; -} - -function afterTransform(stream, er, data) { - var ts = stream._transformState; - ts.transforming = false; - - var cb = ts.writecb; - - if (!cb) { - return stream.emit('error', new Error('write callback called multiple times')); - } - - ts.writechunk = null; - ts.writecb = null; - - if (data !== null && data !== undefined) stream.push(data); - - cb(er); - - var rs = stream._readableState; - rs.reading = false; - if (rs.needReadable || rs.length < rs.highWaterMark) { - stream._read(rs.highWaterMark); - } -} - -function Transform(options) { - if (!(this instanceof Transform)) return new Transform(options); - - Duplex.call(this, options); - - this._transformState = new TransformState(this); - - var stream = this; - - // start out asking for a readable event once data is transformed. - this._readableState.needReadable = true; - - // we have implemented the _read method, and done the other things - // that Readable wants before the first _read call, so unset the - // sync guard flag. - this._readableState.sync = false; - - if (options) { - if (typeof options.transform === 'function') this._transform = options.transform; - - if (typeof options.flush === 'function') this._flush = options.flush; - } - - // When the writable side finishes, then flush out anything remaining. - this.once('prefinish', function () { - if (typeof this._flush === 'function') this._flush(function (er, data) { - done(stream, er, data); - });else done(stream); - }); -} - -Transform.prototype.push = function (chunk, encoding) { - this._transformState.needTransform = false; - return Duplex.prototype.push.call(this, chunk, encoding); -}; - -// This is the part where you do stuff! -// override this function in implementation classes. -// 'chunk' is an input chunk. -// -// Call `push(newChunk)` to pass along transformed output -// to the readable side. You may call 'push' zero or more times. -// -// Call `cb(err)` when you are done with this chunk. If you pass -// an error, then that'll put the hurt on the whole operation. If you -// never call cb(), then you'll never get another chunk. -Transform.prototype._transform = function (chunk, encoding, cb) { - throw new Error('_transform() is not implemented'); -}; - -Transform.prototype._write = function (chunk, encoding, cb) { - var ts = this._transformState; - ts.writecb = cb; - ts.writechunk = chunk; - ts.writeencoding = encoding; - if (!ts.transforming) { - var rs = this._readableState; - if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); - } -}; - -// Doesn't matter what the args are here. -// _transform does all the work. -// That we got here means that the readable side wants more data. -Transform.prototype._read = function (n) { - var ts = this._transformState; - - if (ts.writechunk !== null && ts.writecb && !ts.transforming) { - ts.transforming = true; - this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); - } else { - // mark that we need a transform, so that any data that comes in - // will get processed, now that we've asked for it. - ts.needTransform = true; - } -}; - -Transform.prototype._destroy = function (err, cb) { - var _this = this; - - Duplex.prototype._destroy.call(this, err, function (err2) { - cb(err2); - _this.emit('close'); - }); -}; - -function done(stream, er, data) { - if (er) return stream.emit('error', er); - - if (data !== null && data !== undefined) stream.push(data); - - // if there's nothing in the write buffer, then that means - // that nothing more will ever be provided - var ws = stream._writableState; - var ts = stream._transformState; - - if (ws.length) throw new Error('Calling transform done when ws.length != 0'); - - if (ts.transforming) throw new Error('Calling transform done when still transforming'); - - return stream.push(null); -} -},{"./_stream_duplex":57,"core-util-is":41,"inherits":49}],61:[function(require,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// A bit simpler than readable streams. -// Implement an async ._write(chunk, encoding, cb), and it'll handle all -// the drain event emission and buffering. - -'use strict'; - -/**/ - -var processNextTick = require('process-nextick-args'); -/**/ - -module.exports = Writable; - -/* */ -function WriteReq(chunk, encoding, cb) { - this.chunk = chunk; - this.encoding = encoding; - this.callback = cb; - this.next = null; -} - -// It seems a linked list but it is not -// there will be only 2 of these for each stream -function CorkedRequest(state) { - var _this = this; - - this.next = null; - this.entry = null; - this.finish = function () { - onCorkedFinish(_this, state); - }; -} -/* */ - -/**/ -var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick; -/**/ - -/**/ -var Duplex; -/**/ - -Writable.WritableState = WritableState; - -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ - -/**/ -var internalUtil = { - deprecate: require('util-deprecate') -}; -/**/ - -/**/ -var Stream = require('./internal/streams/stream'); -/**/ - -/**/ -var Buffer = require('safe-buffer').Buffer; -var OurUint8Array = global.Uint8Array || function () {}; -function _uint8ArrayToBuffer(chunk) { - return Buffer.from(chunk); -} -function _isUint8Array(obj) { - return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; -} -/**/ - -var destroyImpl = require('./internal/streams/destroy'); - -util.inherits(Writable, Stream); - -function nop() {} - -function WritableState(options, stream) { - Duplex = Duplex || require('./_stream_duplex'); - - options = options || {}; - - // object stream flag to indicate whether or not this stream - // contains buffers or objects. - this.objectMode = !!options.objectMode; - - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; - - // the point at which write() starts returning false - // Note: 0 is a valid value, means that we always return false if - // the entire buffer is not flushed immediately on write() - var hwm = options.highWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; - - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); - - // if _final has been called - this.finalCalled = false; - - // drain event flag. - this.needDrain = false; - // at the start of calling end() - this.ending = false; - // when end() has been called, and returned - this.ended = false; - // when 'finish' is emitted - this.finished = false; - - // has it been destroyed - this.destroyed = false; - - // should we decode strings into buffers before passing to _write? - // this is here so that some node-core streams can optimize string - // handling at a lower level. - var noDecode = options.decodeStrings === false; - this.decodeStrings = !noDecode; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // not an actual buffer we keep track of, but a measurement - // of how much we're waiting to get pushed to some underlying - // socket or file. - this.length = 0; - - // a flag to see when we're in the middle of a write. - this.writing = false; - - // when true all writes will be buffered until .uncork() call - this.corked = 0; - - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // a flag to know if we're processing previously buffered items, which - // may call the _write() callback in the same tick, so that we don't - // end up in an overlapped onwrite situation. - this.bufferProcessing = false; - - // the callback that's passed to _write(chunk,cb) - this.onwrite = function (er) { - onwrite(stream, er); - }; - - // the callback that the user supplies to write(chunk,encoding,cb) - this.writecb = null; - - // the amount that is being written when _write is called. - this.writelen = 0; - - this.bufferedRequest = null; - this.lastBufferedRequest = null; - - // number of pending user-supplied write callbacks - // this must be 0 before 'finish' can be emitted - this.pendingcb = 0; - - // emit prefinish if the only thing we're waiting for is _write cbs - // This is relevant for synchronous Transform streams - this.prefinished = false; - - // True if the error was already emitted and should not be thrown again - this.errorEmitted = false; - - // count buffered requests - this.bufferedRequestCount = 0; - - // allocate the first CorkedRequest, there is always - // one allocated and free to use, and we maintain at most two - this.corkedRequestsFree = new CorkedRequest(this); -} - -WritableState.prototype.getBuffer = function getBuffer() { - var current = this.bufferedRequest; - var out = []; - while (current) { - out.push(current); - current = current.next; - } - return out; -}; - -(function () { - try { - Object.defineProperty(WritableState.prototype, 'buffer', { - get: internalUtil.deprecate(function () { - return this.getBuffer(); - }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') - }); - } catch (_) {} -})(); - -// Test _writableState for inheritance to account for Duplex streams, -// whose prototype chain only points to Readable. -var realHasInstance; -if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { - realHasInstance = Function.prototype[Symbol.hasInstance]; - Object.defineProperty(Writable, Symbol.hasInstance, { - value: function (object) { - if (realHasInstance.call(this, object)) return true; - - return object && object._writableState instanceof WritableState; - } - }); -} else { - realHasInstance = function (object) { - return object instanceof this; - }; -} - -function Writable(options) { - Duplex = Duplex || require('./_stream_duplex'); - - // Writable ctor is applied to Duplexes, too. - // `realHasInstance` is necessary because using plain `instanceof` - // would return false, as no `_writableState` property is attached. - - // Trying to use the custom `instanceof` for Writable here will also break the - // Node.js LazyTransform implementation, which has a non-trivial getter for - // `_writableState` that would lead to infinite recursion. - if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { - return new Writable(options); - } - - this._writableState = new WritableState(options, this); - - // legacy. - this.writable = true; - - if (options) { - if (typeof options.write === 'function') this._write = options.write; - - if (typeof options.writev === 'function') this._writev = options.writev; - - if (typeof options.destroy === 'function') this._destroy = options.destroy; - - if (typeof options.final === 'function') this._final = options.final; - } - - Stream.call(this); -} - -// Otherwise people can pipe Writable streams, which is just wrong. -Writable.prototype.pipe = function () { - this.emit('error', new Error('Cannot pipe, not readable')); -}; - -function writeAfterEnd(stream, cb) { - var er = new Error('write after end'); - // TODO: defer error events consistently everywhere, not just the cb - stream.emit('error', er); - processNextTick(cb, er); -} - -// Checks that a user-supplied chunk is valid, especially for the particular -// mode the stream is in. Currently this means that `null` is never accepted -// and undefined/non-string values are only allowed in object mode. -function validChunk(stream, state, chunk, cb) { - var valid = true; - var er = false; - - if (chunk === null) { - er = new TypeError('May not write null values to stream'); - } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - if (er) { - stream.emit('error', er); - processNextTick(cb, er); - valid = false; - } - return valid; -} - -Writable.prototype.write = function (chunk, encoding, cb) { - var state = this._writableState; - var ret = false; - var isBuf = _isUint8Array(chunk) && !state.objectMode; - - if (isBuf && !Buffer.isBuffer(chunk)) { - chunk = _uint8ArrayToBuffer(chunk); - } - - if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } - - if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; - - if (typeof cb !== 'function') cb = nop; - - if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { - state.pendingcb++; - ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); - } - - return ret; -}; - -Writable.prototype.cork = function () { - var state = this._writableState; - - state.corked++; -}; - -Writable.prototype.uncork = function () { - var state = this._writableState; - - if (state.corked) { - state.corked--; - - if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); - } -}; - -Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { - // node::ParseEncoding() requires lower case. - if (typeof encoding === 'string') encoding = encoding.toLowerCase(); - if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding); - this._writableState.defaultEncoding = encoding; - return this; -}; - -function decodeChunk(state, chunk, encoding) { - if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { - chunk = Buffer.from(chunk, encoding); - } - return chunk; -} - -// if we're already writing something, then just put this -// in the queue, and wait our turn. Otherwise, call _write -// If we return false, then we need a drain event, so set that flag. -function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { - if (!isBuf) { - var newChunk = decodeChunk(state, chunk, encoding); - if (chunk !== newChunk) { - isBuf = true; - encoding = 'buffer'; - chunk = newChunk; - } - } - var len = state.objectMode ? 1 : chunk.length; - - state.length += len; - - var ret = state.length < state.highWaterMark; - // we must ensure that previous needDrain will not be reset to false. - if (!ret) state.needDrain = true; - - if (state.writing || state.corked) { - var last = state.lastBufferedRequest; - state.lastBufferedRequest = { - chunk: chunk, - encoding: encoding, - isBuf: isBuf, - callback: cb, - next: null - }; - if (last) { - last.next = state.lastBufferedRequest; - } else { - state.bufferedRequest = state.lastBufferedRequest; - } - state.bufferedRequestCount += 1; - } else { - doWrite(stream, state, false, len, chunk, encoding, cb); - } - - return ret; -} - -function doWrite(stream, state, writev, len, chunk, encoding, cb) { - state.writelen = len; - state.writecb = cb; - state.writing = true; - state.sync = true; - if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); - state.sync = false; -} - -function onwriteError(stream, state, sync, er, cb) { - --state.pendingcb; - - if (sync) { - // defer the callback if we are being called synchronously - // to avoid piling up things on the stack - processNextTick(cb, er); - // this can emit finish, and it will always happen - // after error - processNextTick(finishMaybe, stream, state); - stream._writableState.errorEmitted = true; - stream.emit('error', er); - } else { - // the caller expect this to happen before if - // it is async - cb(er); - stream._writableState.errorEmitted = true; - stream.emit('error', er); - // this can emit finish, but finish must - // always follow error - finishMaybe(stream, state); - } -} - -function onwriteStateUpdate(state) { - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; -} - -function onwrite(stream, er) { - var state = stream._writableState; - var sync = state.sync; - var cb = state.writecb; - - onwriteStateUpdate(state); - - if (er) onwriteError(stream, state, sync, er, cb);else { - // Check if we're actually ready to finish, but don't emit yet - var finished = needFinish(state); - - if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { - clearBuffer(stream, state); - } - - if (sync) { - /**/ - asyncWrite(afterWrite, stream, state, finished, cb); - /**/ - } else { - afterWrite(stream, state, finished, cb); - } - } -} - -function afterWrite(stream, state, finished, cb) { - if (!finished) onwriteDrain(stream, state); - state.pendingcb--; - cb(); - finishMaybe(stream, state); -} - -// Must force callback to be called on nextTick, so that we don't -// emit 'drain' before the write() consumer gets the 'false' return -// value, and has a chance to attach a 'drain' listener. -function onwriteDrain(stream, state) { - if (state.length === 0 && state.needDrain) { - state.needDrain = false; - stream.emit('drain'); - } -} - -// if there's something in the buffer waiting, then process it -function clearBuffer(stream, state) { - state.bufferProcessing = true; - var entry = state.bufferedRequest; - - if (stream._writev && entry && entry.next) { - // Fast case, write everything using _writev() - var l = state.bufferedRequestCount; - var buffer = new Array(l); - var holder = state.corkedRequestsFree; - holder.entry = entry; - - var count = 0; - var allBuffers = true; - while (entry) { - buffer[count] = entry; - if (!entry.isBuf) allBuffers = false; - entry = entry.next; - count += 1; - } - buffer.allBuffers = allBuffers; - - doWrite(stream, state, true, state.length, buffer, '', holder.finish); - - // doWrite is almost always async, defer these to save a bit of time - // as the hot path ends with doWrite - state.pendingcb++; - state.lastBufferedRequest = null; - if (holder.next) { - state.corkedRequestsFree = holder.next; - holder.next = null; - } else { - state.corkedRequestsFree = new CorkedRequest(state); - } - } else { - // Slow case, write chunks one-by-one - while (entry) { - var chunk = entry.chunk; - var encoding = entry.encoding; - var cb = entry.callback; - var len = state.objectMode ? 1 : chunk.length; - - doWrite(stream, state, false, len, chunk, encoding, cb); - entry = entry.next; - // if we didn't call the onwrite immediately, then - // it means that we need to wait until it does. - // also, that means that the chunk and cb are currently - // being processed, so move the buffer counter past them. - if (state.writing) { - break; - } - } - - if (entry === null) state.lastBufferedRequest = null; - } - - state.bufferedRequestCount = 0; - state.bufferedRequest = entry; - state.bufferProcessing = false; -} - -Writable.prototype._write = function (chunk, encoding, cb) { - cb(new Error('_write() is not implemented')); -}; - -Writable.prototype._writev = null; - -Writable.prototype.end = function (chunk, encoding, cb) { - var state = this._writableState; - - if (typeof chunk === 'function') { - cb = chunk; - chunk = null; - encoding = null; - } else if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } - - if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); - - // .end() fully uncorks - if (state.corked) { - state.corked = 1; - this.uncork(); - } - - // ignore unnecessary end() calls. - if (!state.ending && !state.finished) endWritable(this, state, cb); -}; - -function needFinish(state) { - return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; -} -function callFinal(stream, state) { - stream._final(function (err) { - state.pendingcb--; - if (err) { - stream.emit('error', err); - } - state.prefinished = true; - stream.emit('prefinish'); - finishMaybe(stream, state); - }); -} -function prefinish(stream, state) { - if (!state.prefinished && !state.finalCalled) { - if (typeof stream._final === 'function') { - state.pendingcb++; - state.finalCalled = true; - processNextTick(callFinal, stream, state); - } else { - state.prefinished = true; - stream.emit('prefinish'); - } - } -} - -function finishMaybe(stream, state) { - var need = needFinish(state); - if (need) { - prefinish(stream, state); - if (state.pendingcb === 0) { - state.finished = true; - stream.emit('finish'); - } - } - return need; -} - -function endWritable(stream, state, cb) { - state.ending = true; - finishMaybe(stream, state); - if (cb) { - if (state.finished) processNextTick(cb);else stream.once('finish', cb); - } - state.ended = true; - stream.writable = false; -} - -function onCorkedFinish(corkReq, state, err) { - var entry = corkReq.entry; - corkReq.entry = null; - while (entry) { - var cb = entry.callback; - state.pendingcb--; - cb(err); - entry = entry.next; - } - if (state.corkedRequestsFree) { - state.corkedRequestsFree.next = corkReq; - } else { - state.corkedRequestsFree = corkReq; - } -} - -Object.defineProperty(Writable.prototype, 'destroyed', { - get: function () { - if (this._writableState === undefined) { - return false; - } - return this._writableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (!this._writableState) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._writableState.destroyed = value; - } -}); - -Writable.prototype.destroy = destroyImpl.destroy; -Writable.prototype._undestroy = destroyImpl.undestroy; -Writable.prototype._destroy = function (err, cb) { - this.end(); - cb(err); -}; -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./_stream_duplex":57,"./internal/streams/destroy":63,"./internal/streams/stream":64,"_process":55,"core-util-is":41,"inherits":49,"process-nextick-args":54,"safe-buffer":69,"util-deprecate":72}],62:[function(require,module,exports){ -'use strict'; - -/**/ - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Buffer = require('safe-buffer').Buffer; -/**/ - -function copyBuffer(src, target, offset) { - src.copy(target, offset); -} - -module.exports = function () { - function BufferList() { - _classCallCheck(this, BufferList); - - this.head = null; - this.tail = null; - this.length = 0; - } - - BufferList.prototype.push = function push(v) { - var entry = { data: v, next: null }; - if (this.length > 0) this.tail.next = entry;else this.head = entry; - this.tail = entry; - ++this.length; - }; - - BufferList.prototype.unshift = function unshift(v) { - var entry = { data: v, next: this.head }; - if (this.length === 0) this.tail = entry; - this.head = entry; - ++this.length; - }; - - BufferList.prototype.shift = function shift() { - if (this.length === 0) return; - var ret = this.head.data; - if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; - --this.length; - return ret; - }; - - BufferList.prototype.clear = function clear() { - this.head = this.tail = null; - this.length = 0; - }; - - BufferList.prototype.join = function join(s) { - if (this.length === 0) return ''; - var p = this.head; - var ret = '' + p.data; - while (p = p.next) { - ret += s + p.data; - }return ret; - }; - - BufferList.prototype.concat = function concat(n) { - if (this.length === 0) return Buffer.alloc(0); - if (this.length === 1) return this.head.data; - var ret = Buffer.allocUnsafe(n >>> 0); - var p = this.head; - var i = 0; - while (p) { - copyBuffer(p.data, ret, i); - i += p.data.length; - p = p.next; - } - return ret; - }; - - return BufferList; -}(); -},{"safe-buffer":69}],63:[function(require,module,exports){ -'use strict'; - -/**/ - -var processNextTick = require('process-nextick-args'); -/**/ - -// undocumented cb() API, needed for core, not for public API -function destroy(err, cb) { - var _this = this; - - var readableDestroyed = this._readableState && this._readableState.destroyed; - var writableDestroyed = this._writableState && this._writableState.destroyed; - - if (readableDestroyed || writableDestroyed) { - if (cb) { - cb(err); - } else if (err && (!this._writableState || !this._writableState.errorEmitted)) { - processNextTick(emitErrorNT, this, err); - } - return; - } - - // we set destroyed to true before firing error callbacks in order - // to make it re-entrance safe in case destroy() is called within callbacks - - if (this._readableState) { - this._readableState.destroyed = true; - } - - // if this is a duplex stream mark the writable part as destroyed as well - if (this._writableState) { - this._writableState.destroyed = true; - } - - this._destroy(err || null, function (err) { - if (!cb && err) { - processNextTick(emitErrorNT, _this, err); - if (_this._writableState) { - _this._writableState.errorEmitted = true; - } - } else if (cb) { - cb(err); - } - }); -} - -function undestroy() { - if (this._readableState) { - this._readableState.destroyed = false; - this._readableState.reading = false; - this._readableState.ended = false; - this._readableState.endEmitted = false; - } - - if (this._writableState) { - this._writableState.destroyed = false; - this._writableState.ended = false; - this._writableState.ending = false; - this._writableState.finished = false; - this._writableState.errorEmitted = false; - } -} - -function emitErrorNT(self, err) { - self.emit('error', err); -} - -module.exports = { - destroy: destroy, - undestroy: undestroy -}; -},{"process-nextick-args":54}],64:[function(require,module,exports){ -module.exports = require('events').EventEmitter; - -},{"events":46}],65:[function(require,module,exports){ -module.exports = require('./readable').PassThrough - -},{"./readable":66}],66:[function(require,module,exports){ -exports = module.exports = require('./lib/_stream_readable.js'); -exports.Stream = exports; -exports.Readable = exports; -exports.Writable = require('./lib/_stream_writable.js'); -exports.Duplex = require('./lib/_stream_duplex.js'); -exports.Transform = require('./lib/_stream_transform.js'); -exports.PassThrough = require('./lib/_stream_passthrough.js'); - -},{"./lib/_stream_duplex.js":57,"./lib/_stream_passthrough.js":58,"./lib/_stream_readable.js":59,"./lib/_stream_transform.js":60,"./lib/_stream_writable.js":61}],67:[function(require,module,exports){ -module.exports = require('./readable').Transform - -},{"./readable":66}],68:[function(require,module,exports){ -module.exports = require('./lib/_stream_writable.js'); - -},{"./lib/_stream_writable.js":61}],69:[function(require,module,exports){ -/* eslint-disable node/no-deprecated-api */ -var buffer = require('buffer') -var Buffer = buffer.Buffer - -// alternative to using Object.keys for old browsers -function copyProps (src, dst) { - for (var key in src) { - dst[key] = src[key] - } -} -if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { - module.exports = buffer -} else { - // Copy properties from require('buffer') - copyProps(buffer, exports) - exports.Buffer = SafeBuffer -} - -function SafeBuffer (arg, encodingOrOffset, length) { - return Buffer(arg, encodingOrOffset, length) -} - -// Copy static methods from Buffer -copyProps(Buffer, SafeBuffer) - -SafeBuffer.from = function (arg, encodingOrOffset, length) { - if (typeof arg === 'number') { - throw new TypeError('Argument must not be a number') - } - return Buffer(arg, encodingOrOffset, length) -} - -SafeBuffer.alloc = function (size, fill, encoding) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - var buf = Buffer(size) - if (fill !== undefined) { - if (typeof encoding === 'string') { - buf.fill(fill, encoding) - } else { - buf.fill(fill) - } - } else { - buf.fill(0) - } - return buf -} - -SafeBuffer.allocUnsafe = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return Buffer(size) -} - -SafeBuffer.allocUnsafeSlow = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return buffer.SlowBuffer(size) -} - -},{"buffer":"buffer"}],70:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -module.exports = Stream; - -var EE = require('events').EventEmitter; -var inherits = require('inherits'); - -inherits(Stream, EE); -Stream.Readable = require('readable-stream/readable.js'); -Stream.Writable = require('readable-stream/writable.js'); -Stream.Duplex = require('readable-stream/duplex.js'); -Stream.Transform = require('readable-stream/transform.js'); -Stream.PassThrough = require('readable-stream/passthrough.js'); - -// Backwards-compat with node 0.4.x -Stream.Stream = Stream; - - - -// old-style streams. Note that the pipe method (the only relevant -// part of this class) is overridden in the Readable class. - -function Stream() { - EE.call(this); -} - -Stream.prototype.pipe = function(dest, options) { - var source = this; - - function ondata(chunk) { - if (dest.writable) { - if (false === dest.write(chunk) && source.pause) { - source.pause(); - } - } - } - - source.on('data', ondata); - - function ondrain() { - if (source.readable && source.resume) { - source.resume(); - } - } - - dest.on('drain', ondrain); - - // If the 'end' option is not supplied, dest.end() will be called when - // source gets the 'end' or 'close' events. Only dest.end() once. - if (!dest._isStdio && (!options || options.end !== false)) { - source.on('end', onend); - source.on('close', onclose); - } - - var didOnEnd = false; - function onend() { - if (didOnEnd) return; - didOnEnd = true; - - dest.end(); - } - - - function onclose() { - if (didOnEnd) return; - didOnEnd = true; - - if (typeof dest.destroy === 'function') dest.destroy(); - } - - // don't leave dangling pipes when there are errors. - function onerror(er) { - cleanup(); - if (EE.listenerCount(this, 'error') === 0) { - throw er; // Unhandled stream error in pipe. - } - } - - source.on('error', onerror); - dest.on('error', onerror); - - // remove all the event listeners that were added. - function cleanup() { - source.removeListener('data', ondata); - dest.removeListener('drain', ondrain); - - source.removeListener('end', onend); - source.removeListener('close', onclose); - - source.removeListener('error', onerror); - dest.removeListener('error', onerror); - - source.removeListener('end', cleanup); - source.removeListener('close', cleanup); - - dest.removeListener('close', cleanup); - } - - source.on('end', cleanup); - source.on('close', cleanup); - - dest.on('close', cleanup); - - dest.emit('pipe', source); - - // Allow for unix-like usage: A.pipe(B).pipe(C) - return dest; -}; - -},{"events":46,"inherits":49,"readable-stream/duplex.js":56,"readable-stream/passthrough.js":65,"readable-stream/readable.js":66,"readable-stream/transform.js":67,"readable-stream/writable.js":68}],71:[function(require,module,exports){ -'use strict'; - -var Buffer = require('safe-buffer').Buffer; - -var isEncoding = Buffer.isEncoding || function (encoding) { - encoding = '' + encoding; - switch (encoding && encoding.toLowerCase()) { - case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': - return true; - default: - return false; - } -}; - -function _normalizeEncoding(enc) { - if (!enc) return 'utf8'; - var retried; - while (true) { - switch (enc) { - case 'utf8': - case 'utf-8': - return 'utf8'; - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return 'utf16le'; - case 'latin1': - case 'binary': - return 'latin1'; - case 'base64': - case 'ascii': - case 'hex': - return enc; - default: - if (retried) return; // undefined - enc = ('' + enc).toLowerCase(); - retried = true; - } - } -}; - -// Do not cache `Buffer.isEncoding` when checking encoding names as some -// modules monkey-patch it to support additional encodings -function normalizeEncoding(enc) { - var nenc = _normalizeEncoding(enc); - if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); - return nenc || enc; -} - -// StringDecoder provides an interface for efficiently splitting a series of -// buffers into a series of JS strings without breaking apart multi-byte -// characters. -exports.StringDecoder = StringDecoder; -function StringDecoder(encoding) { - this.encoding = normalizeEncoding(encoding); - var nb; - switch (this.encoding) { - case 'utf16le': - this.text = utf16Text; - this.end = utf16End; - nb = 4; - break; - case 'utf8': - this.fillLast = utf8FillLast; - nb = 4; - break; - case 'base64': - this.text = base64Text; - this.end = base64End; - nb = 3; - break; - default: - this.write = simpleWrite; - this.end = simpleEnd; - return; - } - this.lastNeed = 0; - this.lastTotal = 0; - this.lastChar = Buffer.allocUnsafe(nb); -} - -StringDecoder.prototype.write = function (buf) { - if (buf.length === 0) return ''; - var r; - var i; - if (this.lastNeed) { - r = this.fillLast(buf); - if (r === undefined) return ''; - i = this.lastNeed; - this.lastNeed = 0; - } else { - i = 0; - } - if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); - return r || ''; -}; - -StringDecoder.prototype.end = utf8End; - -// Returns only complete characters in a Buffer -StringDecoder.prototype.text = utf8Text; - -// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer -StringDecoder.prototype.fillLast = function (buf) { - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); - this.lastNeed -= buf.length; -}; - -// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a -// continuation byte. -function utf8CheckByte(byte) { - if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; - return -1; -} - -// Checks at most 3 bytes at the end of a Buffer in order to detect an -// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) -// needed to complete the UTF-8 character (if applicable) are returned. -function utf8CheckIncomplete(self, buf, i) { - var j = buf.length - 1; - if (j < i) return 0; - var nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 1; - return nb; - } - if (--j < i) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 2; - return nb; - } - if (--j < i) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) { - if (nb === 2) nb = 0;else self.lastNeed = nb - 3; - } - return nb; - } - return 0; -} - -// Validates as many continuation bytes for a multi-byte UTF-8 character as -// needed or are available. If we see a non-continuation byte where we expect -// one, we "replace" the validated continuation bytes we've seen so far with -// UTF-8 replacement characters ('\ufffd'), to match v8's UTF-8 decoding -// behavior. The continuation byte check is included three times in the case -// where all of the continuation bytes for a character exist in the same buffer. -// It is also done this way as a slight performance increase instead of using a -// loop. -function utf8CheckExtraBytes(self, buf, p) { - if ((buf[0] & 0xC0) !== 0x80) { - self.lastNeed = 0; - return '\ufffd'.repeat(p); - } - if (self.lastNeed > 1 && buf.length > 1) { - if ((buf[1] & 0xC0) !== 0x80) { - self.lastNeed = 1; - return '\ufffd'.repeat(p + 1); - } - if (self.lastNeed > 2 && buf.length > 2) { - if ((buf[2] & 0xC0) !== 0x80) { - self.lastNeed = 2; - return '\ufffd'.repeat(p + 2); - } - } - } -} - -// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. -function utf8FillLast(buf) { - var p = this.lastTotal - this.lastNeed; - var r = utf8CheckExtraBytes(this, buf, p); - if (r !== undefined) return r; - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, p, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, p, 0, buf.length); - this.lastNeed -= buf.length; -} - -// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a -// partial character, the character's bytes are buffered until the required -// number of bytes are available. -function utf8Text(buf, i) { - var total = utf8CheckIncomplete(this, buf, i); - if (!this.lastNeed) return buf.toString('utf8', i); - this.lastTotal = total; - var end = buf.length - (total - this.lastNeed); - buf.copy(this.lastChar, 0, end); - return buf.toString('utf8', i, end); -} - -// For UTF-8, a replacement character for each buffered byte of a (partial) -// character needs to be added to the output. -function utf8End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) return r + '\ufffd'.repeat(this.lastTotal - this.lastNeed); - return r; -} - -// UTF-16LE typically needs two bytes per character, but even if we have an even -// number of bytes available, we need to check if we end on a leading/high -// surrogate. In that case, we need to wait for the next two bytes in order to -// decode the last character properly. -function utf16Text(buf, i) { - if ((buf.length - i) % 2 === 0) { - var r = buf.toString('utf16le', i); - if (r) { - var c = r.charCodeAt(r.length - 1); - if (c >= 0xD800 && c <= 0xDBFF) { - this.lastNeed = 2; - this.lastTotal = 4; - this.lastChar[0] = buf[buf.length - 2]; - this.lastChar[1] = buf[buf.length - 1]; - return r.slice(0, -1); - } - } - return r; - } - this.lastNeed = 1; - this.lastTotal = 2; - this.lastChar[0] = buf[buf.length - 1]; - return buf.toString('utf16le', i, buf.length - 1); -} - -// For UTF-16LE we do not explicitly append special replacement characters if we -// end on a partial character, we simply let v8 handle that. -function utf16End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) { - var end = this.lastTotal - this.lastNeed; - return r + this.lastChar.toString('utf16le', 0, end); - } - return r; -} - -function base64Text(buf, i) { - var n = (buf.length - i) % 3; - if (n === 0) return buf.toString('base64', i); - this.lastNeed = 3 - n; - this.lastTotal = 3; - if (n === 1) { - this.lastChar[0] = buf[buf.length - 1]; - } else { - this.lastChar[0] = buf[buf.length - 2]; - this.lastChar[1] = buf[buf.length - 1]; - } - return buf.toString('base64', i, buf.length - n); -} - -function base64End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); - return r; -} - -// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) -function simpleWrite(buf) { - return buf.toString(this.encoding); -} - -function simpleEnd(buf) { - return buf && buf.length ? this.write(buf) : ''; -} -},{"safe-buffer":69}],72:[function(require,module,exports){ -(function (global){ - -/** - * Module exports. - */ - -module.exports = deprecate; - -/** - * Mark that a method should not be used. - * Returns a modified function which warns once by default. - * - * If `localStorage.noDeprecation = true` is set, then it is a no-op. - * - * If `localStorage.throwDeprecation = true` is set, then deprecated functions - * will throw an Error when invoked. - * - * If `localStorage.traceDeprecation = true` is set, then deprecated functions - * will invoke `console.trace()` instead of `console.error()`. - * - * @param {Function} fn - the function to deprecate - * @param {String} msg - the string to print to the console when `fn` is invoked - * @returns {Function} a new "deprecated" version of `fn` - * @api public - */ - -function deprecate (fn, msg) { - if (config('noDeprecation')) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (config('throwDeprecation')) { - throw new Error(msg); - } else if (config('traceDeprecation')) { - console.trace(msg); - } else { - console.warn(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - - return deprecated; -} - -/** - * Checks `localStorage` for boolean values for the given `name`. - * - * @param {String} name - * @returns {Boolean} - * @api private - */ - -function config (name) { - // accessing global.localStorage can trigger a DOMException in sandboxed iframes - try { - if (!global.localStorage) return false; - } catch (_) { - return false; - } - var val = global.localStorage[name]; - if (null == val) return false; - return String(val).toLowerCase() === 'true'; -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],73:[function(require,module,exports){ -arguments[4][49][0].apply(exports,arguments) -},{"dup":49}],74:[function(require,module,exports){ -module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; -} -},{}],75:[function(require,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; -}; - - -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } - - if (process.noDeprecation === true) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - - return deprecated; -}; - - -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; -}; - - -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; - - -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; - -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } -} - - -function stylizeNoColor(str, styleType) { - return str; -} - - -function arrayToHash(array) { - var hash = {}; - - array.forEach(function(val, idx) { - hash[val] = true; - }); - - return hash; -} - - -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); -} - - -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} - - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} - - -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} - - -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; -} - - -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} - - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; - -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; - -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; - -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; - -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; - -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; - -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; - -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; - -exports.isBuffer = require('./support/isBuffer'); - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - - -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - - -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} - - -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; - - -/** - * Inherit the prototype methods from one constructor into another. - * - * The Function.prototype.inherits from lang.js rewritten as a standalone - * function (not on Function.prototype). NOTE: If this file is to be loaded - * during bootstrapping this function needs to be rewritten using some native - * functions as prototype setup using normal JavaScript does not work as - * expected during bootstrapping (see mirror.js in r114903). - * - * @param {function} ctor Constructor function which needs to inherit the - * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. - */ -exports.inherits = require('inherits'); - -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -}; - -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":74,"_process":55,"inherits":73}],"buffer":[function(require,module,exports){ -(function (global){ -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -/* eslint-disable no-proto */ - -'use strict' - -var base64 = require('base64-js') -var ieee754 = require('ieee754') -var isArray = require('isarray') - -exports.Buffer = Buffer -exports.SlowBuffer = SlowBuffer -exports.INSPECT_MAX_BYTES = 50 - -/** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Use Object implementation (most compatible, even IE6) - * - * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, - * Opera 11.6+, iOS 4.2+. - * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. - * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. - - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. - */ -Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined - ? global.TYPED_ARRAY_SUPPORT - : typedArraySupport() - -/* - * Export kMaxLength after typed array support is determined. - */ -exports.kMaxLength = kMaxLength() - -function typedArraySupport () { - try { - var arr = new Uint8Array(1) - arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }} - return arr.foo() === 42 && // typed array instances can be augmented - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` - } catch (e) { - return false - } -} - -function kMaxLength () { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff -} - -function createBuffer (that, length) { - if (kMaxLength() < length) { - throw new RangeError('Invalid typed array length') - } - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = new Uint8Array(length) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - if (that === null) { - that = new Buffer(length) - } - that.length = length - } - - return that -} - -/** - * The Buffer constructor returns instances of `Uint8Array` that have their - * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of - * `Uint8Array`, so the returned instances will have all the node `Buffer` methods - * and the `Uint8Array` methods. Square bracket notation works as expected -- it - * returns a single octet. - * - * The `Uint8Array` prototype remains unmodified. - */ - -function Buffer (arg, encodingOrOffset, length) { - if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { - return new Buffer(arg, encodingOrOffset, length) - } - - // Common case. - if (typeof arg === 'number') { - if (typeof encodingOrOffset === 'string') { - throw new Error( - 'If encoding is specified then the first argument must be a string' - ) - } - return allocUnsafe(this, arg) - } - return from(this, arg, encodingOrOffset, length) -} - -Buffer.poolSize = 8192 // not used by this implementation - -// TODO: Legacy, not needed anymore. Remove in next major version. -Buffer._augment = function (arr) { - arr.__proto__ = Buffer.prototype - return arr -} - -function from (that, value, encodingOrOffset, length) { - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number') - } - - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - return fromArrayBuffer(that, value, encodingOrOffset, length) - } - - if (typeof value === 'string') { - return fromString(that, value, encodingOrOffset) - } - - return fromObject(that, value) -} - -/** - * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError - * if value is a number. - * Buffer.from(str[, encoding]) - * Buffer.from(array) - * Buffer.from(buffer) - * Buffer.from(arrayBuffer[, byteOffset[, length]]) - **/ -Buffer.from = function (value, encodingOrOffset, length) { - return from(null, value, encodingOrOffset, length) -} - -if (Buffer.TYPED_ARRAY_SUPPORT) { - Buffer.prototype.__proto__ = Uint8Array.prototype - Buffer.__proto__ = Uint8Array - if (typeof Symbol !== 'undefined' && Symbol.species && - Buffer[Symbol.species] === Buffer) { - // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true - }) - } -} - -function assertSize (size) { - if (typeof size !== 'number') { - throw new TypeError('"size" argument must be a number') - } else if (size < 0) { - throw new RangeError('"size" argument must not be negative') - } -} - -function alloc (that, size, fill, encoding) { - assertSize(size) - if (size <= 0) { - return createBuffer(that, size) - } - if (fill !== undefined) { - // Only pay attention to encoding if it's a string. This - // prevents accidentally sending in a number that would - // be interpretted as a start offset. - return typeof encoding === 'string' - ? createBuffer(that, size).fill(fill, encoding) - : createBuffer(that, size).fill(fill) - } - return createBuffer(that, size) -} - -/** - * Creates a new filled Buffer instance. - * alloc(size[, fill[, encoding]]) - **/ -Buffer.alloc = function (size, fill, encoding) { - return alloc(null, size, fill, encoding) -} - -function allocUnsafe (that, size) { - assertSize(size) - that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < size; ++i) { - that[i] = 0 - } - } - return that -} - -/** - * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. - * */ -Buffer.allocUnsafe = function (size) { - return allocUnsafe(null, size) -} -/** - * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. - */ -Buffer.allocUnsafeSlow = function (size) { - return allocUnsafe(null, size) -} - -function fromString (that, string, encoding) { - if (typeof encoding !== 'string' || encoding === '') { - encoding = 'utf8' - } - - if (!Buffer.isEncoding(encoding)) { - throw new TypeError('"encoding" must be a valid string encoding') - } - - var length = byteLength(string, encoding) | 0 - that = createBuffer(that, length) - - var actual = that.write(string, encoding) - - if (actual !== length) { - // Writing a hex string, for example, that contains invalid characters will - // cause everything after the first invalid character to be ignored. (e.g. - // 'abxxcd' will be treated as 'ab') - that = that.slice(0, actual) - } - - return that -} - -function fromArrayLike (that, array) { - var length = array.length < 0 ? 0 : checked(array.length) | 0 - that = createBuffer(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 - } - return that -} - -function fromArrayBuffer (that, array, byteOffset, length) { - array.byteLength // this throws if `array` is not a valid ArrayBuffer - - if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('\'offset\' is out of bounds') - } - - if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('\'length\' is out of bounds') - } - - if (byteOffset === undefined && length === undefined) { - array = new Uint8Array(array) - } else if (length === undefined) { - array = new Uint8Array(array, byteOffset) - } else { - array = new Uint8Array(array, byteOffset, length) - } - - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = array - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that = fromArrayLike(that, array) - } - return that -} - -function fromObject (that, obj) { - if (Buffer.isBuffer(obj)) { - var len = checked(obj.length) | 0 - that = createBuffer(that, len) - - if (that.length === 0) { - return that - } - - obj.copy(that, 0, 0, len) - return that - } - - if (obj) { - if ((typeof ArrayBuffer !== 'undefined' && - obj.buffer instanceof ArrayBuffer) || 'length' in obj) { - if (typeof obj.length !== 'number' || isnan(obj.length)) { - return createBuffer(that, 0) - } - return fromArrayLike(that, obj) - } - - if (obj.type === 'Buffer' && isArray(obj.data)) { - return fromArrayLike(that, obj.data) - } - } - - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') -} - -function checked (length) { - // Note: cannot use `length < kMaxLength()` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') - } - return length | 0 -} - -function SlowBuffer (length) { - if (+length != length) { // eslint-disable-line eqeqeq - length = 0 - } - return Buffer.alloc(+length) -} - -Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) -} - -Buffer.compare = function compare (a, b) { - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') - } - - if (a === b) return 0 - - var x = a.length - var y = b.length - - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i] - y = b[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -Buffer.isEncoding = function isEncoding (encoding) { - switch (String(encoding).toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'latin1': - case 'binary': - case 'base64': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } -} - -Buffer.concat = function concat (list, length) { - if (!isArray(list)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - - if (list.length === 0) { - return Buffer.alloc(0) - } - - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; ++i) { - length += list[i].length - } - } - - var buffer = Buffer.allocUnsafe(length) - var pos = 0 - for (i = 0; i < list.length; ++i) { - var buf = list[i] - if (!Buffer.isBuffer(buf)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - buf.copy(buffer, pos) - pos += buf.length - } - return buffer -} - -function byteLength (string, encoding) { - if (Buffer.isBuffer(string)) { - return string.length - } - if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && - (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { - return string.byteLength - } - if (typeof string !== 'string') { - string = '' + string - } - - var len = string.length - if (len === 0) return 0 - - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'latin1': - case 'binary': - return len - case 'utf8': - case 'utf-8': - case undefined: - return utf8ToBytes(string).length - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return len * 2 - case 'hex': - return len >>> 1 - case 'base64': - return base64ToBytes(string).length - default: - if (loweredCase) return utf8ToBytes(string).length // assume utf8 - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} -Buffer.byteLength = byteLength - -function slowToString (encoding, start, end) { - var loweredCase = false - - // No need to verify that "this.length <= MAX_UINT32" since it's a read-only - // property of a typed array. - - // This behaves neither like String nor Uint8Array in that we set start/end - // to their upper/lower bounds if the value passed is out of range. - // undefined is handled specially as per ECMA-262 6th Edition, - // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. - if (start === undefined || start < 0) { - start = 0 - } - // Return early if start > this.length. Done here to prevent potential uint32 - // coercion fail below. - if (start > this.length) { - return '' - } - - if (end === undefined || end > this.length) { - end = this.length - } - - if (end <= 0) { - return '' - } - - // Force coersion to uint32. This will also coerce falsey/NaN values to 0. - end >>>= 0 - start >>>= 0 - - if (end <= start) { - return '' - } - - if (!encoding) encoding = 'utf8' - - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) - - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) - - case 'ascii': - return asciiSlice(this, start, end) - - case 'latin1': - case 'binary': - return latin1Slice(this, start, end) - - case 'base64': - return base64Slice(this, start, end) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } -} - -// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect -// Buffer instances. -Buffer.prototype._isBuffer = true - -function swap (b, n, m) { - var i = b[n] - b[n] = b[m] - b[m] = i -} - -Buffer.prototype.swap16 = function swap16 () { - var len = this.length - if (len % 2 !== 0) { - throw new RangeError('Buffer size must be a multiple of 16-bits') - } - for (var i = 0; i < len; i += 2) { - swap(this, i, i + 1) - } - return this -} - -Buffer.prototype.swap32 = function swap32 () { - var len = this.length - if (len % 4 !== 0) { - throw new RangeError('Buffer size must be a multiple of 32-bits') - } - for (var i = 0; i < len; i += 4) { - swap(this, i, i + 3) - swap(this, i + 1, i + 2) - } - return this -} - -Buffer.prototype.swap64 = function swap64 () { - var len = this.length - if (len % 8 !== 0) { - throw new RangeError('Buffer size must be a multiple of 64-bits') - } - for (var i = 0; i < len; i += 8) { - swap(this, i, i + 7) - swap(this, i + 1, i + 6) - swap(this, i + 2, i + 5) - swap(this, i + 3, i + 4) - } - return this -} - -Buffer.prototype.toString = function toString () { - var length = this.length | 0 - if (length === 0) return '' - if (arguments.length === 0) return utf8Slice(this, 0, length) - return slowToString.apply(this, arguments) -} - -Buffer.prototype.equals = function equals (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return true - return Buffer.compare(this, b) === 0 -} - -Buffer.prototype.inspect = function inspect () { - var str = '' - var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) str += ' ... ' - } - return '' -} - -Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { - if (!Buffer.isBuffer(target)) { - throw new TypeError('Argument must be a Buffer') - } - - if (start === undefined) { - start = 0 - } - if (end === undefined) { - end = target ? target.length : 0 - } - if (thisStart === undefined) { - thisStart = 0 - } - if (thisEnd === undefined) { - thisEnd = this.length - } - - if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { - throw new RangeError('out of range index') - } - - if (thisStart >= thisEnd && start >= end) { - return 0 - } - if (thisStart >= thisEnd) { - return -1 - } - if (start >= end) { - return 1 - } - - start >>>= 0 - end >>>= 0 - thisStart >>>= 0 - thisEnd >>>= 0 - - if (this === target) return 0 - - var x = thisEnd - thisStart - var y = end - start - var len = Math.min(x, y) - - var thisCopy = this.slice(thisStart, thisEnd) - var targetCopy = target.slice(start, end) - - for (var i = 0; i < len; ++i) { - if (thisCopy[i] !== targetCopy[i]) { - x = thisCopy[i] - y = targetCopy[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, -// OR the last index of `val` in `buffer` at offset <= `byteOffset`. -// -// Arguments: -// - buffer - a Buffer to search -// - val - a string, Buffer, or number -// - byteOffset - an index into `buffer`; will be clamped to an int32 -// - encoding - an optional encoding, relevant is val is a string -// - dir - true for indexOf, false for lastIndexOf -function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { - // Empty buffer means no match - if (buffer.length === 0) return -1 - - // Normalize byteOffset - if (typeof byteOffset === 'string') { - encoding = byteOffset - byteOffset = 0 - } else if (byteOffset > 0x7fffffff) { - byteOffset = 0x7fffffff - } else if (byteOffset < -0x80000000) { - byteOffset = -0x80000000 - } - byteOffset = +byteOffset // Coerce to Number. - if (isNaN(byteOffset)) { - // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer - byteOffset = dir ? 0 : (buffer.length - 1) - } - - // Normalize byteOffset: negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = buffer.length + byteOffset - if (byteOffset >= buffer.length) { - if (dir) return -1 - else byteOffset = buffer.length - 1 - } else if (byteOffset < 0) { - if (dir) byteOffset = 0 - else return -1 - } - - // Normalize val - if (typeof val === 'string') { - val = Buffer.from(val, encoding) - } - - // Finally, search either indexOf (if dir is true) or lastIndexOf - if (Buffer.isBuffer(val)) { - // Special case: looking for empty string/buffer always fails - if (val.length === 0) { - return -1 - } - return arrayIndexOf(buffer, val, byteOffset, encoding, dir) - } else if (typeof val === 'number') { - val = val & 0xFF // Search for a byte value [0-255] - if (Buffer.TYPED_ARRAY_SUPPORT && - typeof Uint8Array.prototype.indexOf === 'function') { - if (dir) { - return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) - } else { - return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) - } - } - return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) - } - - throw new TypeError('val must be string, number or Buffer') -} - -function arrayIndexOf (arr, val, byteOffset, encoding, dir) { - var indexSize = 1 - var arrLength = arr.length - var valLength = val.length - - if (encoding !== undefined) { - encoding = String(encoding).toLowerCase() - if (encoding === 'ucs2' || encoding === 'ucs-2' || - encoding === 'utf16le' || encoding === 'utf-16le') { - if (arr.length < 2 || val.length < 2) { - return -1 - } - indexSize = 2 - arrLength /= 2 - valLength /= 2 - byteOffset /= 2 - } - } - - function read (buf, i) { - if (indexSize === 1) { - return buf[i] - } else { - return buf.readUInt16BE(i * indexSize) - } - } - - var i - if (dir) { - var foundIndex = -1 - for (i = byteOffset; i < arrLength; i++) { - if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === valLength) return foundIndex * indexSize - } else { - if (foundIndex !== -1) i -= i - foundIndex - foundIndex = -1 - } - } - } else { - if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength - for (i = byteOffset; i >= 0; i--) { - var found = true - for (var j = 0; j < valLength; j++) { - if (read(arr, i + j) !== read(val, j)) { - found = false - break - } - } - if (found) return i - } - } - - return -1 -} - -Buffer.prototype.includes = function includes (val, byteOffset, encoding) { - return this.indexOf(val, byteOffset, encoding) !== -1 -} - -Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, true) -} - -Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, false) -} - -function hexWrite (buf, string, offset, length) { - offset = Number(offset) || 0 - var remaining = buf.length - offset - if (!length) { - length = remaining - } else { - length = Number(length) - if (length > remaining) { - length = remaining - } - } - - // must be an even number of digits - var strLen = string.length - if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') - - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; ++i) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) return i - buf[offset + i] = parsed - } - return i -} - -function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) -} - -function asciiWrite (buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) -} - -function latin1Write (buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) -} - -function base64Write (buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) -} - -function ucs2Write (buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) -} - -Buffer.prototype.write = function write (string, offset, length, encoding) { - // Buffer#write(string) - if (offset === undefined) { - encoding = 'utf8' - length = this.length - offset = 0 - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - encoding = offset - length = this.length - offset = 0 - // Buffer#write(string, offset[, length][, encoding]) - } else if (isFinite(offset)) { - offset = offset | 0 - if (isFinite(length)) { - length = length | 0 - if (encoding === undefined) encoding = 'utf8' - } else { - encoding = length - length = undefined - } - // legacy write(string, encoding, offset, length) - remove in v0.13 - } else { - throw new Error( - 'Buffer.write(string, encoding, offset[, length]) is no longer supported' - ) - } - - var remaining = this.length - offset - if (length === undefined || length > remaining) length = remaining - - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('Attempt to write outside buffer bounds') - } - - if (!encoding) encoding = 'utf8' - - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) - - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) - - case 'ascii': - return asciiWrite(this, string, offset, length) - - case 'latin1': - case 'binary': - return latin1Write(this, string, offset, length) - - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} - -Buffer.prototype.toJSON = function toJSON () { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) - } -} - -function base64Slice (buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } -} - -function utf8Slice (buf, start, end) { - end = Math.min(buf.length, end) - var res = [] - - var i = start - while (i < end) { - var firstByte = buf[i] - var codePoint = null - var bytesPerSequence = (firstByte > 0xEF) ? 4 - : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 - - if (i + bytesPerSequence <= end) { - var secondByte, thirdByte, fourthByte, tempCodePoint - - switch (bytesPerSequence) { - case 1: - if (firstByte < 0x80) { - codePoint = firstByte - } - break - case 2: - secondByte = buf[i + 1] - if ((secondByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) - if (tempCodePoint > 0x7F) { - codePoint = tempCodePoint - } - } - break - case 3: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) - if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { - codePoint = tempCodePoint - } - } - break - case 4: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - fourthByte = buf[i + 3] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) - if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { - codePoint = tempCodePoint - } - } - } - } - - if (codePoint === null) { - // we did not generate a valid codePoint so insert a - // replacement char (U+FFFD) and advance only 1 byte - codePoint = 0xFFFD - bytesPerSequence = 1 - } else if (codePoint > 0xFFFF) { - // encode to utf16 (surrogate pair dance) - codePoint -= 0x10000 - res.push(codePoint >>> 10 & 0x3FF | 0xD800) - codePoint = 0xDC00 | codePoint & 0x3FF - } - - res.push(codePoint) - i += bytesPerSequence - } - - return decodeCodePointsArray(res) -} - -// Based on http://stackoverflow.com/a/22747272/680742, the browser with -// the lowest limit is Chrome, with 0x10000 args. -// We go 1 magnitude less, for safety -var MAX_ARGUMENTS_LENGTH = 0x1000 - -function decodeCodePointsArray (codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() - } - - // Decode in chunks to avoid "call stack size exceeded". - var res = '' - var i = 0 - while (i < len) { - res += String.fromCharCode.apply( - String, - codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) - ) - } - return res -} - -function asciiSlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i] & 0x7F) - } - return ret -} - -function latin1Slice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i]) - } - return ret -} - -function hexSlice (buf, start, end) { - var len = buf.length - - if (!start || start < 0) start = 0 - if (!end || end < 0 || end > len) end = len - - var out = '' - for (var i = start; i < end; ++i) { - out += toHex(buf[i]) - } - return out -} - -function utf16leSlice (buf, start, end) { - var bytes = buf.slice(start, end) - var res = '' - for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) - } - return res -} - -Buffer.prototype.slice = function slice (start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end - - if (start < 0) { - start += len - if (start < 0) start = 0 - } else if (start > len) { - start = len - } - - if (end < 0) { - end += len - if (end < 0) end = 0 - } else if (end > len) { - end = len - } - - if (end < start) end = start - - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = this.subarray(start, end) - newBuf.__proto__ = Buffer.prototype - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; ++i) { - newBuf[i] = this[i + start] - } - } - - return newBuf -} - -/* - * Need to make sure that buffer isn't trying to write out of bounds. - */ -function checkOffset (offset, ext, length) { - if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') - if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') -} - -Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - - return val -} - -Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } - - return val -} - -Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - return this[offset] -} - -Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return this[offset] | (this[offset + 1] << 8) -} - -Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - return (this[offset] << 8) | this[offset + 1] -} - -Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) -} - -Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) -} - -Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { - if (!noAssert) checkOffset(offset, 1, this.length) - if (!(this[offset] & 0x80)) return (this[offset]) - return ((0xff - this[offset] + 1) * -1) -} - -Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) -} - -Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) -} - -Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, true, 23, 4) -} - -Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, false, 23, 4) -} - -Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, true, 52, 8) -} - -Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, false, 52, 8) -} - -function checkInt (buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') - if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') - if (offset + ext > buf.length) throw new RangeError('Index out of range') -} - -Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - byteLength = byteLength | 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - this[offset] = (value & 0xff) - return offset + 1 -} - -function objectWriteUInt16 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } -} - -Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} - -Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} - -function objectWriteUInt32 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffffffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } -} - -Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} - -Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} - -Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = 0 - var mul = 1 - var sub = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = byteLength - 1 - var mul = 1 - var sub = 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) - if (value < 0) value = 0xff + value + 1 - this[offset] = (value & 0xff) - return offset + 1 -} - -Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } - return offset + 2 -} - -Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } - return offset + 2 -} - -Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } - return offset + 4 -} - -Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { - value = +value - offset = offset | 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (value < 0) value = 0xffffffff + value + 1 - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } - return offset + 4 -} - -function checkIEEE754 (buf, value, offset, ext, max, min) { - if (offset + ext > buf.length) throw new RangeError('Index out of range') - if (offset < 0) throw new RangeError('Index out of range') -} - -function writeFloat (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) - } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 -} - -Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) -} - -function writeDouble (buf, value, offset, littleEndian, noAssert) { - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 -} - -Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) -} - -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function copy (target, targetStart, start, end) { - if (!start) start = 0 - if (!end && end !== 0) end = this.length - if (targetStart >= target.length) targetStart = target.length - if (!targetStart) targetStart = 0 - if (end > 0 && end < start) end = start - - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 - - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') - if (end < 0) throw new RangeError('sourceEnd out of bounds') - - // Are we oob? - if (end > this.length) end = this.length - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start - } - - var len = end - start - var i - - if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (i = len - 1; i >= 0; --i) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; ++i) { - target[i + targetStart] = this[i + start] - } - } else { - Uint8Array.prototype.set.call( - target, - this.subarray(start, start + len), - targetStart - ) - } - - return len -} - -// Usage: -// buffer.fill(number[, offset[, end]]) -// buffer.fill(buffer[, offset[, end]]) -// buffer.fill(string[, offset[, end]][, encoding]) -Buffer.prototype.fill = function fill (val, start, end, encoding) { - // Handle string cases: - if (typeof val === 'string') { - if (typeof start === 'string') { - encoding = start - start = 0 - end = this.length - } else if (typeof end === 'string') { - encoding = end - end = this.length - } - if (val.length === 1) { - var code = val.charCodeAt(0) - if (code < 256) { - val = code - } - } - if (encoding !== undefined && typeof encoding !== 'string') { - throw new TypeError('encoding must be a string') - } - if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { - throw new TypeError('Unknown encoding: ' + encoding) - } - } else if (typeof val === 'number') { - val = val & 255 - } - - // Invalid ranges are not set to a default, so can range check early. - if (start < 0 || this.length < start || this.length < end) { - throw new RangeError('Out of range index') - } - - if (end <= start) { - return this - } - - start = start >>> 0 - end = end === undefined ? this.length : end >>> 0 - - if (!val) val = 0 - - var i - if (typeof val === 'number') { - for (i = start; i < end; ++i) { - this[i] = val - } - } else { - var bytes = Buffer.isBuffer(val) - ? val - : utf8ToBytes(new Buffer(val, encoding).toString()) - var len = bytes.length - for (i = 0; i < end - start; ++i) { - this[i + start] = bytes[i % len] - } - } - - return this -} - -// HELPER FUNCTIONS -// ================ - -var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g - -function base64clean (str) { - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).replace(INVALID_BASE64_RE, '') - // Node converts strings with length < 2 to '' - if (str.length < 2) return '' - // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not - while (str.length % 4 !== 0) { - str = str + '=' - } - return str -} - -function stringtrim (str) { - if (str.trim) return str.trim() - return str.replace(/^\s+|\s+$/g, '') -} - -function toHex (n) { - if (n < 16) return '0' + n.toString(16) - return n.toString(16) -} - -function utf8ToBytes (string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] - - for (var i = 0; i < length; ++i) { - codePoint = string.charCodeAt(i) - - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } - - // valid lead - leadSurrogate = codePoint - - continue - } - - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - leadSurrogate = codePoint - continue - } - - // valid surrogate pair - codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - } - - leadSurrogate = null - - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) break - bytes.push(codePoint) - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) break - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) break - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) break - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else { - throw new Error('Invalid code point') - } - } - - return bytes -} - -function asciiToBytes (str) { - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push(str.charCodeAt(i) & 0xFF) - } - return byteArray -} - -function utf16leToBytes (str, units) { - var c, hi, lo - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - if ((units -= 2) < 0) break - - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } - - return byteArray -} - -function base64ToBytes (str) { - return base64.toByteArray(base64clean(str)) -} - -function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; ++i) { - if ((i + offset >= dst.length) || (i >= src.length)) break - dst[i + offset] = src[i] - } - return i -} - -function isnan (val) { - return val !== val // eslint-disable-line no-self-compare -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"base64-js":37,"ieee754":48,"isarray":51}]},{},[1]); diff --git a/src/bin/test/run.js b/src/bin/test/run.js deleted file mode 100644 index 98128a2..0000000 --- a/src/bin/test/run.js +++ /dev/null @@ -1,2 +0,0 @@ -// mocha.checkLeaks(); -mocha.run(); diff --git a/src/bin/test/setup.js b/src/bin/test/setup.js deleted file mode 100644 index 2486cf0..0000000 --- a/src/bin/test/setup.js +++ /dev/null @@ -1,4 +0,0 @@ -window.expect = chai.expect -window.assert = chai.assert - -mocha.setup({ ui: 'bdd', reporter: 'spec', useColors: true }) diff --git a/src/compiler.rs b/src/compiler.rs index 1ef9586..f7a7a5f 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,10 +1,6 @@ use crate::errors::*; -use std::path::{Path, PathBuf}; - -pub struct Compiler { - pub root: PathBuf, -} +use crate::module_resolver::{ ModuleResolver }; pub struct ModuleInfo { pub module_id: String, @@ -12,19 +8,18 @@ pub struct ModuleInfo { pub source_code: String, } +pub struct Compiler { + pub module_resolvers: Vec>, +} + impl Compiler { #[allow(dead_code)] - pub fn new(root: Option<&Path>) -> Self { - let root = match root { - None => std::env::current_dir().expect("invalid current directory"), - Some(path) => path.to_path_buf(), - }; - - Self { root } + pub fn new(module_resolvers: Vec>) -> Self { + Self { module_resolvers } } pub fn fetch_module( - self: &Self, + &self, module_specifier: &str, containing_file: &str, ) -> FlyResult { @@ -32,73 +27,12 @@ impl Compiler { "fetch_module {} from {}", &module_specifier, &containing_file ); - let (module_id, file_name) = self.resolve_module(&module_specifier, &containing_file)?; - let source_code = std::fs::read_to_string(&module_id)?; - Ok(ModuleInfo { - module_id: module_id, - file_name: file_name, - source_code: source_code, - }) - } - - #[allow(dead_code)] - pub fn resolve_module( - self: &Self, - module_specifier: &str, - containing_file: &str, - ) -> FlyResult<(String, String)> { - println!( - "resolve_module {} from {}", - module_specifier, containing_file - ); - - let mut base = PathBuf::from(containing_file); - if base.is_file() { - base.pop(); - } - - let mut module_id = base.join(module_specifier); //.canonicalize().unwrap(); - info!("trying module {}", module_id.display()); - - if module_id.is_file() { - return Ok(( - module_id.to_str().unwrap().to_string(), - module_id - .canonicalize() - .unwrap() - .to_str() - .unwrap() - .to_owned(), - )); - } - let did_set = module_id.set_extension("ts"); - info!("trying module {} ({})", module_id.display(), did_set); - if module_id.is_file() { - return Ok(( - module_id.to_str().unwrap().to_string(), - module_id - .canonicalize() - .unwrap() - .to_str() - .unwrap() - .to_owned(), - )); + for resolver in &self.module_resolvers { + match resolver.resolve_module(module_specifier, containing_file) { + Ok(m) => return Ok(m), + Err(_err) => info!("resolver failed moving on"), + }; } - let did_set = module_id.set_extension("js"); - info!("trying module {} ({})", module_id.display(), did_set); - if module_id.is_file() { - return Ok(( - module_id.to_str().unwrap().to_string(), - module_id - .canonicalize() - .unwrap() - .to_str() - .unwrap() - .to_owned(), - )); - } - error!("NOPE"); - Err(FlyError::from(format!( "Could not resolve {} from {}", module_specifier, containing_file @@ -141,22 +75,24 @@ mod tests { ), ]; let current_dir = std::env::current_dir().expect("current_dir failed"); - let compiler = Compiler::new(None); + let local_disk_resolver = LocalDiskModuleResolver::new(None); + let resolvers = vec![Box::new(local_disk_resolver) as Box]; + let compiler = Compiler::new(resolvers); for &test in cases.iter() { let specifier = String::from(test.0).replace("", current_dir.to_str().unwrap()); let containing_file = String::from(test.1).replace("", current_dir.to_str().unwrap()); ; - let (module_id, filename) = compiler - .resolve_module(&specifier, &containing_file) + let module_info = compiler + .fetch_module(&specifier, &containing_file) .unwrap(); assert_eq!( String::from(test.2).replace("", current_dir.to_str().unwrap()), - module_id, + module_info.module_id, ); assert_eq!( String::from(test.3).replace("", current_dir.to_str().unwrap()), - filename, + module_info.file_name, ); } } diff --git a/src/data_store.rs b/src/data_store.rs index fc79a5a..02978c1 100644 --- a/src/data_store.rs +++ b/src/data_store.rs @@ -13,6 +13,13 @@ pub trait DataStore { key: String, data: String, ) -> Box + Send>; + fn incr( + &self, + coll: String, + key: String, + field: String, + amount: i32, + ) -> Box + Send>; fn drop_coll(&self, coll: String) -> Box + Send>; } diff --git a/src/dns_server.rs b/src/dns_server.rs index ddcc6da..c963bfb 100644 --- a/src/dns_server.rs +++ b/src/dns_server.rs @@ -1,38 +1,33 @@ -extern crate tokio_udp; +use tokio_udp::UdpSocket; -use self::tokio_udp::UdpSocket; +use trust_dns_server::authority::{AuthLookup, MessageResponseBuilder}; -extern crate trust_dns as dns; -extern crate trust_dns_proto; -extern crate trust_dns_server; +use trust_dns::proto::op::header::Header; +use trust_dns::proto::op::response_code::ResponseCode; +use trust_dns::proto::rr::{Record, RrsetRecords}; +use trust_dns_server::authority::authority::LookupRecords; -use self::trust_dns_server::authority::{AuthLookup, MessageResponseBuilder}; - -use self::trust_dns_proto::op::header::Header; -use self::trust_dns_proto::op::response_code::ResponseCode; -use self::trust_dns_proto::rr::{Record, RrsetRecords}; -use self::trust_dns_server::authority::authority::LookupRecords; - -use self::trust_dns_server::server::{Request, RequestHandler, ResponseHandler, ServerFuture}; use std::io; +use trust_dns_server::server::{Request, RequestHandler, ResponseHandler, ServerFuture}; -use std::net::SocketAddr; +use std::sync::{ RwLock, Arc }; -extern crate flatbuffers; +use std::net::SocketAddr; use tokio::prelude::*; -use crate::ops::dns::*; -use crate::runtime::{EventResponseChannel, JsEvent}; -use crate::{get_next_stream_id, RuntimeSelector}; +use crate::{get_next_stream_id, RuntimeManager}; + +use crate::js::*; +use crate::utils::*; pub struct DnsServer { addr: SocketAddr, - selector: &'static (RuntimeSelector + Send + Sync), + selector: Arc>, } impl DnsServer { - pub fn new(addr: SocketAddr, selector: &'static (RuntimeSelector + Send + Sync)) -> Self { + pub fn new(addr: SocketAddr, selector: Arc>) -> Self { DnsServer { addr, selector } } pub fn start(self) { @@ -60,12 +55,14 @@ impl RequestHandler for DnsServer { let eid = get_next_stream_id(); let queries = req.message.queries(); - let mut name = dns::rr::Name::from(queries[0].name().clone()) + let mut name = trust_dns::rr::Name::from(queries[0].name().clone()) .trim_to(2) .to_utf8(); name.pop(); - let rt = match self.selector.get_by_hostname(name.as_str()) { + debug!("Dns request for hostname: {}", name); + + let rt = match self.selector.read().unwrap().get_by_hostname(name.as_str()) { Ok(maybe_rt) => match maybe_rt { Some(rt) => rt, None => { @@ -75,7 +72,7 @@ impl RequestHandler for DnsServer { req.message.op_code(), ResponseCode::ServFail, ), - ) + ); } }, Err(e) => { @@ -90,7 +87,9 @@ impl RequestHandler for DnsServer { } }; - let rx = match rt.dispatch_event( + let rt_lock = rt.read().unwrap(); + + let rx = match rt_lock.dispatch_event( eid, JsEvent::Resolv(JsDnsRequest { id: eid, @@ -105,7 +104,7 @@ impl RequestHandler for DnsServer { req.message.op_code(), ResponseCode::ServFail, ), - ) + ); } Some(Err(e)) => { error!("error sending js dns request: {:?}", e); diff --git a/src/errors.rs b/src/errors.rs index 8302108..70abf94 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,9 +1,10 @@ -use hyper; pub use crate::msg::ErrorKind; +use hyper; use std; use std::fmt; use std::io; use url; +use crate::runtime_manager::RuntimeManagerError; pub type FlyResult = Result; @@ -14,16 +15,22 @@ pub struct FlyError { #[derive(Debug)] enum Repr { - Simple(String), + Simple(ErrorKind, String), IoErr(io::Error), UrlErr(url::ParseError), HyperErr(hyper::Error), } +pub fn new(kind: ErrorKind, msg: String) -> FlyError { + FlyError { + repr: Repr::Simple(kind, msg), + } +} + impl FlyError { pub fn kind(&self) -> ErrorKind { match self.repr { - Repr::Simple(_) => ErrorKind::String, + Repr::Simple(kind, ref _msg) => kind, Repr::IoErr(ref err) => { use std::io::ErrorKind::*; match err.kind() { @@ -87,7 +94,7 @@ impl fmt::Display for FlyError { Repr::IoErr(ref err) => err.fmt(f), Repr::UrlErr(ref err) => err.fmt(f), Repr::HyperErr(ref err) => err.fmt(f), - Repr::Simple(ref s) => write!(f, "{}", s), + Repr::Simple(_kind, ref s) => write!(f, "{}", s), } } } @@ -98,7 +105,7 @@ impl std::error::Error for FlyError { Repr::IoErr(ref err) => err.description(), Repr::UrlErr(ref err) => err.description(), Repr::HyperErr(ref err) => err.description(), - Repr::Simple(ref s) => s.as_str(), + Repr::Simple(_kind, ref s) => s.as_str(), } } @@ -107,7 +114,7 @@ impl std::error::Error for FlyError { Repr::IoErr(ref err) => Some(err), Repr::UrlErr(ref err) => Some(err), Repr::HyperErr(ref err) => Some(err), - Repr::Simple(_) => None, + Repr::Simple(_, _) => None, } } } @@ -143,7 +150,35 @@ impl From for FlyError { #[inline] fn from(err: String) -> FlyError { FlyError { - repr: Repr::Simple(err), + repr: Repr::Simple(ErrorKind::String, err), } } } + +impl From for FlyError { + #[inline] + fn from(_: RuntimeManagerError) -> FlyError { + FlyError { + repr: Repr::Simple( + ErrorKind::String, + "Errored with runtime manager error.".to_string(), + ), + } + } +} + +impl From<()> for FlyError { + #[inline] + fn from(_: ()) -> FlyError { + FlyError { + repr: Repr::Simple( + ErrorKind::String, + "Errored with non message error.".to_string(), + ), + } + } +} + +pub fn permission_denied() -> FlyError { + new(ErrorKind::PermissionDenied, "permission denied".to_owned()) +} diff --git a/src/fixed_runtime_selector.rs b/src/fixed_runtime_selector.rs index f25401a..e04e1d1 100644 --- a/src/fixed_runtime_selector.rs +++ b/src/fixed_runtime_selector.rs @@ -16,3 +16,10 @@ impl RuntimeSelector for FixedRuntimeSelector { Ok(Some(self.runtime.ptr.to_runtime())) } } + +impl Drop for FixedRuntimeSelector { + fn drop(&mut self) { + debug!("Dropping FixedRuntime, will dispose of runtime."); + self.runtime.dispose(); + } +} diff --git a/src/http_server.rs b/src/http_server.rs index 1b9e5d2..709decb 100644 --- a/src/http_server.rs +++ b/src/http_server.rs @@ -1,9 +1,10 @@ use futures::{future, Future, Stream}; -use std::net::SocketAddr; +use std::net::{IpAddr, SocketAddr}; +use crate::js::*; use crate::metrics::*; -use crate::runtime::{EventResponseChannel, JsBody, JsEvent, JsHttpRequest, JsHttpResponse}; -use crate::{get_next_stream_id, RuntimeSelector}; +use crate::utils::*; +use crate::{get_next_stream_id, RuntimeManager}; use hyper::body::Payload; use hyper::{header, Body, Request, Response, StatusCode}; @@ -12,35 +13,62 @@ use floating_duration::TimeAsFloat; use std::io; use std::time; +use std::sync::{ RwLock, Arc }; + +use slog::{o, slog_debug, slog_error, slog_info}; + type BoxedResponseFuture = Box, Error = futures::Canceled> + Send>; lazy_static! { // static ref SERVER_HEADER: &'static str = static ref SERVER_HEADER_VALUE: header::HeaderValue = { - let s = format!("Fly ({})", env!("GIT_HASH")); + let s = format!("Fly ({})", crate::BUILD_VERSION); header::HeaderValue::from_str(s.as_str()).unwrap() }; } +struct RequestInfo { + timer: time::Instant, + request_id: String, + remote_addr: IpAddr, + url: String, + method: String, +} + pub fn serve_http( tls: bool, req: Request, - selector: &RuntimeSelector, + selector: Arc>, remote_addr: SocketAddr, ) -> BoxedResponseFuture { - let timer = time::Instant::now(); - debug!("serving http: {}", req.uri()); - let req_id = ksuid::Ksuid::generate().to_base62(); + let mut request_info = RequestInfo { + timer: time::Instant::now(), + request_id: ksuid::Ksuid::generate().to_base62(), + remote_addr: remote_addr.ip(), + url: req.uri().to_string(), + method: req.method().to_string(), + }; + + let logger = slog_scope::logger().new(o!( + "request_id" => request_info.request_id.to_owned(), + "client_ip" => remote_addr, + "uri" => request_info.url.to_string(), + "method" => request_info.method.to_owned() + )); + + slog_debug!(logger, "begin request"); + let (parts, body) = req.into_parts(); let host = if parts.version == hyper::Version::HTTP_2 { match parts.uri.host() { Some(h) => h, None => { return future_response( - simple_response(req_id, StatusCode::NOT_FOUND, None), - timer, + simple_response(StatusCode::NOT_FOUND, None), + request_info, + logger, None, - ) + ); } } } else { @@ -48,69 +76,91 @@ pub fn serve_http( Some(v) => match v.to_str() { Ok(s) => s, Err(e) => { - error!("error stringifying host: {}", e); + slog_error!(logger, "error stringifying host: {}", e); return future_response( - simple_response( - req_id, - StatusCode::BAD_REQUEST, - Some(Body::from("Bad host header")), - ), - timer, + simple_response(StatusCode::BAD_REQUEST, Some("Bad host header")), + request_info, + logger, None, ); } }, None => { return future_response( - simple_response(req_id, StatusCode::NOT_FOUND, None), - timer, + simple_response(StatusCode::NOT_FOUND, None), + request_info, + logger, None, - ) + ); } } }; - let rt = match selector.get_by_hostname(host) { + let url: String = if parts.version == hyper::Version::HTTP_2 { + format!("{}", parts.uri) + } else { + format!( + "{}://{}{}", + if tls { "https" } else { "http" }, + host, + parts.uri.path_and_query().unwrap() + ) + }; + + request_info.url = url.to_owned(); + + let rt_man_lock = selector.read().unwrap(); + + let rt = match rt_man_lock.get_by_hostname(host) { Ok(maybe_rt) => match maybe_rt { Some(rt) => rt, None => { return future_response( - simple_response( - req_id, - StatusCode::NOT_FOUND, - Some(Body::from("app not found")), - ), - timer, + simple_response(StatusCode::NOT_FOUND, Some("app not found")), + request_info, + logger, None, ); } }, Err(e) => { - error!("error getting runtime: {:?}", e); + slog_error!(logger, "error getting runtime: {:?}", e); return future_response( - simple_response(req_id, StatusCode::SERVICE_UNAVAILABLE, None), - timer, + simple_response(StatusCode::SERVICE_UNAVAILABLE, None), + request_info, + logger, None, ); } }; - let url: String = if parts.version == hyper::Version::HTTP_2 { - format!("{}", parts.uri) + let stream_id = get_next_stream_id(); + + let rt_lock = rt.read().unwrap(); + let rt_name = rt_lock.name.clone(); + let rt_version = rt_lock.version.clone(); + let logger = + logger.new(o!("app_name" => rt_name.to_owned(), "app_version" => rt_version.to_owned())); + + let inbound_data = + DATA_IN_TOTAL.with_label_values(&[rt_name.as_str(), rt_version.as_str(), "http_request"]); + let outbound_data = + DATA_OUT_TOTAL.with_label_values(&[rt_name.as_str(), rt_version.as_str(), "http_response"]); + + let body = if body.is_end_stream() { + None } else { - format!( - "{}://{}{}", - if tls { "https" } else { "http" }, - host, - parts.uri.path_and_query().unwrap() - ) + Some(JsBody::BoxedStream(Box::new({ + body.map_err(|e| format!("{}", e).into()) + .map(move |chunk| chunk.into_bytes().to_vec()) + .inspect(move |bytes| inbound_data.inc_by(bytes.len() as i64)) + }))) }; - let stream_id = get_next_stream_id(); - let rt_name = rt.name.clone(); - let rt_version = rt.version.clone(); + let rt_name = rt_lock.name.clone(); + let rt_version = rt_lock.version.clone(); - match rt.dispatch_event( + match rt_lock.dispatch_event( stream_id, JsEvent::Fetch(JsHttpRequest { id: stream_id, @@ -118,123 +168,72 @@ pub fn serve_http( remote_addr: remote_addr, url: url, headers: parts.headers.clone(), - body: if body.is_end_stream() { - None - } else { - Some(JsBody::BoxedStream(Box::new( - body.map_err(|e| format!("{}", e).into()).map(move |chunk| { - let bytes = chunk.into_bytes(); - DATA_IN_TOTAL - .with_label_values(&[ - rt_name.as_str(), - rt_version.as_str(), - "http_request", - ]) - .inc_by(bytes.len() as i64); - bytes.to_vec() - }), - ))) - }, + body, }), ) { None => future_response( - simple_response(req_id, StatusCode::SERVICE_UNAVAILABLE, None), - timer, - Some((rt.name.clone(), rt.version.clone())), + simple_response(StatusCode::SERVICE_UNAVAILABLE, None), + request_info, + logger, + Some((rt_lock.name.clone(), rt_version.clone())), ), Some(Err(e)) => { - error!("error sending js http request: {:?}", e); + slog_error!(logger, "error sending js http request: {:?}", e); future_response( - simple_response(req_id, StatusCode::INTERNAL_SERVER_ERROR, None), - timer, - Some((rt.name.clone(), rt.version.clone())), - ) - } - Some(Ok(EventResponseChannel::Http(rx))) => { - let rt_name = rt.name.clone(); - let rt_version = rt.version.clone(); - wrap_future( - rx.and_then(move |res: JsHttpResponse| { - let (mut parts, mut body) = Response::::default().into_parts(); - parts.headers = res.headers; - parts.status = res.status; - - if let Some(js_body) = res.body { - body = match js_body { - JsBody::Stream(s) => Body::wrap_stream( - s.map_err(|_| { - io::Error::new(io::ErrorKind::Interrupted, "interrupted stream") - }) - .inspect(move |v| { - DATA_OUT_TOTAL - .with_label_values(&[ - rt_name.as_str(), - rt_version.as_str(), - "http_response", - ]) - .inc_by(v.len() as i64); - }), - ), - JsBody::BytesStream(s) => Body::wrap_stream( - s.map_err(|_| { - io::Error::new(io::ErrorKind::Interrupted, "interrupted stream") - }) - .map(|bm| bm.freeze()) - .inspect(move |bytes| { - DATA_OUT_TOTAL - .with_label_values(&[ - rt_name.as_str(), - rt_version.as_str(), - "http_response", - ]) - .inc_by(bytes.len() as i64); - }), - ), - JsBody::Static(b) => { - DATA_OUT_TOTAL - .with_label_values(&[ - rt_name.as_str(), - rt_version.as_str(), - "http_response", - ]) - .inc_by(b.len() as i64); - Body::from(b) - } - _ => unimplemented!(), - }; - } - - Ok(set_request_id( - set_server_header(Response::from_parts(parts, body)), - req_id, - )) - }), - timer, - Some((rt.name.clone(), rt.version.clone())), + simple_response(StatusCode::INTERNAL_SERVER_ERROR, None), + request_info, + logger, + Some((rt_lock.name.clone(), rt_version.clone())), ) } + Some(Ok(EventResponseChannel::Http(rx))) => wrap_future( + rx.and_then(move |res: JsHttpResponse| { + let (mut parts, mut body) = Response::::default().into_parts(); + parts.headers = res.headers; + parts.status = res.status; + + if let Some(js_body) = res.body { + body = match js_body { + JsBody::Stream(s) => Body::wrap_stream( + s.map_err(|_| { + io::Error::new(io::ErrorKind::Interrupted, "interrupted stream") + }) + .inspect(move |v| { + outbound_data.inc_by(v.len() as i64); + }), + ), + JsBody::Static(b) => { + outbound_data.inc_by(b.len() as i64); + Body::from(b) + } + _ => unimplemented!(), + }; + } + + Ok(Response::from_parts(parts, body)) + }), + request_info, + logger, + Some((rt_name.clone(), rt_version.clone())), + ), _ => unimplemented!(), } } fn future_response( res: Response, - timer: time::Instant, + req: RequestInfo, + logger: slog::Logger, namever: Option<(String, String)>, ) -> BoxedResponseFuture { - wrap_future(future::ok(res), timer, namever) + wrap_future(future::ok(res), req, logger, namever) } -fn simple_response(req_id: String, status: StatusCode, body: Option) -> Response { - set_request_id( - set_server_header( - Response::builder() - .status(status) - .body(body.unwrap_or(Body::empty())) - .unwrap(), - ), - req_id, - ) +fn simple_response(status: StatusCode, body: Option<&str>) -> Response { + Response::builder() + .status(status) + .body(body.map_or_else(|| Body::empty(), |b| Body::from(b.to_owned()))) + .unwrap() } fn set_server_header(mut res: Response) -> Response { @@ -253,22 +252,47 @@ fn set_request_id(mut res: Response, req_id: String) -> Response { fn wrap_future( fut: F, - timer: time::Instant, + req: RequestInfo, + logger: slog::Logger, namever: Option<(String, String)>, ) -> BoxedResponseFuture where F: Future, Error = futures::Canceled> + Send + 'static, { Box::new(fut.and_then(move |res| { - let (name, ver) = namever.unwrap_or((String::new(), String::new())); + let (name, ver) = namever.unwrap_or_else(|| (String::new(), String::new())); let status = res.status(); let status_str = status.as_str(); + let elapsed = req.timer.elapsed(); + + let res = set_server_header(set_request_id(res, req.request_id)); + HTTP_RESPONSE_TIME_HISTOGRAM .with_label_values(&[name.as_str(), ver.as_str(), status_str]) - .observe(timer.elapsed().as_fractional_secs()); + .observe(elapsed.as_fractional_secs()); HTTP_RESPONSE_COUNTER .with_label_values(&[name.as_str(), ver.as_str(), status_str]) .inc(); + + slog_debug!( + logger, + "end request {http_response} {request_time_ms}", + http_response = res.status().as_u16(), + request_time_ms = elapsed.as_fractional_secs() * 1000.0 + ); + + // TODO(md): send common log format message to the app logger once debugging is done + // commong log format + slog_info!( + logger, + "{client_ip} {http_method} {request_uri} {http_response} {request_time_ms}ms", + client_ip = req.remote_addr.to_string(), + http_method = req.method.to_owned(), + request_uri = req.url.to_owned(), + http_response = res.status().as_u16(), + request_time_ms = elapsed.as_fractional_secs() * 1000.0 + ); + Ok(res) })) } diff --git a/src/js.rs b/src/js.rs new file mode 100644 index 0000000..8488503 --- /dev/null +++ b/src/js.rs @@ -0,0 +1,79 @@ +use crate::errors::FlyError; +use futures::{sync::mpsc, Stream}; +use hyper::HeaderMap; +use hyper::StatusCode; +use std::net::SocketAddr; +use trust_dns as dns; + +pub enum JsBody { + BoxedStream(Box, Error = FlyError> + Send>), + Stream(mpsc::UnboundedReceiver>), + Static(Vec), +} + +pub struct JsHttpResponse { + pub headers: HeaderMap, + pub status: StatusCode, + pub body: Option, +} + +pub struct JsHttpRequest { + pub id: u32, + pub method: http::Method, + pub remote_addr: SocketAddr, + pub url: String, + pub headers: HeaderMap, + pub body: Option, +} + +pub enum JsEvent { + Fetch(JsHttpRequest), + Resolv(JsDnsRequest), + Serve(JsServiceRequest), +} + +#[derive(Debug)] +pub struct JsDnsResponse { + pub op_code: dns::op::OpCode, + pub message_type: dns::op::MessageType, + pub response_code: dns::op::ResponseCode, + pub answers: Vec, + pub queries: Vec, + pub authoritative: bool, + pub truncated: bool, +} + +#[derive(Debug)] +pub struct JsDnsRequest { + pub id: u32, + pub message_type: dns::op::MessageType, + pub queries: Vec, +} + +#[derive(Debug)] +pub struct JsDnsRecord { + pub name: dns::rr::Name, + pub rdata: dns::rr::RData, + pub dns_class: dns::rr::DNSClass, + pub ttl: u32, +} + +#[derive(Debug)] +pub struct JsDnsQuery { + pub name: dns::rr::Name, + pub rr_type: dns::rr::RecordType, + pub dns_class: dns::rr::DNSClass, +} + +#[derive(Debug)] +pub struct JsServiceRequest { + pub id: u32, + pub sender: String, + pub data: String, +} + +#[derive(Debug)] +pub struct JsServiceResponse { + pub success: bool, + pub data: Option, +} diff --git a/src/lib.rs b/src/lib.rs index c886f99..497c332 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,45 +20,55 @@ use std::os::raw::c_uint; #[no_mangle] pub unsafe extern "C" fn c_get_next_stream_id() -> c_uint { - get_next_stream_id() + get_next_stream_id() } pub fn get_next_stream_id() -> u32 { - NEXT_EVENT_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as u32 + NEXT_EVENT_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as u32 } +pub static BUILD_VERSION: &str = env!("BUILD_VERSION"); + +pub mod js; +pub mod v8env; pub mod errors; pub mod msg; pub mod ops; pub mod runtime; - +pub mod runtime_permissions; pub mod utils; +pub mod acme_store; pub mod cache_store; pub mod cache_store_notifier; pub mod data_store; pub mod fs_store; -pub mod acme_store; pub mod settings; -pub mod runtime_selector; -pub use crate::runtime_selector::{RuntimeSelector, SelectorError}; +pub mod runtime_manager; +pub use crate::runtime_manager::{RuntimeManager, RuntimeManagerError}; pub mod dns_server; -pub mod fixed_runtime_selector; +pub mod standard_runtime_manager; pub mod http_server; pub mod metrics; -mod compiler; +pub mod module_resolver; +pub use crate::module_resolver::{JsonSecretsResolver, LocalDiskModuleResolver, ModuleResolver}; + +pub mod msg_handler; + mod disk_fs; mod postgres_data; +mod redis_acme; mod redis_cache; mod redis_cache_notifier; mod redis_fs; -mod redis_acme; mod sqlite_cache; mod sqlite_data; mod redis_pool; + +pub mod logging; diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 0000000..f87d033 --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,133 @@ +use slog::{Drain, Level, Logger}; +use std::env; +use std::panic::{RefUnwindSafe, UnwindSafe}; + +pub fn build_logger + Send + 'static>( + drain: D, +) -> Logger { + slog::Logger::root(slog_async::Async::default(drain.fuse()).fuse(), slog::o!()) +} + +pub fn build_routing_logger< + D1: slog::Drain + Send + 'static, + D2: slog::Drain + Send + 'static, +>( + runtime_drain: D1, + app_drain: D2, +) -> Logger { + slog::Logger::root( + slog_async::Async::default( + SwitchDrain { + runtime_drain, + app_drain, + } + .fuse(), + ) + .fuse(), + slog::o!(), + ) +} + +pub fn log_level_from_env(name: &str, default: Level) -> Level { + match env::var(name).unwrap_or_default().to_uppercase().as_str() { + "TRACE" => Level::Trace, + "DEBUG" => Level::Debug, + "INFO" => Level::Info, + "WARN" | "WARNING" => Level::Warning, + "ERROR" => Level::Error, + _ => default, + } +} + +pub struct SwitchDrain { + runtime_drain: D1, + app_drain: D2, +} + +impl UnwindSafe for SwitchDrain {} +impl RefUnwindSafe for SwitchDrain {} + +impl<'a, D1: slog::Drain, D2: slog::Drain> slog::Drain for SwitchDrain { + type Err = slog::Never; + type Ok = (); + + fn log( + &self, + record: &slog::Record, + values: &slog::OwnedKVList, + ) -> Result { + if record.tag() == "app" { + self.app_drain.log(record, values).ok(); + } else { + self.runtime_drain.log(record, values).ok(); + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use slog::slog_info; + use tempfile; + + #[test] + fn test_separate_drains() { + let runtime_buf = tempfile::NamedTempFile::new().unwrap(); + let app_buf = tempfile::NamedTempFile::new().unwrap(); + + { + let logger = build_routing_logger( + slog_json::Json::default(runtime_buf.reopen().unwrap()).fuse(), + slog_json::Json::default(app_buf.reopen().unwrap()).fuse(), + ); + + slog_info!(logger, #"runtime", "runtime-message"); + slog_info!(logger, #"app", "app-message"); + } + + let runtime_output = std::fs::read_to_string(runtime_buf.path()).unwrap(); + let app_output = std::fs::read_to_string(app_buf.path()).unwrap(); + + assert!( + runtime_output.contains("runtime-message"), + "runtime message not written to runtime drain!" + ); + assert!( + !runtime_output.contains("app-message"), + "app message written to runtime drain!" + ); + + assert!( + app_output.contains("app-message"), + "app message not written to app drain!" + ); + assert!( + !app_output.contains("runtime-message"), + "runtime message written to app drain!" + ); + } + + #[test] + fn test_single_drain() { + let buf = tempfile::NamedTempFile::new().unwrap(); + + { + let logger = build_logger(slog_json::Json::default(buf.reopen().unwrap()).fuse()); + + slog_info!(logger, #"runtime", "runtime-message"); + slog_info!(logger, #"app", "app-message"); + } + + let output = std::fs::read_to_string(buf.path()).unwrap(); + assert!( + output.contains("runtime-message"), + "runtime message not written to drain!" + ); + assert!( + output.contains("app-message"), + "runtime message not written to drain!" + ); + } +} diff --git a/src/module_resolver.rs b/src/module_resolver.rs new file mode 100644 index 0000000..8ba8e56 --- /dev/null +++ b/src/module_resolver.rs @@ -0,0 +1,404 @@ +use crate::errors::*; + +use std::path::PathBuf; + +use std::marker::Send; + +use std::clone::Clone; + +use std::collections::HashMap; + +use serde_json; + +#[derive(Clone, Debug)] +pub struct RefererInfo { + pub origin_url: String, + pub is_wasm: Option, + pub source_code: Option, + pub indentifier_hash: Option, +} + +#[derive(Clone, Debug)] +pub struct LoadedSourceCode { + pub is_wasm: bool, + pub source_map: Option, + pub source: String, +} + +#[derive(Clone, Debug)] +pub struct LoadedModule { + pub loaded_source: LoadedSourceCode, + pub origin_url: String, +} + +pub struct ModuleSourceData { + pub origin_url: String, + pub source_loader: Box, +} + +/** + * Similar function to what is known as a "loader" in the javascript packaging world + */ +pub trait SourceLoader: Send { + fn load_source(&self) -> FlyResult; +} + +/** + * Resolves a module specifier and returns a "strategy" for loading the module to ES6 or WASM code. + */ +pub trait ModuleResolver: Send + Sync { + fn resolve_module( + &self, + module_specifier: &str, + referer_info: Option, + ) -> FlyResult; + fn get_protocol(&self) -> String; +} + +/** + * This trait is a used as the "front door" of the dynamic module resolution system. + */ +pub trait ModuleResolverManager: Send + Sync { + fn resolve_module( + &self, + specifier: String, + referer_info: Option, + ) -> FlyResult; +} + +/** + * Parse url or join it to the working url if it's relative. working_url_str << MUST BE AN ABSOLUTE PATH. + */ +fn parse_url(url_str: &str, working_url_str: &str) -> Result { + debug!("parse_url {} from {}", &url_str, &working_url_str); + // TODO: Add some additional logic to this thing to account for file paths without the "file://" protocol denotation. + let mut url_parsed = match url::Url::parse(url_str) { + Ok(v) => v, + Err(e) => { + if e == url::ParseError::RelativeUrlWithoutBase { + // If the url is relative join it to the working path. + trace!("Url relative: {}", url_str); + let working_url_parsed = url::Url::parse(working_url_str)?; + let final_url = working_url_parsed.join(url_str)?; + final_url + } else { + return Err(e); + } + } + }; + + // The default scheme/protocol should be "file://" + if url_parsed.scheme() == "" { + // ignore result since "file" scheme won't error + let _ = url_parsed.set_scheme("file"); + } + + return Ok(url_parsed); +} + +pub struct LocalDiskRawLoader { + pub source_file_path: PathBuf, + pub source_map_path: Option, +} + +impl LocalDiskRawLoader { + pub fn new(source_file_path: PathBuf, source_map_path: Option) -> Self { + Self { + source_file_path, + source_map_path, + } + } +} + +impl SourceLoader for LocalDiskRawLoader { + fn load_source(&self) -> FlyResult { + // Try to load file from path for this loader and return if successful + let source = std::fs::read_to_string(&self.source_file_path.to_str().unwrap().to_string())?; + let source_map = match &self.source_map_path { + Some(v) => match std::fs::read_to_string(&v.to_str().unwrap().to_string()) { + Ok(v) => Some(v), + Err(_err) => None, + }, + None => None, + }; + Ok(LoadedSourceCode { + is_wasm: false, + source_map, + source, + }) + } +} + +pub struct LocalDiskModuleResolver { + pub default_working_url: String, +} + +impl LocalDiskModuleResolver { + pub fn new(default_working_url: Option) -> Self { + let default_working_url = match default_working_url { + None => url::Url::from_directory_path( + std::env::current_dir().expect("invalid current directory"), + ) + .unwrap() + .as_str() + .to_string(), + Some(default_working_url) => default_working_url, + }; + Self { + default_working_url, + } + } +} + +impl ModuleResolver for LocalDiskModuleResolver { + fn resolve_module( + &self, + module_specifier: &str, + referer_info: Option, + ) -> FlyResult { + let referer_origin_url = match referer_info { + Some(v) => v.origin_url, + None => self.default_working_url.clone(), + }; + trace!( + "resolve_module {} from {}", + module_specifier, + referer_origin_url + ); + + let module_specifier_url = parse_url(module_specifier, referer_origin_url.as_str())?; + + let mut module_file_path = module_specifier_url.to_file_path()?; + + if module_file_path.is_file() { + return Ok(ModuleSourceData { + origin_url: url::Url::from_file_path(module_file_path.clone()) + .unwrap() + .as_str() + .to_string(), + source_loader: Box::new(LocalDiskRawLoader::new(module_file_path, None)), + }); + } + let did_set = module_file_path.set_extension("ts"); + trace!("trying module {} ({})", module_file_path.display(), did_set); + if module_file_path.is_file() { + return Ok(ModuleSourceData { + origin_url: url::Url::from_file_path(module_file_path.clone()) + .unwrap() + .as_str() + .to_string(), + source_loader: Box::new(LocalDiskRawLoader::new(module_file_path, None)), + }); + } + let did_set = module_file_path.set_extension("js"); + trace!("trying module {} ({})", module_file_path.display(), did_set); + if module_file_path.is_file() { + return Ok(ModuleSourceData { + origin_url: url::Url::from_file_path(module_file_path.clone()) + .unwrap() + .as_str() + .to_string(), + source_loader: Box::new(LocalDiskRawLoader::new(module_file_path, None)), + }); + } + // TODO: Add code here for json files and other media types. + error!("NOPE"); + + Err(FlyError::from(format!( + "Could not resolve {} from {} ", + module_specifier, referer_origin_url + ))) + } + fn get_protocol(&self) -> String { + return "file".to_string(); + } +} + +pub struct FunctionModuleResolver { + resolve_fn: Box) -> FlyResult + Send + Sync>, +} + +impl FunctionModuleResolver { + pub fn new( + resolve_fn: Box) -> FlyResult + Send + Sync>, + ) -> Self { + Self { resolve_fn } + } +} + +impl ModuleResolver for FunctionModuleResolver { + fn resolve_module( + &self, + module_specifier: &str, + referer_info: Option, + ) -> FlyResult { + let referer_origin_url = match referer_info.clone() { + Some(v) => v.origin_url, + None => "".to_string(), + }; + trace!( + "resolve_module {} from {}", + module_specifier, + referer_origin_url + ); + (self.resolve_fn)(module_specifier, referer_info) + } + fn get_protocol(&self) -> String { + return "function".to_string(); + } +} + +pub struct JsonSecretsLoader { + pub json_value: serde_json::Value, +} + +impl JsonSecretsLoader { + pub fn new(json_value: &serde_json::Value) -> Self { + Self { + json_value: (*json_value).clone(), + } + } +} + +impl SourceLoader for JsonSecretsLoader { + fn load_source(&self) -> FlyResult { + let source_code = format!( + "export default JSON.parse(`{}`);", + self.json_value.to_string().replace("`", "") + ); + + trace!("Loaded json secrets {}", source_code); + + return Ok(LoadedSourceCode { + is_wasm: false, + source_map: None, + source: source_code, + }); + } +} + +pub struct JsonSecretsResolver { + json_value: serde_json::Value, +} + +impl JsonSecretsResolver { + pub fn new(json_value: serde_json::Value) -> Self { + Self { json_value } + } +} + +impl ModuleResolver for JsonSecretsResolver { + fn resolve_module( + &self, + module_specifier: &str, + referer_info: Option, + ) -> FlyResult { + let referer_origin_url = match referer_info { + Some(v) => v.origin_url, + None => "secrets:///".to_string(), + }; + let module_specifier_url = parse_url(module_specifier, referer_origin_url.as_str())?; + // TODO: add some origin checks for referer. + let mut value = self.json_value.clone(); + let path_segs = module_specifier_url.path_segments().unwrap(); + for path_seg in path_segs { + if value[path_seg] != serde_json::Value::Null { + value = value[path_seg].clone(); + } else { + return Err(FlyError::from(format!( + "Could not resolve {} from {} ", + module_specifier_url, referer_origin_url + ))); + } + } + return Ok(ModuleSourceData { + origin_url: format!("{}{}", module_specifier.to_string(), ".js"), + source_loader: Box::new(JsonSecretsLoader::new(&value)), + }); + } + fn get_protocol(&self) -> String { + return "secrets".to_string(); + } +} + +pub struct StandardModuleResolverManager { + protocol_resolver_map: HashMap>>, + default_working_url: String, +} + +impl StandardModuleResolverManager { + pub fn new(resolvers: Vec>, default_working_url: Option) -> Self { + // Create protocol to resolver map and map out resolvers. + let mut protocol_resolver_map: HashMap>> = HashMap::new(); + for resolver in resolvers { + match protocol_resolver_map.get_mut(&resolver.get_protocol()) { + Some(v) => v.push(resolver), + None => { + protocol_resolver_map.insert(resolver.get_protocol(), vec![resolver]); + } + } + } + let default_working_url = match default_working_url { + None => url::Url::from_directory_path( + std::env::current_dir().expect("invalid current directory"), + ) + .unwrap() + .as_str() + .to_string(), + Some(default_working_url) => default_working_url, + }; + Self { + protocol_resolver_map, + default_working_url, + } + } +} + +impl ModuleResolverManager for StandardModuleResolverManager { + fn resolve_module( + &self, + specifier: String, + referer_info: Option, + ) -> FlyResult { + let referer_origin_url = match referer_info.clone() { + Some(v) => v.origin_url, + None => self.default_working_url.clone(), + }; + // Parse the specifier with the referer origin_url as the working path/url. + info!("resolve_module {} from {}", &specifier, &referer_origin_url); + + let specifier_url = parse_url(specifier.as_str(), referer_origin_url.as_str())?; + + // Try to get a vector of the resolvers for the protocol we are tring to resolve. + let resolvers = match self.protocol_resolver_map.get(specifier_url.scheme()) { + Some(v) => v, + None => { + return Err(FlyError::from(format!( + "Could not resolve {} from {}: no resolvers for protocol {} setup.", + specifier, + &referer_origin_url, + specifier_url.scheme() + ))); + } + }; + + for resolver in resolvers { + let resolver_result = resolver.resolve_module(specifier.as_str(), referer_info.clone()); + if let Err(e) = resolver_result { + info!("Resolver failed trying the next one: {}", e); + } else { + let module_loader = resolver_result.unwrap(); + let loaded_source = module_loader.source_loader.load_source()?; + return Ok(LoadedModule { + loaded_source, + origin_url: module_loader.origin_url, + }); + } + } + + Err(FlyError::from(format!( + "Could not resolve {} from {}: exausted all resolvers.", + specifier, referer_origin_url + ))) + } +} diff --git a/src/msg_generated.rs b/src/msg_generated.rs index 784b8d3..37ef37e 100644 --- a/src/msg_generated.rs +++ b/src/msg_generated.rs @@ -505,12 +505,13 @@ pub struct DnsRecordDataUnionTableOffset {} #[repr(i8)] #[derive(Clone, Copy, PartialEq, Debug)] pub enum ImageTransformType { - ImageWebPEncode = 0, + WebPEncode = 0, + Resize = 1, } const ENUM_MIN_IMAGE_TRANSFORM_TYPE: i8 = 0; -const ENUM_MAX_IMAGE_TRANSFORM_TYPE: i8 = 0; +const ENUM_MAX_IMAGE_TRANSFORM_TYPE: i8 = 1; impl<'a> flatbuffers::Follow<'a> for ImageTransformType { type Inner = Self; @@ -544,13 +545,15 @@ impl flatbuffers::Push for ImageTransformType { } #[allow(non_camel_case_types)] -const ENUM_VALUES_IMAGE_TRANSFORM_TYPE:[ImageTransformType; 1] = [ - ImageTransformType::ImageWebPEncode +const ENUM_VALUES_IMAGE_TRANSFORM_TYPE:[ImageTransformType; 2] = [ + ImageTransformType::WebPEncode, + ImageTransformType::Resize ]; #[allow(non_camel_case_types)] -const ENUM_NAMES_IMAGE_TRANSFORM_TYPE:[&'static str; 1] = [ - "ImageWebPEncode" +const ENUM_NAMES_IMAGE_TRANSFORM_TYPE:[&'static str; 2] = [ + "WebPEncode", + "Resize" ]; pub fn enum_name_image_transform_type(e: ImageTransformType) -> &'static str { @@ -558,17 +561,87 @@ pub fn enum_name_image_transform_type(e: ImageTransformType) -> &'static str { ENUM_NAMES_IMAGE_TRANSFORM_TYPE[index] } +#[allow(non_camel_case_types)] +#[repr(i8)] +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum ImageSamplingFilter { + Nearest = 0, + Triangle = 1, + CatmullRom = 2, + Gaussian = 3, + Lanczos3 = 4, + +} + +const ENUM_MIN_IMAGE_SAMPLING_FILTER: i8 = 0; +const ENUM_MAX_IMAGE_SAMPLING_FILTER: i8 = 4; + +impl<'a> flatbuffers::Follow<'a> for ImageSamplingFilter { + type Inner = Self; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + flatbuffers::read_scalar_at::(buf, loc) + } +} + +impl flatbuffers::EndianScalar for ImageSamplingFilter { + #[inline] + fn to_little_endian(self) -> Self { + let n = i8::to_le(self as i8); + let p = &n as *const i8 as *const ImageSamplingFilter; + unsafe { *p } + } + #[inline] + fn from_little_endian(self) -> Self { + let n = i8::from_le(self as i8); + let p = &n as *const i8 as *const ImageSamplingFilter; + unsafe { *p } + } +} + +impl flatbuffers::Push for ImageSamplingFilter { + type Output = ImageSamplingFilter; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::(dst, *self); + } +} + +#[allow(non_camel_case_types)] +const ENUM_VALUES_IMAGE_SAMPLING_FILTER:[ImageSamplingFilter; 5] = [ + ImageSamplingFilter::Nearest, + ImageSamplingFilter::Triangle, + ImageSamplingFilter::CatmullRom, + ImageSamplingFilter::Gaussian, + ImageSamplingFilter::Lanczos3 +]; + +#[allow(non_camel_case_types)] +const ENUM_NAMES_IMAGE_SAMPLING_FILTER:[&'static str; 5] = [ + "Nearest", + "Triangle", + "CatmullRom", + "Gaussian", + "Lanczos3" +]; + +pub fn enum_name_image_sampling_filter(e: ImageSamplingFilter) -> &'static str { + let index: usize = e as usize; + ENUM_NAMES_IMAGE_SAMPLING_FILTER[index] +} + #[allow(non_camel_case_types)] #[repr(u8)] #[derive(Clone, Copy, PartialEq, Debug)] pub enum ImageTransformOptions { NONE = 0, ImageWebPEncode = 1, + ImageResize = 2, } const ENUM_MIN_IMAGE_TRANSFORM_OPTIONS: u8 = 0; -const ENUM_MAX_IMAGE_TRANSFORM_OPTIONS: u8 = 1; +const ENUM_MAX_IMAGE_TRANSFORM_OPTIONS: u8 = 2; impl<'a> flatbuffers::Follow<'a> for ImageTransformOptions { type Inner = Self; @@ -602,15 +675,17 @@ impl flatbuffers::Push for ImageTransformOptions { } #[allow(non_camel_case_types)] -const ENUM_VALUES_IMAGE_TRANSFORM_OPTIONS:[ImageTransformOptions; 2] = [ +const ENUM_VALUES_IMAGE_TRANSFORM_OPTIONS:[ImageTransformOptions; 3] = [ ImageTransformOptions::NONE, - ImageTransformOptions::ImageWebPEncode + ImageTransformOptions::ImageWebPEncode, + ImageTransformOptions::ImageResize ]; #[allow(non_camel_case_types)] -const ENUM_NAMES_IMAGE_TRANSFORM_OPTIONS:[&'static str; 2] = [ +const ENUM_NAMES_IMAGE_TRANSFORM_OPTIONS:[&'static str; 3] = [ "NONE", - "ImageWebPEncode" + "ImageWebPEncode", + "ImageResize" ]; pub fn enum_name_image_transform_options(e: ImageTransformOptions) -> &'static str { @@ -653,22 +728,28 @@ pub enum Any { DataGet = 27, DataGetReady = 28, DataDel = 29, - DataDropCollection = 30, - DnsQuery = 31, - DnsRequest = 32, - DnsResponse = 33, - AddEventListener = 34, - LoadModule = 35, - LoadModuleResp = 36, - ImageApplyTransforms = 37, - ImageReady = 38, - AcmeGetChallenge = 39, - AcmeGetChallengeReady = 40, + DataIncr = 30, + DataDropCollection = 31, + DnsQuery = 32, + DnsRequest = 33, + DnsResponse = 34, + AddEventListener = 35, + LoadModule = 36, + LoadModuleResp = 37, + ImageApplyTransforms = 38, + ImageReady = 39, + AcmeGetChallenge = 40, + AcmeGetChallengeReady = 41, + ServiceRequest = 42, + ServiceResponse = 43, + RequestServiceRequest = 44, + RequestServiceResponse = 45, + OsExit = 46, } const ENUM_MIN_ANY: u8 = 0; -const ENUM_MAX_ANY: u8 = 40; +const ENUM_MAX_ANY: u8 = 46; impl<'a> flatbuffers::Follow<'a> for Any { type Inner = Self; @@ -702,7 +783,7 @@ impl flatbuffers::Push for Any { } #[allow(non_camel_case_types)] -const ENUM_VALUES_ANY:[Any; 41] = [ +const ENUM_VALUES_ANY:[Any; 47] = [ Any::NONE, Any::TimerStart, Any::TimerReady, @@ -733,6 +814,7 @@ const ENUM_VALUES_ANY:[Any; 41] = [ Any::DataGet, Any::DataGetReady, Any::DataDel, + Any::DataIncr, Any::DataDropCollection, Any::DnsQuery, Any::DnsRequest, @@ -743,11 +825,16 @@ const ENUM_VALUES_ANY:[Any; 41] = [ Any::ImageApplyTransforms, Any::ImageReady, Any::AcmeGetChallenge, - Any::AcmeGetChallengeReady + Any::AcmeGetChallengeReady, + Any::ServiceRequest, + Any::ServiceResponse, + Any::RequestServiceRequest, + Any::RequestServiceResponse, + Any::OsExit ]; #[allow(non_camel_case_types)] -const ENUM_NAMES_ANY:[&'static str; 41] = [ +const ENUM_NAMES_ANY:[&'static str; 47] = [ "NONE", "TimerStart", "TimerReady", @@ -778,6 +865,7 @@ const ENUM_NAMES_ANY:[&'static str; 41] = [ "DataGet", "DataGetReady", "DataDel", + "DataIncr", "DataDropCollection", "DnsQuery", "DnsRequest", @@ -788,7 +876,12 @@ const ENUM_NAMES_ANY:[&'static str; 41] = [ "ImageApplyTransforms", "ImageReady", "AcmeGetChallenge", - "AcmeGetChallengeReady" + "AcmeGetChallengeReady", + "ServiceRequest", + "ServiceResponse", + "RequestServiceRequest", + "RequestServiceResponse", + "OsExit" ]; pub fn enum_name_any(e: Any) -> &'static str { @@ -1043,11 +1136,12 @@ pub fn enum_name_http_method(e: HttpMethod) -> &'static str { pub enum EventType { Fetch = 0, Resolv = 1, + Serve = 2, } const ENUM_MIN_EVENT_TYPE: i8 = 0; -const ENUM_MAX_EVENT_TYPE: i8 = 1; +const ENUM_MAX_EVENT_TYPE: i8 = 2; impl<'a> flatbuffers::Follow<'a> for EventType { type Inner = Self; @@ -1081,15 +1175,17 @@ impl flatbuffers::Push for EventType { } #[allow(non_camel_case_types)] -const ENUM_VALUES_EVENT_TYPE:[EventType; 2] = [ +const ENUM_VALUES_EVENT_TYPE:[EventType; 3] = [ EventType::Fetch, - EventType::Resolv + EventType::Resolv, + EventType::Serve ]; #[allow(non_camel_case_types)] -const ENUM_NAMES_EVENT_TYPE:[&'static str; 2] = [ +const ENUM_NAMES_EVENT_TYPE:[&'static str; 3] = [ "Fetch", - "Resolv" + "Resolv", + "Serve" ]; pub fn enum_name_event_type(e: EventType) -> &'static str { @@ -3595,15 +3691,15 @@ impl<'a: 'b, 'b> CachePurgeTagBuilder<'a, 'b> { } } -pub enum ImageWebPEncodeOffset {} +pub enum DataPutOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct ImageWebPEncode<'a> { +pub struct DataPut<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for ImageWebPEncode<'a> { - type Inner = ImageWebPEncode<'a>; +impl<'a> flatbuffers::Follow<'a> for DataPut<'a> { + type Inner = DataPut<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -3612,110 +3708,98 @@ impl<'a> flatbuffers::Follow<'a> for ImageWebPEncode<'a> { } } -impl<'a> ImageWebPEncode<'a> { +impl<'a> DataPut<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - ImageWebPEncode { + DataPut { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args ImageWebPEncodeArgs) -> flatbuffers::WIPOffset> { - let mut builder = ImageWebPEncodeBuilder::new(_fbb); - builder.add_alpha_quality(args.alpha_quality); - builder.add_quality(args.quality); - builder.add_near_lossless(args.near_lossless); - builder.add_lossless(args.lossless); + args: &'args DataPutArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = DataPutBuilder::new(_fbb); + if let Some(x) = args.json { builder.add_json(x); } + if let Some(x) = args.key { builder.add_key(x); } + if let Some(x) = args.collection { builder.add_collection(x); } builder.finish() } - pub const VT_QUALITY: flatbuffers::VOffsetT = 4; - pub const VT_ALPHA_QUALITY: flatbuffers::VOffsetT = 6; - pub const VT_LOSSLESS: flatbuffers::VOffsetT = 8; - pub const VT_NEAR_LOSSLESS: flatbuffers::VOffsetT = 10; + pub const VT_COLLECTION: flatbuffers::VOffsetT = 4; + pub const VT_KEY: flatbuffers::VOffsetT = 6; + pub const VT_JSON: flatbuffers::VOffsetT = 8; #[inline] - pub fn quality(&self) -> f32 { - self._tab.get::(ImageWebPEncode::VT_QUALITY, Some(0.0)).unwrap() - } - #[inline] - pub fn alpha_quality(&self) -> f32 { - self._tab.get::(ImageWebPEncode::VT_ALPHA_QUALITY, Some(0.0)).unwrap() + pub fn collection(&self) -> Option<&'a str> { + self._tab.get::>(DataPut::VT_COLLECTION, None) } #[inline] - pub fn lossless(&self) -> bool { - self._tab.get::(ImageWebPEncode::VT_LOSSLESS, Some(false)).unwrap() + pub fn key(&self) -> Option<&'a str> { + self._tab.get::>(DataPut::VT_KEY, None) } #[inline] - pub fn near_lossless(&self) -> bool { - self._tab.get::(ImageWebPEncode::VT_NEAR_LOSSLESS, Some(false)).unwrap() + pub fn json(&self) -> Option<&'a str> { + self._tab.get::>(DataPut::VT_JSON, None) } } -pub struct ImageWebPEncodeArgs { - pub quality: f32, - pub alpha_quality: f32, - pub lossless: bool, - pub near_lossless: bool, +pub struct DataPutArgs<'a> { + pub collection: Option>, + pub key: Option>, + pub json: Option>, } -impl<'a> Default for ImageWebPEncodeArgs { +impl<'a> Default for DataPutArgs<'a> { #[inline] fn default() -> Self { - ImageWebPEncodeArgs { - quality: 0.0, - alpha_quality: 0.0, - lossless: false, - near_lossless: false, + DataPutArgs { + collection: None, + key: None, + json: None, } } } -pub struct ImageWebPEncodeBuilder<'a: 'b, 'b> { +pub struct DataPutBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> ImageWebPEncodeBuilder<'a, 'b> { - #[inline] - pub fn add_quality(&mut self, quality: f32) { - self.fbb_.push_slot::(ImageWebPEncode::VT_QUALITY, quality, 0.0); - } +impl<'a: 'b, 'b> DataPutBuilder<'a, 'b> { #[inline] - pub fn add_alpha_quality(&mut self, alpha_quality: f32) { - self.fbb_.push_slot::(ImageWebPEncode::VT_ALPHA_QUALITY, alpha_quality, 0.0); + pub fn add_collection(&mut self, collection: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataPut::VT_COLLECTION, collection); } #[inline] - pub fn add_lossless(&mut self, lossless: bool) { - self.fbb_.push_slot::(ImageWebPEncode::VT_LOSSLESS, lossless, false); + pub fn add_key(&mut self, key: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataPut::VT_KEY, key); } #[inline] - pub fn add_near_lossless(&mut self, near_lossless: bool) { - self.fbb_.push_slot::(ImageWebPEncode::VT_NEAR_LOSSLESS, near_lossless, false); + pub fn add_json(&mut self, json: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataPut::VT_JSON, json); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ImageWebPEncodeBuilder<'a, 'b> { + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataPutBuilder<'a, 'b> { let start = _fbb.start_table(); - ImageWebPEncodeBuilder { + DataPutBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } } -pub enum ImageTransformOffset {} +pub enum DataGetOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct ImageTransform<'a> { +pub struct DataGet<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for ImageTransform<'a> { - type Inner = ImageTransform<'a>; +impl<'a> flatbuffers::Follow<'a> for DataGet<'a> { + type Inner = DataGet<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -3724,108 +3808,86 @@ impl<'a> flatbuffers::Follow<'a> for ImageTransform<'a> { } } -impl<'a> ImageTransform<'a> { +impl<'a> DataGet<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - ImageTransform { + DataGet { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args ImageTransformArgs) -> flatbuffers::WIPOffset> { - let mut builder = ImageTransformBuilder::new(_fbb); - if let Some(x) = args.options { builder.add_options(x); } - builder.add_options_type(args.options_type); - builder.add_transform(args.transform); + args: &'args DataGetArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = DataGetBuilder::new(_fbb); + if let Some(x) = args.key { builder.add_key(x); } + if let Some(x) = args.collection { builder.add_collection(x); } builder.finish() } - pub const VT_TRANSFORM: flatbuffers::VOffsetT = 4; - pub const VT_OPTIONS_TYPE: flatbuffers::VOffsetT = 6; - pub const VT_OPTIONS: flatbuffers::VOffsetT = 8; + pub const VT_COLLECTION: flatbuffers::VOffsetT = 4; + pub const VT_KEY: flatbuffers::VOffsetT = 6; #[inline] - pub fn transform(&self) -> ImageTransformType { - self._tab.get::(ImageTransform::VT_TRANSFORM, Some(ImageTransformType::ImageWebPEncode)).unwrap() - } - #[inline] - pub fn options_type(&self) -> ImageTransformOptions { - self._tab.get::(ImageTransform::VT_OPTIONS_TYPE, Some(ImageTransformOptions::NONE)).unwrap() - } - #[inline] - pub fn options(&self) -> Option> { - self._tab.get::>>(ImageTransform::VT_OPTIONS, None) + pub fn collection(&self) -> Option<&'a str> { + self._tab.get::>(DataGet::VT_COLLECTION, None) } #[inline] - #[allow(non_snake_case)] - pub fn options_as_image_web_pencode(&'a self) -> Option { - if self.options_type() == ImageTransformOptions::ImageWebPEncode { - self.options().map(|u| ImageWebPEncode::init_from_table(u)) - } else { - None - } + pub fn key(&self) -> Option<&'a str> { + self._tab.get::>(DataGet::VT_KEY, None) } - } -pub struct ImageTransformArgs { - pub transform: ImageTransformType, - pub options_type: ImageTransformOptions, - pub options: Option>, +pub struct DataGetArgs<'a> { + pub collection: Option>, + pub key: Option>, } -impl<'a> Default for ImageTransformArgs { +impl<'a> Default for DataGetArgs<'a> { #[inline] fn default() -> Self { - ImageTransformArgs { - transform: ImageTransformType::ImageWebPEncode, - options_type: ImageTransformOptions::NONE, - options: None, + DataGetArgs { + collection: None, + key: None, } } } -pub struct ImageTransformBuilder<'a: 'b, 'b> { +pub struct DataGetBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> ImageTransformBuilder<'a, 'b> { - #[inline] - pub fn add_transform(&mut self, transform: ImageTransformType) { - self.fbb_.push_slot::(ImageTransform::VT_TRANSFORM, transform, ImageTransformType::ImageWebPEncode); - } +impl<'a: 'b, 'b> DataGetBuilder<'a, 'b> { #[inline] - pub fn add_options_type(&mut self, options_type: ImageTransformOptions) { - self.fbb_.push_slot::(ImageTransform::VT_OPTIONS_TYPE, options_type, ImageTransformOptions::NONE); + pub fn add_collection(&mut self, collection: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataGet::VT_COLLECTION, collection); } #[inline] - pub fn add_options(&mut self, options: flatbuffers::WIPOffset) { - self.fbb_.push_slot_always::>(ImageTransform::VT_OPTIONS, options); + pub fn add_key(&mut self, key: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataGet::VT_KEY, key); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ImageTransformBuilder<'a, 'b> { + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataGetBuilder<'a, 'b> { let start = _fbb.start_table(); - ImageTransformBuilder { + DataGetBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } } -pub enum ImageApplyTransformsOffset {} +pub enum DataGetReadyOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct ImageApplyTransforms<'a> { +pub struct DataGetReady<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for ImageApplyTransforms<'a> { - type Inner = ImageApplyTransforms<'a>; +impl<'a> flatbuffers::Follow<'a> for DataGetReady<'a> { + type Inner = DataGetReady<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -3834,50 +3896,734 @@ impl<'a> flatbuffers::Follow<'a> for ImageApplyTransforms<'a> { } } -impl<'a> ImageApplyTransforms<'a> { +impl<'a> DataGetReady<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - ImageApplyTransforms { + DataGetReady { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args ImageApplyTransformsArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = ImageApplyTransformsBuilder::new(_fbb); - if let Some(x) = args.transforms { builder.add_transforms(x); } + args: &'args DataGetReadyArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = DataGetReadyBuilder::new(_fbb); + if let Some(x) = args.json { builder.add_json(x); } builder.finish() } - pub const VT_TRANSFORMS: flatbuffers::VOffsetT = 4; + pub const VT_JSON: flatbuffers::VOffsetT = 4; #[inline] - pub fn transforms(&self) -> Option>>> { - self._tab.get::>>>>(ImageApplyTransforms::VT_TRANSFORMS, None) + pub fn json(&self) -> Option<&'a str> { + self._tab.get::>(DataGetReady::VT_JSON, None) } } -pub struct ImageApplyTransformsArgs<'a> { - pub transforms: Option>>>>, +pub struct DataGetReadyArgs<'a> { + pub json: Option>, } -impl<'a> Default for ImageApplyTransformsArgs<'a> { +impl<'a> Default for DataGetReadyArgs<'a> { #[inline] fn default() -> Self { - ImageApplyTransformsArgs { - transforms: None, + DataGetReadyArgs { + json: None, } } } -pub struct ImageApplyTransformsBuilder<'a: 'b, 'b> { +pub struct DataGetReadyBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> ImageApplyTransformsBuilder<'a, 'b> { +impl<'a: 'b, 'b> DataGetReadyBuilder<'a, 'b> { #[inline] - pub fn add_transforms(&mut self, transforms: flatbuffers::WIPOffset>>>) { - self.fbb_.push_slot_always::>(ImageApplyTransforms::VT_TRANSFORMS, transforms); - } + pub fn add_json(&mut self, json: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataGetReady::VT_JSON, json); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataGetReadyBuilder<'a, 'b> { + let start = _fbb.start_table(); + DataGetReadyBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +pub enum DataDelOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct DataDel<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for DataDel<'a> { + type Inner = DataDel<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> DataDel<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + DataDel { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args DataDelArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = DataDelBuilder::new(_fbb); + if let Some(x) = args.key { builder.add_key(x); } + if let Some(x) = args.collection { builder.add_collection(x); } + builder.finish() + } + + pub const VT_COLLECTION: flatbuffers::VOffsetT = 4; + pub const VT_KEY: flatbuffers::VOffsetT = 6; + + #[inline] + pub fn collection(&self) -> Option<&'a str> { + self._tab.get::>(DataDel::VT_COLLECTION, None) + } + #[inline] + pub fn key(&self) -> Option<&'a str> { + self._tab.get::>(DataDel::VT_KEY, None) + } +} + +pub struct DataDelArgs<'a> { + pub collection: Option>, + pub key: Option>, +} +impl<'a> Default for DataDelArgs<'a> { + #[inline] + fn default() -> Self { + DataDelArgs { + collection: None, + key: None, + } + } +} +pub struct DataDelBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> DataDelBuilder<'a, 'b> { + #[inline] + pub fn add_collection(&mut self, collection: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataDel::VT_COLLECTION, collection); + } + #[inline] + pub fn add_key(&mut self, key: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataDel::VT_KEY, key); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataDelBuilder<'a, 'b> { + let start = _fbb.start_table(); + DataDelBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +pub enum DataDropCollectionOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct DataDropCollection<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for DataDropCollection<'a> { + type Inner = DataDropCollection<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> DataDropCollection<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + DataDropCollection { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args DataDropCollectionArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = DataDropCollectionBuilder::new(_fbb); + if let Some(x) = args.collection { builder.add_collection(x); } + builder.finish() + } + + pub const VT_COLLECTION: flatbuffers::VOffsetT = 4; + + #[inline] + pub fn collection(&self) -> Option<&'a str> { + self._tab.get::>(DataDropCollection::VT_COLLECTION, None) + } +} + +pub struct DataDropCollectionArgs<'a> { + pub collection: Option>, +} +impl<'a> Default for DataDropCollectionArgs<'a> { + #[inline] + fn default() -> Self { + DataDropCollectionArgs { + collection: None, + } + } +} +pub struct DataDropCollectionBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> DataDropCollectionBuilder<'a, 'b> { + #[inline] + pub fn add_collection(&mut self, collection: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataDropCollection::VT_COLLECTION, collection); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataDropCollectionBuilder<'a, 'b> { + let start = _fbb.start_table(); + DataDropCollectionBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +pub enum DataIncrOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct DataIncr<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for DataIncr<'a> { + type Inner = DataIncr<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> DataIncr<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + DataIncr { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args DataIncrArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = DataIncrBuilder::new(_fbb); + builder.add_amount(args.amount); + if let Some(x) = args.field { builder.add_field(x); } + if let Some(x) = args.key { builder.add_key(x); } + if let Some(x) = args.collection { builder.add_collection(x); } + builder.finish() + } + + pub const VT_COLLECTION: flatbuffers::VOffsetT = 4; + pub const VT_KEY: flatbuffers::VOffsetT = 6; + pub const VT_FIELD: flatbuffers::VOffsetT = 8; + pub const VT_AMOUNT: flatbuffers::VOffsetT = 10; + + #[inline] + pub fn collection(&self) -> Option<&'a str> { + self._tab.get::>(DataIncr::VT_COLLECTION, None) + } + #[inline] + pub fn key(&self) -> Option<&'a str> { + self._tab.get::>(DataIncr::VT_KEY, None) + } + #[inline] + pub fn field(&self) -> Option<&'a str> { + self._tab.get::>(DataIncr::VT_FIELD, None) + } + #[inline] + pub fn amount(&self) -> i32 { + self._tab.get::(DataIncr::VT_AMOUNT, Some(0)).unwrap() + } +} + +pub struct DataIncrArgs<'a> { + pub collection: Option>, + pub key: Option>, + pub field: Option>, + pub amount: i32, +} +impl<'a> Default for DataIncrArgs<'a> { + #[inline] + fn default() -> Self { + DataIncrArgs { + collection: None, + key: None, + field: None, + amount: 0, + } + } +} +pub struct DataIncrBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> DataIncrBuilder<'a, 'b> { + #[inline] + pub fn add_collection(&mut self, collection: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataIncr::VT_COLLECTION, collection); + } + #[inline] + pub fn add_key(&mut self, key: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataIncr::VT_KEY, key); + } + #[inline] + pub fn add_field(&mut self, field: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(DataIncr::VT_FIELD, field); + } + #[inline] + pub fn add_amount(&mut self, amount: i32) { + self.fbb_.push_slot::(DataIncr::VT_AMOUNT, amount, 0); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataIncrBuilder<'a, 'b> { + let start = _fbb.start_table(); + DataIncrBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +pub enum ImageWebPEncodeOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct ImageWebPEncode<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for ImageWebPEncode<'a> { + type Inner = ImageWebPEncode<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> ImageWebPEncode<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + ImageWebPEncode { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args ImageWebPEncodeArgs) -> flatbuffers::WIPOffset> { + let mut builder = ImageWebPEncodeBuilder::new(_fbb); + builder.add_alpha_quality(args.alpha_quality); + builder.add_quality(args.quality); + builder.add_near_lossless(args.near_lossless); + builder.add_lossless(args.lossless); + builder.finish() + } + + pub const VT_QUALITY: flatbuffers::VOffsetT = 4; + pub const VT_ALPHA_QUALITY: flatbuffers::VOffsetT = 6; + pub const VT_LOSSLESS: flatbuffers::VOffsetT = 8; + pub const VT_NEAR_LOSSLESS: flatbuffers::VOffsetT = 10; + + #[inline] + pub fn quality(&self) -> f32 { + self._tab.get::(ImageWebPEncode::VT_QUALITY, Some(0.0)).unwrap() + } + #[inline] + pub fn alpha_quality(&self) -> f32 { + self._tab.get::(ImageWebPEncode::VT_ALPHA_QUALITY, Some(0.0)).unwrap() + } + #[inline] + pub fn lossless(&self) -> bool { + self._tab.get::(ImageWebPEncode::VT_LOSSLESS, Some(false)).unwrap() + } + #[inline] + pub fn near_lossless(&self) -> bool { + self._tab.get::(ImageWebPEncode::VT_NEAR_LOSSLESS, Some(false)).unwrap() + } +} + +pub struct ImageWebPEncodeArgs { + pub quality: f32, + pub alpha_quality: f32, + pub lossless: bool, + pub near_lossless: bool, +} +impl<'a> Default for ImageWebPEncodeArgs { + #[inline] + fn default() -> Self { + ImageWebPEncodeArgs { + quality: 0.0, + alpha_quality: 0.0, + lossless: false, + near_lossless: false, + } + } +} +pub struct ImageWebPEncodeBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> ImageWebPEncodeBuilder<'a, 'b> { + #[inline] + pub fn add_quality(&mut self, quality: f32) { + self.fbb_.push_slot::(ImageWebPEncode::VT_QUALITY, quality, 0.0); + } + #[inline] + pub fn add_alpha_quality(&mut self, alpha_quality: f32) { + self.fbb_.push_slot::(ImageWebPEncode::VT_ALPHA_QUALITY, alpha_quality, 0.0); + } + #[inline] + pub fn add_lossless(&mut self, lossless: bool) { + self.fbb_.push_slot::(ImageWebPEncode::VT_LOSSLESS, lossless, false); + } + #[inline] + pub fn add_near_lossless(&mut self, near_lossless: bool) { + self.fbb_.push_slot::(ImageWebPEncode::VT_NEAR_LOSSLESS, near_lossless, false); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ImageWebPEncodeBuilder<'a, 'b> { + let start = _fbb.start_table(); + ImageWebPEncodeBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +pub enum ImageResizeOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct ImageResize<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for ImageResize<'a> { + type Inner = ImageResize<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> ImageResize<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + ImageResize { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args ImageResizeArgs) -> flatbuffers::WIPOffset> { + let mut builder = ImageResizeBuilder::new(_fbb); + builder.add_height(args.height); + builder.add_width(args.width); + builder.add_filter(args.filter); + builder.finish() + } + + pub const VT_WIDTH: flatbuffers::VOffsetT = 4; + pub const VT_HEIGHT: flatbuffers::VOffsetT = 6; + pub const VT_FILTER: flatbuffers::VOffsetT = 8; + + #[inline] + pub fn width(&self) -> u32 { + self._tab.get::(ImageResize::VT_WIDTH, Some(0)).unwrap() + } + #[inline] + pub fn height(&self) -> u32 { + self._tab.get::(ImageResize::VT_HEIGHT, Some(0)).unwrap() + } + #[inline] + pub fn filter(&self) -> ImageSamplingFilter { + self._tab.get::(ImageResize::VT_FILTER, Some(ImageSamplingFilter::Nearest)).unwrap() + } +} + +pub struct ImageResizeArgs { + pub width: u32, + pub height: u32, + pub filter: ImageSamplingFilter, +} +impl<'a> Default for ImageResizeArgs { + #[inline] + fn default() -> Self { + ImageResizeArgs { + width: 0, + height: 0, + filter: ImageSamplingFilter::Nearest, + } + } +} +pub struct ImageResizeBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> ImageResizeBuilder<'a, 'b> { + #[inline] + pub fn add_width(&mut self, width: u32) { + self.fbb_.push_slot::(ImageResize::VT_WIDTH, width, 0); + } + #[inline] + pub fn add_height(&mut self, height: u32) { + self.fbb_.push_slot::(ImageResize::VT_HEIGHT, height, 0); + } + #[inline] + pub fn add_filter(&mut self, filter: ImageSamplingFilter) { + self.fbb_.push_slot::(ImageResize::VT_FILTER, filter, ImageSamplingFilter::Nearest); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ImageResizeBuilder<'a, 'b> { + let start = _fbb.start_table(); + ImageResizeBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +pub enum ImageTransformOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct ImageTransform<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for ImageTransform<'a> { + type Inner = ImageTransform<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> ImageTransform<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + ImageTransform { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args ImageTransformArgs) -> flatbuffers::WIPOffset> { + let mut builder = ImageTransformBuilder::new(_fbb); + if let Some(x) = args.options { builder.add_options(x); } + builder.add_options_type(args.options_type); + builder.add_transform(args.transform); + builder.finish() + } + + pub const VT_TRANSFORM: flatbuffers::VOffsetT = 4; + pub const VT_OPTIONS_TYPE: flatbuffers::VOffsetT = 6; + pub const VT_OPTIONS: flatbuffers::VOffsetT = 8; + + #[inline] + pub fn transform(&self) -> ImageTransformType { + self._tab.get::(ImageTransform::VT_TRANSFORM, Some(ImageTransformType::WebPEncode)).unwrap() + } + #[inline] + pub fn options_type(&self) -> ImageTransformOptions { + self._tab.get::(ImageTransform::VT_OPTIONS_TYPE, Some(ImageTransformOptions::NONE)).unwrap() + } + #[inline] + pub fn options(&self) -> Option> { + self._tab.get::>>(ImageTransform::VT_OPTIONS, None) + } + #[inline] + #[allow(non_snake_case)] + pub fn options_as_image_web_pencode(&'a self) -> Option { + if self.options_type() == ImageTransformOptions::ImageWebPEncode { + self.options().map(|u| ImageWebPEncode::init_from_table(u)) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn options_as_image_resize(&'a self) -> Option { + if self.options_type() == ImageTransformOptions::ImageResize { + self.options().map(|u| ImageResize::init_from_table(u)) + } else { + None + } + } + +} + +pub struct ImageTransformArgs { + pub transform: ImageTransformType, + pub options_type: ImageTransformOptions, + pub options: Option>, +} +impl<'a> Default for ImageTransformArgs { + #[inline] + fn default() -> Self { + ImageTransformArgs { + transform: ImageTransformType::WebPEncode, + options_type: ImageTransformOptions::NONE, + options: None, + } + } +} +pub struct ImageTransformBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> ImageTransformBuilder<'a, 'b> { + #[inline] + pub fn add_transform(&mut self, transform: ImageTransformType) { + self.fbb_.push_slot::(ImageTransform::VT_TRANSFORM, transform, ImageTransformType::WebPEncode); + } + #[inline] + pub fn add_options_type(&mut self, options_type: ImageTransformOptions) { + self.fbb_.push_slot::(ImageTransform::VT_OPTIONS_TYPE, options_type, ImageTransformOptions::NONE); + } + #[inline] + pub fn add_options(&mut self, options: flatbuffers::WIPOffset) { + self.fbb_.push_slot_always::>(ImageTransform::VT_OPTIONS, options); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ImageTransformBuilder<'a, 'b> { + let start = _fbb.start_table(); + ImageTransformBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +pub enum ImageApplyTransformsOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct ImageApplyTransforms<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for ImageApplyTransforms<'a> { + type Inner = ImageApplyTransforms<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> ImageApplyTransforms<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + ImageApplyTransforms { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args ImageApplyTransformsArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = ImageApplyTransformsBuilder::new(_fbb); + if let Some(x) = args.transforms { builder.add_transforms(x); } + builder.finish() + } + + pub const VT_TRANSFORMS: flatbuffers::VOffsetT = 4; + + #[inline] + pub fn transforms(&self) -> Option>>> { + self._tab.get::>>>>(ImageApplyTransforms::VT_TRANSFORMS, None) + } +} + +pub struct ImageApplyTransformsArgs<'a> { + pub transforms: Option>>>>, +} +impl<'a> Default for ImageApplyTransformsArgs<'a> { + #[inline] + fn default() -> Self { + ImageApplyTransformsArgs { + transforms: None, + } + } +} +pub struct ImageApplyTransformsBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> ImageApplyTransformsBuilder<'a, 'b> { + #[inline] + pub fn add_transforms(&mut self, transforms: flatbuffers::WIPOffset>>>) { + self.fbb_.push_slot_always::>(ImageApplyTransforms::VT_TRANSFORMS, transforms); + } #[inline] pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ImageApplyTransformsBuilder<'a, 'b> { let start = _fbb.start_table(); @@ -4157,6 +4903,82 @@ impl<'a: 'b, 'b> AcmeGetChallengeReadyBuilder<'a, 'b> { } } +pub enum OsExitOffset {} +#[derive(Copy, Clone, Debug, PartialEq)] + +pub struct OsExit<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for OsExit<'a> { + type Inner = OsExit<'a>; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table { buf: buf, loc: loc }, + } + } +} + +impl<'a> OsExit<'a> { + #[inline] + pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + OsExit { + _tab: table, + } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args OsExitArgs) -> flatbuffers::WIPOffset> { + let mut builder = OsExitBuilder::new(_fbb); + builder.add_code(args.code); + builder.finish() + } + + pub const VT_CODE: flatbuffers::VOffsetT = 4; + + #[inline] + pub fn code(&self) -> i32 { + self._tab.get::(OsExit::VT_CODE, Some(0)).unwrap() + } +} + +pub struct OsExitArgs { + pub code: i32, +} +impl<'a> Default for OsExitArgs { + #[inline] + fn default() -> Self { + OsExitArgs { + code: 0, + } + } +} +pub struct OsExitBuilder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> OsExitBuilder<'a, 'b> { + #[inline] + pub fn add_code(&mut self, code: i32) { + self.fbb_.push_slot::(OsExit::VT_CODE, code, 0); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> OsExitBuilder<'a, 'b> { + let start = _fbb.start_table(); + OsExitBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + pub enum BaseOffset {} #[derive(Copy, Clone, Debug, PartialEq)] @@ -4516,6 +5338,16 @@ impl<'a> Base<'a> { } } + #[inline] + #[allow(non_snake_case)] + pub fn msg_as_data_incr(&'a self) -> Option { + if self.msg_type() == Any::DataIncr { + self.msg().map(|u| DataIncr::init_from_table(u)) + } else { + None + } + } + #[inline] #[allow(non_snake_case)] pub fn msg_as_data_drop_collection(&'a self) -> Option { @@ -4626,6 +5458,56 @@ impl<'a> Base<'a> { } } + #[inline] + #[allow(non_snake_case)] + pub fn msg_as_service_request(&'a self) -> Option { + if self.msg_type() == Any::ServiceRequest { + self.msg().map(|u| ServiceRequest::init_from_table(u)) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn msg_as_service_response(&'a self) -> Option { + if self.msg_type() == Any::ServiceResponse { + self.msg().map(|u| ServiceResponse::init_from_table(u)) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn msg_as_request_service_request(&'a self) -> Option { + if self.msg_type() == Any::RequestServiceRequest { + self.msg().map(|u| RequestServiceRequest::init_from_table(u)) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn msg_as_request_service_response(&'a self) -> Option { + if self.msg_type() == Any::RequestServiceResponse { + self.msg().map(|u| RequestServiceResponse::init_from_table(u)) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn msg_as_os_exit(&'a self) -> Option { + if self.msg_type() == Any::OsExit { + self.msg().map(|u| OsExit::init_from_table(u)) + } else { + None + } + } + } pub struct BaseArgs<'a> { @@ -5150,6 +6032,7 @@ impl<'a> HttpRequest<'a> { _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, args: &'args HttpRequestArgs<'args>) -> flatbuffers::WIPOffset> { let mut builder = HttpRequestBuilder::new(_fbb); + if let Some(x) = args.remote_addr { builder.add_remote_addr(x); } if let Some(x) = args.headers { builder.add_headers(x); } if let Some(x) = args.url { builder.add_url(x); } builder.add_id(args.id); @@ -5162,7 +6045,8 @@ impl<'a> HttpRequest<'a> { pub const VT_METHOD: flatbuffers::VOffsetT = 6; pub const VT_URL: flatbuffers::VOffsetT = 8; pub const VT_HEADERS: flatbuffers::VOffsetT = 10; - pub const VT_HAS_BODY: flatbuffers::VOffsetT = 12; + pub const VT_REMOTE_ADDR: flatbuffers::VOffsetT = 12; + pub const VT_HAS_BODY: flatbuffers::VOffsetT = 14; #[inline] pub fn id(&self) -> u32 { @@ -5181,6 +6065,10 @@ impl<'a> HttpRequest<'a> { self._tab.get::>>>>(HttpRequest::VT_HEADERS, None) } #[inline] + pub fn remote_addr(&self) -> Option<&'a str> { + self._tab.get::>(HttpRequest::VT_REMOTE_ADDR, None) + } + #[inline] pub fn has_body(&self) -> bool { self._tab.get::(HttpRequest::VT_HAS_BODY, Some(false)).unwrap() } @@ -5191,6 +6079,7 @@ pub struct HttpRequestArgs<'a> { pub method: HttpMethod, pub url: Option>, pub headers: Option>>>>, + pub remote_addr: Option>, pub has_body: bool, } impl<'a> Default for HttpRequestArgs<'a> { @@ -5201,6 +6090,7 @@ impl<'a> Default for HttpRequestArgs<'a> { method: HttpMethod::Get, url: None, headers: None, + remote_addr: None, has_body: false, } } @@ -5227,6 +6117,10 @@ impl<'a: 'b, 'b> HttpRequestBuilder<'a, 'b> { self.fbb_.push_slot_always::>(HttpRequest::VT_HEADERS, headers); } #[inline] + pub fn add_remote_addr(&mut self, remote_addr: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(HttpRequest::VT_REMOTE_ADDR, remote_addr); + } + #[inline] pub fn add_has_body(&mut self, has_body: bool) { self.fbb_.push_slot::(HttpRequest::VT_HAS_BODY, has_body, false); } @@ -6113,115 +7007,15 @@ impl<'a: 'b, 'b> SourceMapReadyBuilder<'a, 'b> { } } -pub enum DataPutOffset {} -#[derive(Copy, Clone, Debug, PartialEq)] - -pub struct DataPut<'a> { - pub _tab: flatbuffers::Table<'a>, -} - -impl<'a> flatbuffers::Follow<'a> for DataPut<'a> { - type Inner = DataPut<'a>; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - Self { - _tab: flatbuffers::Table { buf: buf, loc: loc }, - } - } -} - -impl<'a> DataPut<'a> { - #[inline] - pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - DataPut { - _tab: table, - } - } - #[allow(unused_mut)] - pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( - _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args DataPutArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = DataPutBuilder::new(_fbb); - if let Some(x) = args.json { builder.add_json(x); } - if let Some(x) = args.key { builder.add_key(x); } - if let Some(x) = args.collection { builder.add_collection(x); } - builder.finish() - } - - pub const VT_COLLECTION: flatbuffers::VOffsetT = 4; - pub const VT_KEY: flatbuffers::VOffsetT = 6; - pub const VT_JSON: flatbuffers::VOffsetT = 8; - - #[inline] - pub fn collection(&self) -> Option<&'a str> { - self._tab.get::>(DataPut::VT_COLLECTION, None) - } - #[inline] - pub fn key(&self) -> Option<&'a str> { - self._tab.get::>(DataPut::VT_KEY, None) - } - #[inline] - pub fn json(&self) -> Option<&'a str> { - self._tab.get::>(DataPut::VT_JSON, None) - } -} - -pub struct DataPutArgs<'a> { - pub collection: Option>, - pub key: Option>, - pub json: Option>, -} -impl<'a> Default for DataPutArgs<'a> { - #[inline] - fn default() -> Self { - DataPutArgs { - collection: None, - key: None, - json: None, - } - } -} -pub struct DataPutBuilder<'a: 'b, 'b> { - fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, - start_: flatbuffers::WIPOffset, -} -impl<'a: 'b, 'b> DataPutBuilder<'a, 'b> { - #[inline] - pub fn add_collection(&mut self, collection: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(DataPut::VT_COLLECTION, collection); - } - #[inline] - pub fn add_key(&mut self, key: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(DataPut::VT_KEY, key); - } - #[inline] - pub fn add_json(&mut self, json: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(DataPut::VT_JSON, json); - } - #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataPutBuilder<'a, 'b> { - let start = _fbb.start_table(); - DataPutBuilder { - fbb_: _fbb, - start_: start, - } - } - #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { - let o = self.fbb_.end_table(self.start_); - flatbuffers::WIPOffset::new(o.value()) - } -} - -pub enum DataGetOffset {} +pub enum AddEventListenerOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct DataGet<'a> { +pub struct AddEventListener<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for DataGet<'a> { - type Inner = DataGet<'a>; +impl<'a> flatbuffers::Follow<'a> for AddEventListener<'a> { + type Inner = AddEventListener<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -6230,86 +7024,74 @@ impl<'a> flatbuffers::Follow<'a> for DataGet<'a> { } } -impl<'a> DataGet<'a> { +impl<'a> AddEventListener<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - DataGet { + AddEventListener { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args DataGetArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = DataGetBuilder::new(_fbb); - if let Some(x) = args.key { builder.add_key(x); } - if let Some(x) = args.collection { builder.add_collection(x); } + args: &'args AddEventListenerArgs) -> flatbuffers::WIPOffset> { + let mut builder = AddEventListenerBuilder::new(_fbb); + builder.add_event(args.event); builder.finish() } - pub const VT_COLLECTION: flatbuffers::VOffsetT = 4; - pub const VT_KEY: flatbuffers::VOffsetT = 6; + pub const VT_EVENT: flatbuffers::VOffsetT = 4; #[inline] - pub fn collection(&self) -> Option<&'a str> { - self._tab.get::>(DataGet::VT_COLLECTION, None) - } - #[inline] - pub fn key(&self) -> Option<&'a str> { - self._tab.get::>(DataGet::VT_KEY, None) + pub fn event(&self) -> EventType { + self._tab.get::(AddEventListener::VT_EVENT, Some(EventType::Fetch)).unwrap() } } -pub struct DataGetArgs<'a> { - pub collection: Option>, - pub key: Option>, +pub struct AddEventListenerArgs { + pub event: EventType, } -impl<'a> Default for DataGetArgs<'a> { +impl<'a> Default for AddEventListenerArgs { #[inline] fn default() -> Self { - DataGetArgs { - collection: None, - key: None, + AddEventListenerArgs { + event: EventType::Fetch, } } } -pub struct DataGetBuilder<'a: 'b, 'b> { +pub struct AddEventListenerBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> DataGetBuilder<'a, 'b> { - #[inline] - pub fn add_collection(&mut self, collection: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(DataGet::VT_COLLECTION, collection); - } +impl<'a: 'b, 'b> AddEventListenerBuilder<'a, 'b> { #[inline] - pub fn add_key(&mut self, key: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(DataGet::VT_KEY, key); + pub fn add_event(&mut self, event: EventType) { + self.fbb_.push_slot::(AddEventListener::VT_EVENT, event, EventType::Fetch); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataGetBuilder<'a, 'b> { + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> AddEventListenerBuilder<'a, 'b> { let start = _fbb.start_table(); - DataGetBuilder { + AddEventListenerBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } } -pub enum DataGetReadyOffset {} +pub enum LoadModuleOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct DataGetReady<'a> { +pub struct LoadModule<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for DataGetReady<'a> { - type Inner = DataGetReady<'a>; +impl<'a> flatbuffers::Follow<'a> for LoadModule<'a> { + type Inner = LoadModule<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -6318,74 +7100,86 @@ impl<'a> flatbuffers::Follow<'a> for DataGetReady<'a> { } } -impl<'a> DataGetReady<'a> { +impl<'a> LoadModule<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - DataGetReady { + LoadModule { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args DataGetReadyArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = DataGetReadyBuilder::new(_fbb); - if let Some(x) = args.json { builder.add_json(x); } + args: &'args LoadModuleArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = LoadModuleBuilder::new(_fbb); + if let Some(x) = args.referer_origin_url { builder.add_referer_origin_url(x); } + if let Some(x) = args.specifier_url { builder.add_specifier_url(x); } builder.finish() } - pub const VT_JSON: flatbuffers::VOffsetT = 4; + pub const VT_SPECIFIER_URL: flatbuffers::VOffsetT = 4; + pub const VT_REFERER_ORIGIN_URL: flatbuffers::VOffsetT = 6; #[inline] - pub fn json(&self) -> Option<&'a str> { - self._tab.get::>(DataGetReady::VT_JSON, None) + pub fn specifier_url(&self) -> Option<&'a str> { + self._tab.get::>(LoadModule::VT_SPECIFIER_URL, None) + } + #[inline] + pub fn referer_origin_url(&self) -> Option<&'a str> { + self._tab.get::>(LoadModule::VT_REFERER_ORIGIN_URL, None) } } -pub struct DataGetReadyArgs<'a> { - pub json: Option>, +pub struct LoadModuleArgs<'a> { + pub specifier_url: Option>, + pub referer_origin_url: Option>, } -impl<'a> Default for DataGetReadyArgs<'a> { +impl<'a> Default for LoadModuleArgs<'a> { #[inline] fn default() -> Self { - DataGetReadyArgs { - json: None, + LoadModuleArgs { + specifier_url: None, + referer_origin_url: None, } } } -pub struct DataGetReadyBuilder<'a: 'b, 'b> { +pub struct LoadModuleBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> DataGetReadyBuilder<'a, 'b> { +impl<'a: 'b, 'b> LoadModuleBuilder<'a, 'b> { #[inline] - pub fn add_json(&mut self, json: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(DataGetReady::VT_JSON, json); + pub fn add_specifier_url(&mut self, specifier_url: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(LoadModule::VT_SPECIFIER_URL, specifier_url); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataGetReadyBuilder<'a, 'b> { + pub fn add_referer_origin_url(&mut self, referer_origin_url: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(LoadModule::VT_REFERER_ORIGIN_URL, referer_origin_url); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> LoadModuleBuilder<'a, 'b> { let start = _fbb.start_table(); - DataGetReadyBuilder { + LoadModuleBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } } -pub enum DataDelOffset {} +pub enum LoadModuleRespOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct DataDel<'a> { +pub struct LoadModuleResp<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for DataDel<'a> { - type Inner = DataDel<'a>; +impl<'a> flatbuffers::Follow<'a> for LoadModuleResp<'a> { + type Inner = LoadModuleResp<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -6394,86 +7188,86 @@ impl<'a> flatbuffers::Follow<'a> for DataDel<'a> { } } -impl<'a> DataDel<'a> { +impl<'a> LoadModuleResp<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - DataDel { + LoadModuleResp { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args DataDelArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = DataDelBuilder::new(_fbb); - if let Some(x) = args.key { builder.add_key(x); } - if let Some(x) = args.collection { builder.add_collection(x); } + args: &'args LoadModuleRespArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = LoadModuleRespBuilder::new(_fbb); + if let Some(x) = args.source_code { builder.add_source_code(x); } + if let Some(x) = args.origin_url { builder.add_origin_url(x); } builder.finish() } - pub const VT_COLLECTION: flatbuffers::VOffsetT = 4; - pub const VT_KEY: flatbuffers::VOffsetT = 6; + pub const VT_ORIGIN_URL: flatbuffers::VOffsetT = 4; + pub const VT_SOURCE_CODE: flatbuffers::VOffsetT = 6; #[inline] - pub fn collection(&self) -> Option<&'a str> { - self._tab.get::>(DataDel::VT_COLLECTION, None) + pub fn origin_url(&self) -> Option<&'a str> { + self._tab.get::>(LoadModuleResp::VT_ORIGIN_URL, None) } #[inline] - pub fn key(&self) -> Option<&'a str> { - self._tab.get::>(DataDel::VT_KEY, None) + pub fn source_code(&self) -> Option<&'a str> { + self._tab.get::>(LoadModuleResp::VT_SOURCE_CODE, None) } } -pub struct DataDelArgs<'a> { - pub collection: Option>, - pub key: Option>, +pub struct LoadModuleRespArgs<'a> { + pub origin_url: Option>, + pub source_code: Option>, } -impl<'a> Default for DataDelArgs<'a> { +impl<'a> Default for LoadModuleRespArgs<'a> { #[inline] fn default() -> Self { - DataDelArgs { - collection: None, - key: None, + LoadModuleRespArgs { + origin_url: None, + source_code: None, } } } -pub struct DataDelBuilder<'a: 'b, 'b> { +pub struct LoadModuleRespBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> DataDelBuilder<'a, 'b> { +impl<'a: 'b, 'b> LoadModuleRespBuilder<'a, 'b> { #[inline] - pub fn add_collection(&mut self, collection: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(DataDel::VT_COLLECTION, collection); + pub fn add_origin_url(&mut self, origin_url: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(LoadModuleResp::VT_ORIGIN_URL, origin_url); } #[inline] - pub fn add_key(&mut self, key: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(DataDel::VT_KEY, key); + pub fn add_source_code(&mut self, source_code: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(LoadModuleResp::VT_SOURCE_CODE, source_code); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataDelBuilder<'a, 'b> { + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> LoadModuleRespBuilder<'a, 'b> { let start = _fbb.start_table(); - DataDelBuilder { + LoadModuleRespBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } } -pub enum DataDropCollectionOffset {} +pub enum ServiceRequestOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct DataDropCollection<'a> { +pub struct ServiceRequest<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for DataDropCollection<'a> { - type Inner = DataDropCollection<'a>; +impl<'a> flatbuffers::Follow<'a> for ServiceRequest<'a> { + type Inner = ServiceRequest<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -6482,74 +7276,98 @@ impl<'a> flatbuffers::Follow<'a> for DataDropCollection<'a> { } } -impl<'a> DataDropCollection<'a> { +impl<'a> ServiceRequest<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - DataDropCollection { + ServiceRequest { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args DataDropCollectionArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = DataDropCollectionBuilder::new(_fbb); - if let Some(x) = args.collection { builder.add_collection(x); } + args: &'args ServiceRequestArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = ServiceRequestBuilder::new(_fbb); + if let Some(x) = args.data { builder.add_data(x); } + if let Some(x) = args.sender { builder.add_sender(x); } + builder.add_id(args.id); builder.finish() } - pub const VT_COLLECTION: flatbuffers::VOffsetT = 4; + pub const VT_ID: flatbuffers::VOffsetT = 4; + pub const VT_SENDER: flatbuffers::VOffsetT = 6; + pub const VT_DATA: flatbuffers::VOffsetT = 8; #[inline] - pub fn collection(&self) -> Option<&'a str> { - self._tab.get::>(DataDropCollection::VT_COLLECTION, None) + pub fn id(&self) -> u32 { + self._tab.get::(ServiceRequest::VT_ID, Some(0)).unwrap() + } + #[inline] + pub fn sender(&self) -> Option<&'a str> { + self._tab.get::>(ServiceRequest::VT_SENDER, None) + } + #[inline] + pub fn data(&self) -> Option<&'a str> { + self._tab.get::>(ServiceRequest::VT_DATA, None) } } -pub struct DataDropCollectionArgs<'a> { - pub collection: Option>, +pub struct ServiceRequestArgs<'a> { + pub id: u32, + pub sender: Option>, + pub data: Option>, } -impl<'a> Default for DataDropCollectionArgs<'a> { +impl<'a> Default for ServiceRequestArgs<'a> { #[inline] fn default() -> Self { - DataDropCollectionArgs { - collection: None, + ServiceRequestArgs { + id: 0, + sender: None, + data: None, } } } -pub struct DataDropCollectionBuilder<'a: 'b, 'b> { +pub struct ServiceRequestBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> DataDropCollectionBuilder<'a, 'b> { +impl<'a: 'b, 'b> ServiceRequestBuilder<'a, 'b> { #[inline] - pub fn add_collection(&mut self, collection: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(DataDropCollection::VT_COLLECTION, collection); + pub fn add_id(&mut self, id: u32) { + self.fbb_.push_slot::(ServiceRequest::VT_ID, id, 0); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> DataDropCollectionBuilder<'a, 'b> { + pub fn add_sender(&mut self, sender: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(ServiceRequest::VT_SENDER, sender); + } + #[inline] + pub fn add_data(&mut self, data: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(ServiceRequest::VT_DATA, data); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ServiceRequestBuilder<'a, 'b> { let start = _fbb.start_table(); - DataDropCollectionBuilder { + ServiceRequestBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } } -pub enum AddEventListenerOffset {} +pub enum ServiceResponseOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct AddEventListener<'a> { +pub struct ServiceResponse<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for AddEventListener<'a> { - type Inner = AddEventListener<'a>; +impl<'a> flatbuffers::Follow<'a> for ServiceResponse<'a> { + type Inner = ServiceResponse<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -6558,74 +7376,98 @@ impl<'a> flatbuffers::Follow<'a> for AddEventListener<'a> { } } -impl<'a> AddEventListener<'a> { +impl<'a> ServiceResponse<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - AddEventListener { + ServiceResponse { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args AddEventListenerArgs) -> flatbuffers::WIPOffset> { - let mut builder = AddEventListenerBuilder::new(_fbb); - builder.add_event(args.event); + args: &'args ServiceResponseArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = ServiceResponseBuilder::new(_fbb); + if let Some(x) = args.data { builder.add_data(x); } + builder.add_id(args.id); + builder.add_success(args.success); builder.finish() } - pub const VT_EVENT: flatbuffers::VOffsetT = 4; + pub const VT_ID: flatbuffers::VOffsetT = 4; + pub const VT_SUCCESS: flatbuffers::VOffsetT = 6; + pub const VT_DATA: flatbuffers::VOffsetT = 8; #[inline] - pub fn event(&self) -> EventType { - self._tab.get::(AddEventListener::VT_EVENT, Some(EventType::Fetch)).unwrap() + pub fn id(&self) -> u32 { + self._tab.get::(ServiceResponse::VT_ID, Some(0)).unwrap() + } + #[inline] + pub fn success(&self) -> bool { + self._tab.get::(ServiceResponse::VT_SUCCESS, Some(false)).unwrap() + } + #[inline] + pub fn data(&self) -> Option<&'a str> { + self._tab.get::>(ServiceResponse::VT_DATA, None) } } -pub struct AddEventListenerArgs { - pub event: EventType, +pub struct ServiceResponseArgs<'a> { + pub id: u32, + pub success: bool, + pub data: Option>, } -impl<'a> Default for AddEventListenerArgs { +impl<'a> Default for ServiceResponseArgs<'a> { #[inline] fn default() -> Self { - AddEventListenerArgs { - event: EventType::Fetch, + ServiceResponseArgs { + id: 0, + success: false, + data: None, } } } -pub struct AddEventListenerBuilder<'a: 'b, 'b> { +pub struct ServiceResponseBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> AddEventListenerBuilder<'a, 'b> { +impl<'a: 'b, 'b> ServiceResponseBuilder<'a, 'b> { #[inline] - pub fn add_event(&mut self, event: EventType) { - self.fbb_.push_slot::(AddEventListener::VT_EVENT, event, EventType::Fetch); + pub fn add_id(&mut self, id: u32) { + self.fbb_.push_slot::(ServiceResponse::VT_ID, id, 0); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> AddEventListenerBuilder<'a, 'b> { + pub fn add_success(&mut self, success: bool) { + self.fbb_.push_slot::(ServiceResponse::VT_SUCCESS, success, false); + } + #[inline] + pub fn add_data(&mut self, data: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(ServiceResponse::VT_DATA, data); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ServiceResponseBuilder<'a, 'b> { let start = _fbb.start_table(); - AddEventListenerBuilder { + ServiceResponseBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } } -pub enum LoadModuleOffset {} +pub enum RequestServiceRequestOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct LoadModule<'a> { +pub struct RequestServiceRequest<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for LoadModule<'a> { - type Inner = LoadModule<'a>; +impl<'a> flatbuffers::Follow<'a> for RequestServiceRequest<'a> { + type Inner = RequestServiceRequest<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -6634,86 +7476,86 @@ impl<'a> flatbuffers::Follow<'a> for LoadModule<'a> { } } -impl<'a> LoadModule<'a> { +impl<'a> RequestServiceRequest<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - LoadModule { + RequestServiceRequest { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args LoadModuleArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = LoadModuleBuilder::new(_fbb); - if let Some(x) = args.containing_file { builder.add_containing_file(x); } - if let Some(x) = args.module_specifier { builder.add_module_specifier(x); } + args: &'args RequestServiceRequestArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = RequestServiceRequestBuilder::new(_fbb); + if let Some(x) = args.data { builder.add_data(x); } + if let Some(x) = args.destination_name { builder.add_destination_name(x); } builder.finish() } - pub const VT_MODULE_SPECIFIER: flatbuffers::VOffsetT = 4; - pub const VT_CONTAINING_FILE: flatbuffers::VOffsetT = 6; + pub const VT_DESTINATION_NAME: flatbuffers::VOffsetT = 4; + pub const VT_DATA: flatbuffers::VOffsetT = 6; #[inline] - pub fn module_specifier(&self) -> Option<&'a str> { - self._tab.get::>(LoadModule::VT_MODULE_SPECIFIER, None) + pub fn destination_name(&self) -> Option<&'a str> { + self._tab.get::>(RequestServiceRequest::VT_DESTINATION_NAME, None) } #[inline] - pub fn containing_file(&self) -> Option<&'a str> { - self._tab.get::>(LoadModule::VT_CONTAINING_FILE, None) + pub fn data(&self) -> Option<&'a str> { + self._tab.get::>(RequestServiceRequest::VT_DATA, None) } } -pub struct LoadModuleArgs<'a> { - pub module_specifier: Option>, - pub containing_file: Option>, +pub struct RequestServiceRequestArgs<'a> { + pub destination_name: Option>, + pub data: Option>, } -impl<'a> Default for LoadModuleArgs<'a> { +impl<'a> Default for RequestServiceRequestArgs<'a> { #[inline] fn default() -> Self { - LoadModuleArgs { - module_specifier: None, - containing_file: None, + RequestServiceRequestArgs { + destination_name: None, + data: None, } } } -pub struct LoadModuleBuilder<'a: 'b, 'b> { +pub struct RequestServiceRequestBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> LoadModuleBuilder<'a, 'b> { +impl<'a: 'b, 'b> RequestServiceRequestBuilder<'a, 'b> { #[inline] - pub fn add_module_specifier(&mut self, module_specifier: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(LoadModule::VT_MODULE_SPECIFIER, module_specifier); + pub fn add_destination_name(&mut self, destination_name: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(RequestServiceRequest::VT_DESTINATION_NAME, destination_name); } #[inline] - pub fn add_containing_file(&mut self, containing_file: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(LoadModule::VT_CONTAINING_FILE, containing_file); + pub fn add_data(&mut self, data: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(RequestServiceRequest::VT_DATA, data); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> LoadModuleBuilder<'a, 'b> { + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> RequestServiceRequestBuilder<'a, 'b> { let start = _fbb.start_table(); - LoadModuleBuilder { + RequestServiceRequestBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } } -pub enum LoadModuleRespOffset {} +pub enum RequestServiceResponseOffset {} #[derive(Copy, Clone, Debug, PartialEq)] -pub struct LoadModuleResp<'a> { +pub struct RequestServiceResponse<'a> { pub _tab: flatbuffers::Table<'a>, } -impl<'a> flatbuffers::Follow<'a> for LoadModuleResp<'a> { - type Inner = LoadModuleResp<'a>; +impl<'a> flatbuffers::Follow<'a> for RequestServiceResponse<'a> { + type Inner = RequestServiceResponse<'a>; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { Self { @@ -6722,84 +7564,72 @@ impl<'a> flatbuffers::Follow<'a> for LoadModuleResp<'a> { } } -impl<'a> LoadModuleResp<'a> { +impl<'a> RequestServiceResponse<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - LoadModuleResp { + RequestServiceResponse { _tab: table, } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, - args: &'args LoadModuleRespArgs<'args>) -> flatbuffers::WIPOffset> { - let mut builder = LoadModuleRespBuilder::new(_fbb); - if let Some(x) = args.source_code { builder.add_source_code(x); } - if let Some(x) = args.file_name { builder.add_file_name(x); } - if let Some(x) = args.module_id { builder.add_module_id(x); } + args: &'args RequestServiceResponseArgs<'args>) -> flatbuffers::WIPOffset> { + let mut builder = RequestServiceResponseBuilder::new(_fbb); + if let Some(x) = args.data { builder.add_data(x); } + builder.add_success(args.success); builder.finish() } - pub const VT_MODULE_ID: flatbuffers::VOffsetT = 4; - pub const VT_FILE_NAME: flatbuffers::VOffsetT = 6; - pub const VT_SOURCE_CODE: flatbuffers::VOffsetT = 8; + pub const VT_SUCCESS: flatbuffers::VOffsetT = 4; + pub const VT_DATA: flatbuffers::VOffsetT = 6; #[inline] - pub fn module_id(&self) -> Option<&'a str> { - self._tab.get::>(LoadModuleResp::VT_MODULE_ID, None) - } - #[inline] - pub fn file_name(&self) -> Option<&'a str> { - self._tab.get::>(LoadModuleResp::VT_FILE_NAME, None) + pub fn success(&self) -> bool { + self._tab.get::(RequestServiceResponse::VT_SUCCESS, Some(false)).unwrap() } #[inline] - pub fn source_code(&self) -> Option<&'a str> { - self._tab.get::>(LoadModuleResp::VT_SOURCE_CODE, None) + pub fn data(&self) -> Option<&'a str> { + self._tab.get::>(RequestServiceResponse::VT_DATA, None) } } -pub struct LoadModuleRespArgs<'a> { - pub module_id: Option>, - pub file_name: Option>, - pub source_code: Option>, +pub struct RequestServiceResponseArgs<'a> { + pub success: bool, + pub data: Option>, } -impl<'a> Default for LoadModuleRespArgs<'a> { +impl<'a> Default for RequestServiceResponseArgs<'a> { #[inline] fn default() -> Self { - LoadModuleRespArgs { - module_id: None, - file_name: None, - source_code: None, + RequestServiceResponseArgs { + success: false, + data: None, } } } -pub struct LoadModuleRespBuilder<'a: 'b, 'b> { +pub struct RequestServiceResponseBuilder<'a: 'b, 'b> { fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, start_: flatbuffers::WIPOffset, } -impl<'a: 'b, 'b> LoadModuleRespBuilder<'a, 'b> { - #[inline] - pub fn add_module_id(&mut self, module_id: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(LoadModuleResp::VT_MODULE_ID, module_id); - } +impl<'a: 'b, 'b> RequestServiceResponseBuilder<'a, 'b> { #[inline] - pub fn add_file_name(&mut self, file_name: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(LoadModuleResp::VT_FILE_NAME, file_name); + pub fn add_success(&mut self, success: bool) { + self.fbb_.push_slot::(RequestServiceResponse::VT_SUCCESS, success, false); } #[inline] - pub fn add_source_code(&mut self, source_code: flatbuffers::WIPOffset<&'b str>) { - self.fbb_.push_slot_always::>(LoadModuleResp::VT_SOURCE_CODE, source_code); + pub fn add_data(&mut self, data: flatbuffers::WIPOffset<&'b str>) { + self.fbb_.push_slot_always::>(RequestServiceResponse::VT_DATA, data); } #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> LoadModuleRespBuilder<'a, 'b> { + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> RequestServiceResponseBuilder<'a, 'b> { let start = _fbb.start_table(); - LoadModuleRespBuilder { + RequestServiceResponseBuilder { fbb_: _fbb, start_: start, } } #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { + pub fn finish(self) -> flatbuffers::WIPOffset> { let o = self.fbb_.end_table(self.start_); flatbuffers::WIPOffset::new(o.value()) } diff --git a/src/msg_handler.rs b/src/msg_handler.rs new file mode 100644 index 0000000..8414f19 --- /dev/null +++ b/src/msg_handler.rs @@ -0,0 +1,54 @@ +use crate::msg; +use crate::runtime::Runtime; +use libfly::*; + +use crate::ops; +use crate::utils::*; + +pub trait MessageHandler: Send + Sync { + fn handle_msg(&self, rt: &mut Runtime, base: &msg::Base, raw_buf: fly_buf) -> Box; +} + +pub struct DefaultMessageHandler {} + +impl MessageHandler for DefaultMessageHandler { + fn handle_msg(&self, rt: &mut Runtime, base: &msg::Base, raw_buf: fly_buf) -> Box { + let msg_type = base.msg_type(); + trace!("MSG TYPE: {:?}", msg_type); + let handler: Handler = match msg_type { + msg::Any::TimerStart => ops::timers::op_timer_start, + msg::Any::TimerClear => ops::timers::op_timer_clear, + msg::Any::HttpRequest => ops::fetch::op_fetch, + msg::Any::HttpResponse => ops::fetch::op_http_response, + msg::Any::StreamChunk => ops::streams::op_stream_chunk, + msg::Any::CacheGet => ops::cache::op_cache_get, + msg::Any::CacheSet => ops::cache::op_cache_set, + msg::Any::CacheDel => ops::cache::op_cache_del, + msg::Any::CacheNotifyDel => ops::cache::op_cache_notify_del, + msg::Any::CacheNotifyPurgeTag => ops::cache::op_cache_notify_purge_tag, + msg::Any::CacheExpire => ops::cache::op_cache_expire, + msg::Any::CacheSetMeta => ops::cache::op_cache_set_meta, + msg::Any::CachePurgeTag => ops::cache::op_cache_purge_tag, + msg::Any::CryptoDigest => ops::crypto::op_crypto_digest, + msg::Any::CryptoRandomValues => ops::crypto::op_crypto_random_values, + msg::Any::SourceMap => ops::source_map::op_source_map, + msg::Any::DataPut => ops::data::op_data_put, + msg::Any::DataGet => ops::data::op_data_get, + msg::Any::DataDel => ops::data::op_data_del, + msg::Any::DataIncr => ops::data::op_data_incr, + msg::Any::DataDropCollection => ops::data::op_data_drop_coll, + msg::Any::DnsQuery => ops::dns::op_dns_query, + msg::Any::DnsResponse => ops::dns::op_dns_response, + msg::Any::AddEventListener => ops::events::op_add_event_ln, + msg::Any::LoadModule => ops::modules::op_load_module, + msg::Any::ImageApplyTransforms => ops::image::op_image_transform, + msg::Any::AcmeGetChallenge => ops::acme::op_get_challenge, + msg::Any::RequestServiceRequest => ops::service::op_request_service_request, + msg::Any::ServiceResponse => ops::service::op_service_response, + msg::Any::OsExit => ops::os::op_exit, + _ => unimplemented!(), + }; + + handler(rt, base, raw_buf) + } +} diff --git a/src/ops/acme.rs b/src/ops/acme.rs index 2a05683..5a80ff3 100644 --- a/src/ops/acme.rs +++ b/src/ops/acme.rs @@ -1,23 +1,23 @@ use crate::msg; -use crate::runtime::{JsRuntime, Op}; +use crate::runtime::Runtime; use crate::utils::*; use flatbuffers::FlatBufferBuilder; use futures::Future; use libfly::*; -pub fn op_get_challenge(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_get_challenge(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let cmd_id = base.cmd_id(); let msg = base.msg_as_acme_get_challenge().unwrap(); let hostname = msg.hostname().unwrap().to_string(); let token = msg.token().unwrap().to_string(); - let acme_store = &ptr.to_runtime().acme_store; + let acme_store = rt.acme_store.as_ref(); if acme_store.is_none() { return Box::new(odd_future("No acme store configured".to_string().into())); } - let acme_store = acme_store.as_ref().unwrap(); + let acme_store = acme_store.unwrap(); Box::new( acme_store diff --git a/src/ops/cache.rs b/src/ops/cache.rs index 992ee23..27755ff 100644 --- a/src/ops/cache.rs +++ b/src/ops/cache.rs @@ -3,7 +3,8 @@ use futures::sync::mpsc; use crate::msg; use flatbuffers::FlatBufferBuilder; -use crate::runtime::{JsBody, JsRuntime, Op}; +use crate::js::*; +use crate::runtime::Runtime; use crate::utils::*; use libfly::*; @@ -14,12 +15,10 @@ use futures::{Future, Stream}; use crate::cache_store::*; use crate::cache_store_notifier::*; -pub fn op_cache_del(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_cache_del(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let msg = base.msg_as_cache_del().unwrap(); let key = msg.key().unwrap().to_string(); - let rt = ptr.to_runtime(); - rt.spawn( rt.cache_store .del(key) @@ -29,13 +28,11 @@ pub fn op_cache_del(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box ok_future(None) } -pub fn op_cache_expire(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_cache_expire(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let msg = base.msg_as_cache_expire().unwrap(); let key = msg.key().unwrap().to_string(); let ttl = msg.ttl(); - let rt = ptr.to_runtime(); - rt.spawn( rt.cache_store .expire(key, ttl) @@ -45,15 +42,13 @@ pub fn op_cache_expire(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box Box { +pub fn op_cache_set(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let cmd_id = base.cmd_id(); let msg = base.msg_as_cache_set().unwrap(); let key = msg.key().unwrap().to_string(); let stream_id = get_next_stream_id(); - let rt = ptr.to_runtime(); - let (sender, recver) = mpsc::unbounded::>(); { rt.streams.lock().unwrap().insert(stream_id, sender); @@ -76,15 +71,14 @@ pub fn op_cache_set(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box None => None, }; - let fut = rt.cache_store.set( - key, - Box::new(recver), - CacheSetOptions { - ttl, - tags, - meta: None, - }, - ); + let meta = match msg.meta() { + Some(m) => Some(m.to_string()), + None => None, + }; + + let fut = rt + .cache_store + .set(key, Box::new(recver), CacheSetOptions { ttl, tags, meta }); rt.spawn( fut @@ -111,25 +105,34 @@ pub fn op_cache_set(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box )) } -pub fn op_cache_get(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_cache_get(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let cmd_id = base.cmd_id(); let msg = base.msg_as_cache_get().unwrap(); let stream_id = get_next_stream_id(); let key = msg.key().unwrap().to_string(); + let ptr = rt.ptr; - let rt = ptr.to_runtime(); Box::new( rt.cache_store .get(key) .map_err(|e| format!("cache error: {:?}", e).into()) .and_then(move |maybe_entry| { let builder = &mut FlatBufferBuilder::new(); + let meta = if let Some(ref entry) = maybe_entry { + match entry.meta { + Some(ref m) => Some(builder.create_string(m.as_str())), + None => None, + } + } else { + None + }; let msg = msg::CacheGetReady::create( builder, &msg::CacheGetReadyArgs { id: stream_id, + meta, stream: maybe_entry.is_some(), ..Default::default() }, @@ -156,10 +159,9 @@ pub fn op_cache_get(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box ) } -pub fn op_cache_notify_del(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_cache_notify_del(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let msg = base.msg_as_cache_notify_del().unwrap(); - let rt = ptr.to_runtime(); let key = msg.key().unwrap().to_string(); Box::new( @@ -176,11 +178,9 @@ pub fn op_cache_notify_del(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> B ) } -pub fn op_cache_notify_purge_tag(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_cache_notify_purge_tag(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let msg = base.msg_as_cache_notify_purge_tag().unwrap(); - let rt = ptr.to_runtime(); - let tag = msg.tag().unwrap().to_string(); Box::new( @@ -197,13 +197,11 @@ pub fn op_cache_notify_purge_tag(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf ) } -pub fn op_cache_set_meta(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_cache_set_meta(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let msg = base.msg_as_cache_set_meta().unwrap(); let key = msg.key().unwrap().to_string(); let meta = msg.meta().unwrap().to_string(); - let rt = ptr.to_runtime(); - rt.spawn( rt.cache_store .set_meta(key, meta) @@ -213,12 +211,10 @@ pub fn op_cache_set_meta(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box ok_future(None) } -pub fn op_cache_purge_tag(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_cache_purge_tag(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let msg = base.msg_as_cache_purge_tag().unwrap(); let tag = msg.tag().unwrap().to_string(); - let rt = ptr.to_runtime(); - rt.spawn( rt.cache_store .purge_tag(tag) diff --git a/src/ops/crypto.rs b/src/ops/crypto.rs new file mode 100644 index 0000000..e3ef556 --- /dev/null +++ b/src/ops/crypto.rs @@ -0,0 +1,96 @@ +use crate::msg; +use flatbuffers::FlatBufferBuilder; + +use crate::runtime::Runtime; +use libfly::*; + +use crate::utils::*; + +use rand::{thread_rng, Rng}; + +#[allow(unused_imports)] +use sha1::Digest as Sha1Digest; // puts trait in scope +use sha1::Sha1; + +#[allow(unused_imports)] +use sha2::Digest; // puts trait in scope +use sha2::Sha256; + +use futures::future; +use std::slice; + +pub fn op_crypto_random_values(_rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let cmd_id = base.cmd_id(); + let msg = base.msg_as_crypto_random_values().unwrap(); + + let len = msg.len() as usize; + let mut v = vec![0u8; len]; + let arr = v.as_mut_slice(); + + thread_rng().fill(arr); + + let builder = &mut FlatBufferBuilder::new(); + let ret_buffer = builder.create_vector(arr); + + let crypto_rand = msg::CryptoRandomValuesReady::create( + builder, + &msg::CryptoRandomValuesReadyArgs { + buffer: Some(ret_buffer), + ..Default::default() + }, + ); + + ok_future(serialize_response( + cmd_id, + builder, + msg::BaseArgs { + msg: Some(crypto_rand.as_union_value()), + msg_type: msg::Any::CryptoRandomValuesReady, + ..Default::default() + }, + )) +} + +pub fn op_crypto_digest(_rt: &mut Runtime, base: &msg::Base, raw: fly_buf) -> Box { + let cmd_id = base.cmd_id(); + let msg = base.msg_as_crypto_digest().unwrap(); + + let algo = msg.algo().unwrap().to_uppercase(); + let buffer = unsafe { slice::from_raw_parts(raw.data_ptr, raw.data_len) }.to_vec(); + + Box::new(future::lazy(move || { + let builder = &mut FlatBufferBuilder::new(); + let bytes_vec = match algo.as_str() { + "SHA-256" => { + let mut h = Sha256::default(); + h.input(buffer.as_slice()); + let res = h.result(); + builder.create_vector(res.as_slice()) + } + "SHA-1" => { + let mut h = Sha1::default(); + h.input(buffer.as_slice()); + let res = h.result(); + builder.create_vector(res.as_slice()) + } + _ => unimplemented!(), + }; + + let crypto_ready = msg::CryptoDigestReady::create( + builder, + &msg::CryptoDigestReadyArgs { + buffer: Some(bytes_vec), + ..Default::default() + }, + ); + Ok(serialize_response( + cmd_id, + builder, + msg::BaseArgs { + msg: Some(crypto_ready.as_union_value()), + msg_type: msg::Any::CryptoDigestReady, + ..Default::default() + }, + )) + })) +} diff --git a/src/ops/data.fbs b/src/ops/data.fbs new file mode 100644 index 0000000..20f81c5 --- /dev/null +++ b/src/ops/data.fbs @@ -0,0 +1,25 @@ +table DataPut { + collection: string; + key: string; + json: string; +} +table DataGet { + collection: string; + key: string; +} +table DataGetReady { + json: string; +} +table DataDel { + collection: string; + key: string; +} +table DataDropCollection { + collection: string; +} +table DataIncr { + collection: string; + key: string; + field: string; + amount: int; +} \ No newline at end of file diff --git a/src/ops/data.rs b/src/ops/data.rs new file mode 100644 index 0000000..1c3e3d0 --- /dev/null +++ b/src/ops/data.rs @@ -0,0 +1,98 @@ +use crate::msg; +use flatbuffers::FlatBufferBuilder; + +use crate::runtime::Runtime; +use crate::utils::*; +use libfly::*; + +use futures::Future; + +pub fn op_data_put(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let msg = base.msg_as_data_put().unwrap(); + let coll = msg.collection().unwrap().to_string(); + let key = msg.key().unwrap().to_string(); + let value = msg.json().unwrap().to_string(); + + Box::new( + rt.data_store + .put(coll, key, value) + .map_err(|e| format!("{:?}", e).into()) + .and_then(move |_| Ok(None)), + ) +} + +pub fn op_data_get(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let cmd_id = base.cmd_id(); + let msg = base.msg_as_data_get().unwrap(); + let coll = msg.collection().unwrap().to_string(); + let key = msg.key().unwrap().to_string(); + + Box::new( + rt.data_store + .get(coll, key) + .map_err(|e| format!("error in data store get: {:?}", e).into()) + .and_then(move |s| match s { + None => Ok(None), + Some(s) => { + let builder = &mut FlatBufferBuilder::new(); + let json = builder.create_string(&s); + let msg = msg::DataGetReady::create( + builder, + &msg::DataGetReadyArgs { + json: Some(json), + ..Default::default() + }, + ); + Ok(serialize_response( + cmd_id, + builder, + msg::BaseArgs { + msg: Some(msg.as_union_value()), + msg_type: msg::Any::DataGetReady, + ..Default::default() + }, + )) + } + }), + ) +} + +pub fn op_data_del(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let msg = base.msg_as_data_del().unwrap(); + let coll = msg.collection().unwrap().to_string(); + let key = msg.key().unwrap().to_string(); + + Box::new( + rt.data_store + .del(coll, key) + .map_err(|e| format!("{:?}", e).into()) + .and_then(move |_| Ok(None)), + ) +} + +pub fn op_data_drop_coll(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let msg = base.msg_as_data_drop_collection().unwrap(); + let coll = msg.collection().unwrap().to_string(); + + Box::new( + rt.data_store + .drop_coll(coll) + .map_err(|e| format!("{:?}", e).into()) + .and_then(move |_| Ok(None)), + ) +} + +pub fn op_data_incr(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let msg = base.msg_as_data_incr().unwrap(); + let coll = msg.collection().unwrap().to_string(); + let key = msg.key().unwrap().to_string(); + let field = msg.field().unwrap().to_string(); + let amount = msg.amount(); + + Box::new( + rt.data_store + .incr(coll, key, field, amount) + .map_err(|e| format!("{:?}", e).into()) + .and_then(move |_| Ok(None)), + ) +} diff --git a/src/ops/dns.rs b/src/ops/dns.rs index 1c1c3ec..4427173 100644 --- a/src/ops/dns.rs +++ b/src/ops/dns.rs @@ -1,16 +1,14 @@ use crate::msg; use flatbuffers::FlatBufferBuilder; -extern crate trust_dns as dns; -extern crate trust_dns_proto as dns_proto; -extern crate trust_dns_resolver as dns_resolver; -use self::dns::client::ClientHandle; // necessary for trait to be in scope -use self::dns_resolver::config::ResolverConfig; +use trust_dns::client::ClientHandle; // necessary for trait to be in scope +use trust_dns::proto as dns_proto; +use trust_dns_resolver::config::ResolverConfig; use std::collections::HashMap; use std::sync::Mutex; -use crate::runtime::{JsRuntime, Op, EVENT_LOOP}; +use crate::runtime::{Runtime, EVENT_LOOP}; use crate::utils::*; use libfly::*; @@ -18,9 +16,11 @@ use futures::Future; use std::net::{SocketAddr, ToSocketAddrs}; +use crate::js::*; + lazy_static! { static ref DEFAULT_RESOLVER_CONFIG: ResolverConfig = { - match dns_resolver::system_conf::read_system_conf() { + match trust_dns_resolver::system_conf::read_system_conf() { Ok((r, _)) => r, Err(e) => { warn!("error getting system resolv conf: {}, using google's", e); @@ -28,64 +28,31 @@ lazy_static! { } } }; - static ref DEFAULT_RESOLVER: Mutex> = { - let (stream, handle) = - dns::udp::UdpClientStream::new(DEFAULT_RESOLVER_CONFIG.name_servers()[0].socket_addr); - let (bg, client) = dns::client::ClientFuture::new(stream, handle, None); + static ref DEFAULT_RESOLVER: Mutex> = { + let stream = + trust_dns::udp::UdpClientStream::new(DEFAULT_RESOLVER_CONFIG.name_servers()[0].socket_addr); + let (bg, client) = trust_dns::client::ClientFuture::connect(stream); EVENT_LOOP.0.spawn(bg); Mutex::new(client) }; - static ref DNS_RESOLVERS: Mutex< - HashMap< - SocketAddr, - dns::client::BasicClientHandle, - >, - > = Mutex::new(HashMap::new()); -} - -#[derive(Debug)] -pub struct JsDnsResponse { - pub op_code: dns::op::OpCode, - pub message_type: dns::op::MessageType, - pub response_code: dns::op::ResponseCode, - pub answers: Vec, - pub queries: Vec, - pub authoritative: bool, - pub truncated: bool, -} - -#[derive(Debug)] -pub struct JsDnsRequest { - pub id: u32, - pub message_type: dns::op::MessageType, - pub queries: Vec, -} - -#[derive(Debug)] -pub struct JsDnsRecord { - pub name: dns::rr::Name, - pub rdata: dns::rr::RData, - pub dns_class: dns::rr::DNSClass, - pub ttl: u32, -} - -#[derive(Debug)] -pub struct JsDnsQuery { - pub name: dns::rr::Name, - pub rr_type: dns::rr::RecordType, - pub dns_class: dns::rr::DNSClass, + static ref DNS_RESOLVERS: Mutex>> = + Mutex::new(HashMap::new()); } fn dns_query( cmd_id: u32, - client: &mut dns::client::BasicClientHandle, + client: &mut trust_dns::client::BasicClientHandle, name: &str, - query_type: dns::rr::RecordType, + query_type: trust_dns::rr::RecordType, ) -> Box { debug!("dns_query {} {}", cmd_id, name); Box::new( client - .query(name.parse().unwrap(), dns::rr::DNSClass::IN, query_type) + .query( + name.parse().unwrap(), + trust_dns::rr::DNSClass::IN, + query_type, + ) .map_err(|e| format!("dns query error: {}", e).into()) .and_then(move |res| { // debug!("got a dns response! {:?}", res); @@ -98,7 +65,7 @@ fn dns_query( .iter() .map(|ans| { debug!("answer: {:?}", ans); - use self::dns::rr::{DNSClass, RData, RecordType}; + use trust_dns::rr::{DNSClass, RData, RecordType}; let name = builder.create_string(&ans.name().to_utf8()); let rr_type = match ans.rr_type() { RecordType::A => msg::DnsRecordType::A, @@ -305,28 +272,28 @@ fn dns_query( ) } -pub fn op_dns_query(_ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_dns_query(_rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { debug!("handle dns"); let cmd_id = base.cmd_id(); let msg = base.msg_as_dns_query().unwrap(); let query_type = match msg.rr_type() { - msg::DnsRecordType::A => dns::rr::RecordType::A, - msg::DnsRecordType::AAAA => dns::rr::RecordType::AAAA, - msg::DnsRecordType::ANY => dns::rr::RecordType::ANY, - msg::DnsRecordType::AXFR => dns::rr::RecordType::AXFR, - msg::DnsRecordType::CAA => dns::rr::RecordType::CAA, - msg::DnsRecordType::CNAME => dns::rr::RecordType::CNAME, - msg::DnsRecordType::IXFR => dns::rr::RecordType::IXFR, - msg::DnsRecordType::MX => dns::rr::RecordType::MX, - msg::DnsRecordType::NS => dns::rr::RecordType::NS, - msg::DnsRecordType::NULL => dns::rr::RecordType::NULL, - msg::DnsRecordType::OPT => dns::rr::RecordType::OPT, - msg::DnsRecordType::PTR => dns::rr::RecordType::PTR, - msg::DnsRecordType::SOA => dns::rr::RecordType::SOA, - msg::DnsRecordType::SRV => dns::rr::RecordType::SRV, - msg::DnsRecordType::TLSA => dns::rr::RecordType::TLSA, - msg::DnsRecordType::TXT => dns::rr::RecordType::TXT, + msg::DnsRecordType::A => trust_dns::rr::RecordType::A, + msg::DnsRecordType::AAAA => trust_dns::rr::RecordType::AAAA, + msg::DnsRecordType::ANY => trust_dns::rr::RecordType::ANY, + msg::DnsRecordType::AXFR => trust_dns::rr::RecordType::AXFR, + msg::DnsRecordType::CAA => trust_dns::rr::RecordType::CAA, + msg::DnsRecordType::CNAME => trust_dns::rr::RecordType::CNAME, + msg::DnsRecordType::IXFR => trust_dns::rr::RecordType::IXFR, + msg::DnsRecordType::MX => trust_dns::rr::RecordType::MX, + msg::DnsRecordType::NS => trust_dns::rr::RecordType::NS, + msg::DnsRecordType::NULL => trust_dns::rr::RecordType::NULL, + msg::DnsRecordType::OPT => trust_dns::rr::RecordType::OPT, + msg::DnsRecordType::PTR => trust_dns::rr::RecordType::PTR, + msg::DnsRecordType::SOA => trust_dns::rr::RecordType::SOA, + msg::DnsRecordType::SRV => trust_dns::rr::RecordType::SRV, + msg::DnsRecordType::TLSA => trust_dns::rr::RecordType::TLSA, + msg::DnsRecordType::TXT => trust_dns::rr::RecordType::TXT, }; let name = msg.name().unwrap(); @@ -346,8 +313,8 @@ pub fn op_dns_query(_ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box return dns_query(cmd_id, client, name, query_type); } } - let (stream, handle) = dns::udp::UdpClientStream::new(sockaddr.clone()); - let (bg, client) = dns::client::ClientFuture::new(stream, handle, None); + let stream = trust_dns::udp::UdpClientStream::new(sockaddr.clone()); + let (bg, client) = trust_dns::client::ClientFuture::connect(stream); EVENT_LOOP.0.spawn(bg); { DNS_RESOLVERS @@ -369,25 +336,25 @@ pub fn op_dns_query(_ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box } } -pub fn op_dns_response(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +pub fn op_dns_response(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let msg = base.msg_as_dns_response().unwrap(); let req_id = msg.id(); let op_code = match msg.op_code() { - msg::DnsOpCode::Query => dns::op::OpCode::Query, - msg::DnsOpCode::Status => dns::op::OpCode::Status, - msg::DnsOpCode::Notify => dns::op::OpCode::Notify, - msg::DnsOpCode::Update => dns::op::OpCode::Update, + msg::DnsOpCode::Query => trust_dns::op::OpCode::Query, + msg::DnsOpCode::Status => trust_dns::op::OpCode::Status, + msg::DnsOpCode::Notify => trust_dns::op::OpCode::Notify, + msg::DnsOpCode::Update => trust_dns::op::OpCode::Update, }; let res_code = msg.response_code() as u16; let message_type = match msg.message_type() { - msg::DnsMessageType::Query => dns::op::MessageType::Query, - msg::DnsMessageType::Response => dns::op::MessageType::Response, + msg::DnsMessageType::Query => trust_dns::op::MessageType::Query, + msg::DnsMessageType::Response => trust_dns::op::MessageType::Response, }; - use self::dns::rr::RData; + use trust_dns::rr::RData; let queries: Vec = if let Some(msg_queries) = msg.queries() { let qlen = msg_queries.len(); @@ -396,30 +363,30 @@ pub fn op_dns_response(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box dns::rr::RecordType::A, - msg::DnsRecordType::AAAA => dns::rr::RecordType::AAAA, - msg::DnsRecordType::ANY => dns::rr::RecordType::ANY, - msg::DnsRecordType::AXFR => dns::rr::RecordType::AXFR, - msg::DnsRecordType::CAA => dns::rr::RecordType::CAA, - msg::DnsRecordType::CNAME => dns::rr::RecordType::CNAME, - msg::DnsRecordType::IXFR => dns::rr::RecordType::IXFR, - msg::DnsRecordType::MX => dns::rr::RecordType::MX, - msg::DnsRecordType::NS => dns::rr::RecordType::NS, - msg::DnsRecordType::NULL => dns::rr::RecordType::NULL, - msg::DnsRecordType::OPT => dns::rr::RecordType::OPT, - msg::DnsRecordType::PTR => dns::rr::RecordType::PTR, - msg::DnsRecordType::SOA => dns::rr::RecordType::SOA, - msg::DnsRecordType::SRV => dns::rr::RecordType::SRV, - msg::DnsRecordType::TLSA => dns::rr::RecordType::TLSA, - msg::DnsRecordType::TXT => dns::rr::RecordType::TXT, + msg::DnsRecordType::A => trust_dns::rr::RecordType::A, + msg::DnsRecordType::AAAA => trust_dns::rr::RecordType::AAAA, + msg::DnsRecordType::ANY => trust_dns::rr::RecordType::ANY, + msg::DnsRecordType::AXFR => trust_dns::rr::RecordType::AXFR, + msg::DnsRecordType::CAA => trust_dns::rr::RecordType::CAA, + msg::DnsRecordType::CNAME => trust_dns::rr::RecordType::CNAME, + msg::DnsRecordType::IXFR => trust_dns::rr::RecordType::IXFR, + msg::DnsRecordType::MX => trust_dns::rr::RecordType::MX, + msg::DnsRecordType::NS => trust_dns::rr::RecordType::NS, + msg::DnsRecordType::NULL => trust_dns::rr::RecordType::NULL, + msg::DnsRecordType::OPT => trust_dns::rr::RecordType::OPT, + msg::DnsRecordType::PTR => trust_dns::rr::RecordType::PTR, + msg::DnsRecordType::SOA => trust_dns::rr::RecordType::SOA, + msg::DnsRecordType::SRV => trust_dns::rr::RecordType::SRV, + msg::DnsRecordType::TLSA => trust_dns::rr::RecordType::TLSA, + msg::DnsRecordType::TXT => trust_dns::rr::RecordType::TXT, }; let dns_class = match q.dns_class() { - msg::DnsClass::IN => dns::rr::DNSClass::IN, - msg::DnsClass::CH => dns::rr::DNSClass::CH, - msg::DnsClass::HS => dns::rr::DNSClass::HS, - msg::DnsClass::NONE => dns::rr::DNSClass::NONE, - msg::DnsClass::ANY => dns::rr::DNSClass::ANY, + msg::DnsClass::IN => trust_dns::rr::DNSClass::IN, + msg::DnsClass::CH => trust_dns::rr::DNSClass::CH, + msg::DnsClass::HS => trust_dns::rr::DNSClass::HS, + msg::DnsClass::NONE => trust_dns::rr::DNSClass::NONE, + msg::DnsClass::ANY => trust_dns::rr::DNSClass::ANY, }; queries.push(JsDnsQuery { @@ -440,11 +407,11 @@ pub fn op_dns_response(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box dns::rr::DNSClass::IN, - msg::DnsClass::CH => dns::rr::DNSClass::CH, - msg::DnsClass::HS => dns::rr::DNSClass::HS, - msg::DnsClass::NONE => dns::rr::DNSClass::NONE, - msg::DnsClass::ANY => dns::rr::DNSClass::ANY, + msg::DnsClass::IN => trust_dns::rr::DNSClass::IN, + msg::DnsClass::CH => trust_dns::rr::DNSClass::CH, + msg::DnsClass::HS => trust_dns::rr::DNSClass::HS, + msg::DnsClass::NONE => trust_dns::rr::DNSClass::NONE, + msg::DnsClass::ANY => trust_dns::rr::DNSClass::ANY, }; let rdata: RData = match ans.rdata_type() { @@ -462,7 +429,7 @@ pub fn op_dns_response(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { let d = ans.rdata_as_dns_mx().unwrap(); - RData::MX(dns::rr::rdata::mx::MX::new( + RData::MX(trust_dns::rr::rdata::mx::MX::new( d.preference(), d.exchange().unwrap().parse().unwrap(), )) @@ -477,7 +444,7 @@ pub fn op_dns_response(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { let d = ans.rdata_as_dns_soa().unwrap(); - RData::SOA(dns::rr::rdata::soa::SOA::new( + RData::SOA(trust_dns::rr::rdata::soa::SOA::new( d.mname().unwrap().parse().unwrap(), d.rname().unwrap().parse().unwrap(), d.serial(), @@ -489,7 +456,7 @@ pub fn op_dns_response(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { let d = ans.rdata_as_dns_srv().unwrap(); - RData::SRV(dns::rr::rdata::srv::SRV::new( + RData::SRV(trust_dns::rr::rdata::srv::SRV::new( d.priority(), d.weight(), d.port(), @@ -505,7 +472,7 @@ pub fn op_dns_response(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box unimplemented!(), }; @@ -522,8 +489,6 @@ pub fn op_dns_response(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { diff --git a/src/ops/events.rs b/src/ops/events.rs new file mode 100644 index 0000000..4086060 --- /dev/null +++ b/src/ops/events.rs @@ -0,0 +1,239 @@ +use crate::msg; +use flatbuffers::FlatBufferBuilder; + +use crate::runtime::Runtime; +use libfly::*; + +use crate::js::*; +use crate::utils::*; + +use hyper::Method; + +use futures::{sync::mpsc, Future, Stream}; + +use trust_dns as dns; + +pub fn op_add_event_ln(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let msg = base.msg_as_add_event_listener().unwrap(); + let ptr = rt.ptr; + + match msg.event() { + msg::EventType::Fetch => { + let (tx, rx) = mpsc::unbounded::(); + rt.spawn( + rx.map_err(|_| error!("error event receiving http request")) + .for_each(move |req| { + debug!("Listener received new http event."); + let builder = &mut FlatBufferBuilder::new(); + + let req_url = builder.create_string(req.url.as_str()); + + let req_method = match req.method { + Method::GET => msg::HttpMethod::Get, + Method::POST => msg::HttpMethod::Post, + Method::PUT => msg::HttpMethod::Put, + Method::DELETE => msg::HttpMethod::Delete, + Method::HEAD => msg::HttpMethod::Head, + Method::OPTIONS => msg::HttpMethod::Options, + Method::CONNECT => msg::HttpMethod::Connect, + Method::PATCH => msg::HttpMethod::Patch, + Method::TRACE => msg::HttpMethod::Trace, + _ => unimplemented!(), + }; + + let headers: Vec<_> = req + .headers + .iter() + .map(|(key, value)| { + let key = builder.create_string(key.as_str()); + let value = builder.create_string(value.to_str().unwrap()); + msg::HttpHeader::create( + builder, + &msg::HttpHeaderArgs { + key: Some(key), + value: Some(value), + ..Default::default() + }, + ) + }) + .collect(); + + let req_headers = builder.create_vector(&headers); + let req_remote_addr = + builder.create_string(req.remote_addr.ip().to_string().as_str()); + + let req_msg = msg::HttpRequest::create( + builder, + &msg::HttpRequestArgs { + id: req.id, + method: req_method, + url: Some(req_url), + headers: Some(req_headers), + remote_addr: Some(req_remote_addr), + has_body: req.body.is_some(), + ..Default::default() + }, + ); + + let to_send = fly_buf_from( + serialize_response( + 0, + builder, + msg::BaseArgs { + msg: Some(req_msg.as_union_value()), + msg_type: msg::Any::HttpRequest, + ..Default::default() + }, + ) + .unwrap(), + ); + + ptr.send(to_send, None); + + if let Some(stream) = req.body { + send_body_stream(ptr, req.id, stream); + } + + Ok(()) + }) + .and_then(|_| Ok(debug!("done listening to http events."))), + ); + rt.fetch_events = Some(tx); + } + msg::EventType::Resolv => { + let (tx, rx) = mpsc::unbounded::(); + rt.spawn( + rx.map_err(|_| error!("error event receiving http request")) + .for_each(move |req| { + debug!("Listener received new resolve event."); + let builder = &mut FlatBufferBuilder::new(); + + let queries: Vec<_> = req + .queries + .iter() + .map(|q| { + debug!("query: {:?}", q); + use self::dns::rr::{DNSClass, Name, RecordType}; + let name = + builder.create_string(&Name::from(q.name().clone()).to_utf8()); + let rr_type = match q.query_type() { + RecordType::A => msg::DnsRecordType::A, + RecordType::AAAA => msg::DnsRecordType::AAAA, + RecordType::AXFR => msg::DnsRecordType::AXFR, + RecordType::CAA => msg::DnsRecordType::CAA, + RecordType::CNAME => msg::DnsRecordType::CNAME, + RecordType::IXFR => msg::DnsRecordType::IXFR, + RecordType::MX => msg::DnsRecordType::MX, + RecordType::NS => msg::DnsRecordType::NS, + RecordType::NULL => msg::DnsRecordType::NULL, + RecordType::OPT => msg::DnsRecordType::OPT, + RecordType::PTR => msg::DnsRecordType::PTR, + RecordType::SOA => msg::DnsRecordType::SOA, + RecordType::SRV => msg::DnsRecordType::SRV, + RecordType::TLSA => msg::DnsRecordType::TLSA, + RecordType::TXT => msg::DnsRecordType::TXT, + _ => unimplemented!(), + }; + let dns_class = match q.query_class() { + DNSClass::IN => msg::DnsClass::IN, + DNSClass::CH => msg::DnsClass::CH, + DNSClass::HS => msg::DnsClass::HS, + DNSClass::NONE => msg::DnsClass::NONE, + DNSClass::ANY => msg::DnsClass::ANY, + _ => unimplemented!(), + }; + + msg::DnsQuery::create( + builder, + &msg::DnsQueryArgs { + name: Some(name), + rr_type: rr_type, + dns_class: dns_class, + ..Default::default() + }, + ) + }) + .collect(); + + let req_queries = builder.create_vector(&queries); + + let req_msg = msg::DnsRequest::create( + builder, + &msg::DnsRequestArgs { + id: req.id, + message_type: match req.message_type { + dns::op::MessageType::Query => msg::DnsMessageType::Query, + _ => unimplemented!(), + }, + queries: Some(req_queries), + ..Default::default() + }, + ); + + let to_send = fly_buf_from( + serialize_response( + 0, + builder, + msg::BaseArgs { + msg: Some(req_msg.as_union_value()), + msg_type: msg::Any::DnsRequest, + ..Default::default() + }, + ) + .unwrap(), + ); + + ptr.send(to_send, None); + Ok(()) + }), + ); + rt.resolv_events = Some(tx); + }, + msg::EventType::Serve => { + debug!("Register service event listener."); + let (tx, rx) = mpsc::unbounded::(); + rt.spawn( + rx.map_err(|_| error!("error event receiving service request")) + .for_each(move |req| { + debug!("Listener received new service event."); + let builder = &mut FlatBufferBuilder::new(); + + let req_sender = builder.create_string(req.sender.as_str()); + + let req_data = builder.create_string(req.data.as_str()); + + let req_msg = msg::ServiceRequest::create( + builder, + &msg::ServiceRequestArgs { + id: req.id, + sender: Some(req_sender), + data: Some(req_data), + } + ); + + let to_send = fly_buf_from( + serialize_response( + 0, + builder, + msg::BaseArgs { + msg: Some(req_msg.as_union_value()), + msg_type: msg::Any::ServiceRequest, + ..Default::default() + }, + ) + .unwrap(), + ); + + ptr.send(to_send, None); + + Ok(()) + }) + .and_then(|_| Ok(info!("done listening to service events."))), + ); + rt.serve_events = Some(tx); + debug!("Finished registering service event listener."); + }, + }; + + ok_future(None) +} diff --git a/src/ops/fetch.rs b/src/ops/fetch.rs index 84bea74..cbe102e 100644 --- a/src/ops/fetch.rs +++ b/src/ops/fetch.rs @@ -6,7 +6,8 @@ use futures::{ use crate::msg; use flatbuffers::FlatBufferBuilder; -use crate::runtime::{JsBody, JsHttpResponse, JsRuntime, Op, EVENT_LOOP}; +use crate::js::*; +use crate::runtime::{Runtime, EVENT_LOOP}; use crate::utils::*; use libfly::*; @@ -14,17 +15,14 @@ use crate::errors::{FlyError, FlyResult}; use crate::get_next_stream_id; -extern crate hyper; +use hyper::body::Payload; +use hyper::client::HttpConnector; +use hyper::header::HeaderName; +use hyper::rt::{Future, Stream}; +use hyper::HeaderMap; +use hyper::{Body, Client, Method, Request, StatusCode}; -use self::hyper::body::Payload; -use self::hyper::client::HttpConnector; -use self::hyper::header::HeaderName; -use self::hyper::rt::{Future, Stream}; -use self::hyper::HeaderMap; -use self::hyper::{Body, Client, Method, Request, StatusCode}; - -extern crate hyper_tls; -use self::hyper_tls::HttpsConnector; +use hyper_tls::HttpsConnector; use std::io; @@ -43,15 +41,17 @@ lazy_static! { }; } -pub fn op_fetch(ptr: JsRuntime, base: &msg::Base, raw: fly_buf) -> Box { +pub fn op_fetch(rt: &mut Runtime, base: &msg::Base, raw: fly_buf) -> Box { let cmd_id = base.cmd_id(); let msg = base.msg_as_http_request().unwrap(); let url = msg.url().unwrap(); if url.starts_with("file://") { - return file_request(ptr, cmd_id, url); + return file_request(rt, cmd_id, url); } + let ptr = rt.ptr; + let req_id = msg.id(); let http_uri: hyper::Uri = match url.parse() { @@ -76,7 +76,6 @@ pub fn op_fetch(ptr: JsRuntime, base: &msg::Base, raw: fly_buf) -> Box { format!("{}:{}", host_str, port) }; - let rt = ptr.to_runtime(); FETCH_HTTP_REQUESTS_TOTAL .with_label_values(&[rt.name.as_str(), rt.version.as_str(), host.as_str()]) .inc(); @@ -105,13 +104,13 @@ pub fn op_fetch(ptr: JsRuntime, base: &msg::Base, raw: fly_buf) -> Box { } let has_body = msg.has_body(); - println!("HAS BODY? {}", has_body); + trace!("HAS BODY? {}", has_body); let req_body = if has_body { if raw.data_len > 0 { - println!("STATIC BODY!"); + trace!("STATIC BODY!"); Body::from(unsafe { slice::from_raw_parts(raw.data_ptr, raw.data_len) }.to_vec()) } else { - println!("STREAMING BODY"); + trace!("STREAMING BODY"); let (sender, recver) = mpsc::unbounded::>(); { rt.streams.lock().unwrap().insert(req_id, sender); @@ -251,7 +250,7 @@ pub fn op_fetch(ptr: JsRuntime, base: &msg::Base, raw: fly_buf) -> Box { Box::new(fut) } -pub fn op_http_response(ptr: JsRuntime, base: &msg::Base, raw: fly_buf) -> Box { +pub fn op_http_response(rt: &mut Runtime, base: &msg::Base, raw: fly_buf) -> Box { debug!("handling http response"); let msg = base.msg_as_http_response().unwrap(); let req_id = msg.id(); @@ -273,8 +272,6 @@ pub fn op_http_response(ptr: JsRuntime, base: &msg::Base, raw: fly_buf) -> Box = None; let has_body = msg.has_body(); if has_body { @@ -287,6 +284,7 @@ pub fn op_http_response(ptr: JsRuntime, base: &msg::Base, raw: fly_buf) -> Box Box Box { +fn file_request(rt: &mut Runtime, cmd_id: u32, url: &str) -> Box { let req_id = get_next_stream_id(); let path: String = url.chars().skip(7).collect(); - let rt = ptr.to_runtime(); + let ptr = rt.ptr; Box::new( rt.fs_store diff --git a/src/ops/image.fbs b/src/ops/image.fbs index ec4b90c..2f2bd6e 100644 --- a/src/ops/image.fbs +++ b/src/ops/image.fbs @@ -1,5 +1,6 @@ enum ImageTransformType: byte { - ImageWebPEncode = 0, + WebPEncode = 0, + Resize, } table ImageWebPEncode { @@ -9,8 +10,23 @@ table ImageWebPEncode { near_lossless: bool; } +enum ImageSamplingFilter: byte { + Nearest = 0, + Triangle, + CatmullRom, + Gaussian, + Lanczos3, +} + +table ImageResize { + width: uint; + height: uint; + filter: ImageSamplingFilter; +} + union ImageTransformOptions { ImageWebPEncode, + ImageResize, } table ImageTransform { diff --git a/src/ops/image.rs b/src/ops/image.rs index 710fa7e..4761646 100644 --- a/src/ops/image.rs +++ b/src/ops/image.rs @@ -6,13 +6,15 @@ use libc::{c_float, c_int, c_void}; use crate::msg; use flatbuffers::FlatBufferBuilder; -use crate::runtime::{JsBody, JsRuntime, Op}; +use crate::js::*; +use crate::runtime::Runtime; use crate::utils::*; use libfly::*; use crate::get_next_stream_id; use futures::{sync::mpsc, Future, Stream}; +use std::{fmt, fmt::Display}; #[derive(Debug)] struct WebPEncodeOptions { @@ -22,11 +24,31 @@ struct WebPEncodeOptions { pub alpha_quality: f32, } +struct ResizeOptions { + pub width: u32, + pub height: u32, + pub filter: image::FilterType, +} + enum ImageTransform { WebPEncode(WebPEncodeOptions), + Resize(ResizeOptions), } -pub fn op_image_transform(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { +impl Display for ImageTransform { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}", + match self { + ImageTransform::Resize(_) => "Resize", + ImageTransform::WebPEncode(_) => "WebP", + } + ) + } +} + +pub fn op_image_transform(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { let cmd_id = base.cmd_id(); let msg = base.msg_as_image_apply_transforms().unwrap(); let transforms: Vec = match msg.transforms() { @@ -42,7 +64,7 @@ pub fn op_image_transform(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Bo .map(|i| { let item = t.get(i); match item.transform() { - msg::ImageTransformType::ImageWebPEncode => { + msg::ImageTransformType::WebPEncode => { let opts = item.options_as_image_web_pencode().unwrap(); ImageTransform::WebPEncode(WebPEncodeOptions { lossless: opts.lossless(), @@ -51,6 +73,28 @@ pub fn op_image_transform(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Bo quality: opts.quality(), }) } + msg::ImageTransformType::Resize => { + let opts = item.options_as_image_resize().unwrap(); + ImageTransform::Resize(ResizeOptions { + width: opts.width(), + height: opts.height(), + filter: match opts.filter() { + msg::ImageSamplingFilter::Nearest => image::FilterType::Nearest, + msg::ImageSamplingFilter::Triangle => { + image::FilterType::Triangle + } + msg::ImageSamplingFilter::CatmullRom => { + image::FilterType::CatmullRom + } + msg::ImageSamplingFilter::Gaussian => { + image::FilterType::Gaussian + } + msg::ImageSamplingFilter::Lanczos3 => { + image::FilterType::Lanczos3 + } + }, + }) + } } }) .collect() @@ -60,13 +104,13 @@ pub fn op_image_transform(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Bo let in_id = get_next_stream_id(); let out_id = get_next_stream_id(); - let rt = ptr.to_runtime(); - let (sender, recver) = mpsc::unbounded::>(); { rt.streams.lock().unwrap().insert(in_id, sender); } + let ptr = rt.ptr; + rt.spawn( recver .map_err(|e| error!("error cache set stream! {:?}", e)) @@ -74,15 +118,32 @@ pub fn op_image_transform(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Bo .and_then( move |chunks: Vec| match image::load_from_memory(chunks.as_slice()) { Err(e) => Err(error!("error loading image from memory: {}", e)), - Ok(img) => { - for t in transforms { + Ok(mut img) => { + let mut encode: Option<&ImageTransform> = None; + for t in transforms.iter() { + debug!("Applying image transform: {}", t); match t { + ImageTransform::Resize(opts) => { + img = img.resize(opts.width, opts.height, opts.filter); + } + ImageTransform::WebPEncode(_) => { + encode = Some(t); + } + }; + } + + if let Some(enc) = encode { + match enc { ImageTransform::WebPEncode(opts) => { let v = encode_webp(&img, opts).unwrap(); send_body_stream(ptr, out_id, JsBody::Static(v)); + return Ok(()); } - }; + _ => {} + } } + + send_body_stream(ptr, out_id, JsBody::Static(img.raw_pixels())); Ok(()) } }, @@ -102,11 +163,13 @@ pub fn op_image_transform(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Bo )) } -fn encode_webp(img: &image::DynamicImage, opts: WebPEncodeOptions) -> Result, String> { +fn encode_webp(img: &image::DynamicImage, opts: &WebPEncodeOptions) -> Result, String> { let width = img.width(); let height = img.height(); let stride = width * 3; + debug!("WEBP WIDTH: {}, HEIGHT: {}", width, height); + let lossless = opts.lossless; // Set to true for lossless (Warning: CPU intensive/slow) let _near_lossless = opts.near_lossless; let _alpha_quality = opts.alpha_quality; diff --git a/src/ops/mod.rs b/src/ops/mod.rs index b30e812..6c885cc 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -1,5 +1,14 @@ pub mod acme; pub mod cache; +pub mod crypto; +pub mod data; pub mod dns; +pub mod events; pub mod fetch; pub mod image; +pub mod modules; +pub mod os; +pub mod service; +pub mod source_map; +pub mod streams; +pub mod timers; diff --git a/src/ops/modules.rs b/src/ops/modules.rs new file mode 100644 index 0000000..af73c1f --- /dev/null +++ b/src/ops/modules.rs @@ -0,0 +1,58 @@ +use crate::msg; +use flatbuffers::FlatBufferBuilder; + +use crate::runtime::Runtime; +use libfly::*; + +use crate::utils::*; + +use crate::module_resolver::RefererInfo; + +use futures::future; + +pub fn op_load_module(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let cmd_id = base.cmd_id(); + let msg = base.msg_as_load_module().unwrap(); + let specifier_url = msg.specifier_url().unwrap().to_string(); + + let referer_info = match msg.referer_origin_url() { + Some(v) => Some(RefererInfo { + origin_url: v.to_string(), + is_wasm: Some(false), + source_code: None, + indentifier_hash: None, + }), + None => None, + }; + + let module = match rt + .module_resolver_manager + .resolve_module(specifier_url, referer_info) + { + Ok(m) => m, + Err(e) => return odd_future(e.into()), + }; + + Box::new(future::lazy(move || { + let builder = &mut FlatBufferBuilder::new(); + let origin_url = builder.create_string(&module.origin_url); + let source_code = builder.create_string(&module.loaded_source.source); + + let msg = msg::LoadModuleResp::create( + builder, + &msg::LoadModuleRespArgs { + origin_url: Some(origin_url), + source_code: Some(source_code), + }, + ); + Ok(serialize_response( + cmd_id, + builder, + msg::BaseArgs { + msg: Some(msg.as_union_value()), + msg_type: msg::Any::LoadModuleResp, + ..Default::default() + }, + )) + })) +} diff --git a/src/ops/os.fbs b/src/ops/os.fbs new file mode 100644 index 0000000..d07af1e --- /dev/null +++ b/src/ops/os.fbs @@ -0,0 +1,3 @@ +table OsExit { + code: int; +} diff --git a/src/ops/os.rs b/src/ops/os.rs new file mode 100644 index 0000000..52dbace --- /dev/null +++ b/src/ops/os.rs @@ -0,0 +1,14 @@ +use crate::msg; +use crate::runtime::Runtime; +use crate::utils::*; +use libfly::*; + +pub fn op_exit(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + if let Err(e) = rt.permissions.check_os() { + return odd_future(e); + } + + let msg = base.msg_as_os_exit().unwrap(); + + std::process::exit(msg.code()) +} diff --git a/src/ops/service.rs b/src/ops/service.rs new file mode 100644 index 0000000..e4e8aef --- /dev/null +++ b/src/ops/service.rs @@ -0,0 +1,90 @@ + +use crate::utils::{ok_future, odd_future}; +use crate::runtime::{Runtime}; +use crate::msg; +use flatbuffers::FlatBufferBuilder; +use crate::utils::Op; +use libfly::*; +use crate::js::*; +use crate::utils::*; +use futures::future::Future; +use crate::errors::{ FlyError }; + +pub fn op_request_service_request(rt: &mut Runtime, base: &msg::Base, raw: fly_buf) -> Box { + let cmd_id = base.cmd_id(); + let msg = base.msg_as_request_service_request().unwrap(); + + let destination_name = msg.destination_name().unwrap().to_string(); + let data = msg.data().unwrap().to_string(); + + match &rt.manager_callbacks { + Some(v) => { + match (v.uuid_by_servicename)(destination_name) { + Ok(Some(destination_uuid)) => { + match (v.send_message)(destination_uuid, data) { + Ok(rx) => { + debug!("Channel received responding with future."); + Box::new(rx.then(move |f| { + match f { + Ok(resp) => { + let builder = &mut FlatBufferBuilder::new(); + let data_string = match resp.data { + Some(v) => Some(builder.create_string(&v)), + None => None, + }; + + let msg = msg::RequestServiceResponse::create( + builder, + &msg::RequestServiceResponseArgs { + success: resp.success, + data: data_string, + }, + ); + Ok(serialize_response( + cmd_id, + builder, + msg::BaseArgs { + msg: Some(msg.as_union_value()), + msg_type: msg::Any::RequestServiceResponse, + ..Default::default() + }, + )) + }, + Err(e) => Err(FlyError::from(format!("Failed to get response: {}", e))), + } + })) + } + Err(e) => odd_future(format!("Failed to make request: {}", e).into()), + } + } + Ok(None) => odd_future("Runtime not found bound to servicename!".to_string().into()), + Err(_) => odd_future("An error occured while looking for servicename binding!".to_string().into()), + } + }, + None => odd_future("Manager callbacks missing!".to_string().into()) + } +} + +pub fn op_service_response(rt: &mut Runtime, base: &msg::Base, raw: fly_buf) -> Box { + debug!("handle service"); + let msg = base.msg_as_service_response().unwrap(); + let req_id = msg.id(); + + let mut responses = rt.service_responses.lock().unwrap(); + match responses.remove(&req_id) { + Some(sender) => { + if let Err(_) = sender.send(JsServiceResponse { + success: msg.success(), + data: match msg.data() { + Some(v) => Some(v.to_string()), + None => None, + }, + }) { + return odd_future("error sending service response".to_string().into()); + } + }, + None => return odd_future("no service response receiver!".to_string().into()), + }; + + ok_future(None) +} \ No newline at end of file diff --git a/src/ops/source_map.rs b/src/ops/source_map.rs new file mode 100644 index 0000000..d182f46 --- /dev/null +++ b/src/ops/source_map.rs @@ -0,0 +1,134 @@ +use crate::msg; +use flatbuffers::FlatBufferBuilder; + +use crate::runtime::Runtime; +use crate::v8env::V8ENV_SOURCEMAP; +use libfly::*; + +use crate::utils::*; + +use sourcemap::SourceMap; +use std::sync::{mpsc, Mutex}; + +use futures::{sync::oneshot, Future}; +use std::thread; + +type SourceMapId = (u32, u32, String, String); + +lazy_static! { + static ref SM_CHAN: Mutex, oneshot::Sender>)>> = { + let (sender, receiver) = + mpsc::channel::<(Vec, oneshot::Sender>)>(); + thread::Builder::new() + .name("sourcemapper".to_string()) + .spawn(move || { + let sm = SourceMap::from_reader(*V8ENV_SOURCEMAP).unwrap(); + for tup in receiver.iter() { + let ch = tup.1; + let v = tup.0; + ch.send( + v.iter() + .map(|(line, col, name, filename)| { + if filename == "v8env/dist/v8env.js" { + return match sm.lookup_token(*line, *col) { + Some(t) => { + let newline = t.get_src_line(); + let newcol = t.get_src_col(); + let newfilename = match t.get_source() { + Some(s) => String::from(s), + None => filename.clone(), + }; + (newline, newcol, name.clone(), newfilename) + } + None => (*line, *col, name.clone(), filename.clone()), + }; + } + (*line, *col, name.clone(), filename.clone()) + }) + .collect(), + ) + .unwrap(); + } + }) + .unwrap(); + Mutex::new(sender) + }; +} + +pub fn op_source_map(_rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let cmd_id = base.cmd_id(); + let msg = base.msg_as_source_map().unwrap(); + + let msg_frames = msg.frames().unwrap(); + let mut frames = Vec::with_capacity(msg_frames.len()); + + for i in 0..msg_frames.len() { + let f = msg_frames.get(i); + + debug!( + "got frame: {:?} {:?} {:?} {:?}", + f.name(), + f.filename(), + f.line(), + f.col() + ); + + let name = match f.name() { + Some(n) => n, + None => "", + }; + + let filename = match f.filename() { + Some(f) => f, + None => "", + }; + + let line = f.line(); + let col = f.col(); + + frames.insert(i, (line, col, String::from(name), String::from(filename))); + } + + let (tx, rx) = oneshot::channel::>(); + if let Err(err) = SM_CHAN.lock().unwrap().send((frames, tx)) { + return odd_future(format!("{}", err).into()); + } + + Box::new(rx.map_err(|e| format!("{}", e).into()).and_then(move |v| { + let builder = &mut FlatBufferBuilder::new(); + let framed: Vec<_> = v + .iter() + .map(|(line, col, name, filename)| { + let namefbb = builder.create_string(name.as_str()); + let filenamefbb = builder.create_string(filename.as_str()); + msg::Frame::create( + builder, + &msg::FrameArgs { + name: Some(namefbb), + filename: Some(filenamefbb), + line: *line, + col: *col, + }, + ) + }) + .collect(); + let ret_frames = builder.create_vector(&framed); + + let ret_msg = msg::SourceMapReady::create( + builder, + &msg::SourceMapReadyArgs { + frames: Some(ret_frames), + ..Default::default() + }, + ); + Ok(serialize_response( + cmd_id, + builder, + msg::BaseArgs { + msg: Some(ret_msg.as_union_value()), + msg_type: msg::Any::SourceMapReady, + ..Default::default() + }, + )) + })) +} diff --git a/src/ops/streams.rs b/src/ops/streams.rs new file mode 100644 index 0000000..54928ee --- /dev/null +++ b/src/ops/streams.rs @@ -0,0 +1,33 @@ +use crate::msg; + +use crate::runtime::Runtime; +use libfly::*; + +use crate::utils::*; + +use std::slice; + +pub fn op_stream_chunk(rt: &mut Runtime, base: &msg::Base, raw: fly_buf) -> Box { + debug!("handle stream chunk {:?}", raw); + let msg = base.msg_as_stream_chunk().unwrap(); + let stream_id = msg.id(); + + let mut streams = rt.streams.lock().unwrap(); + if raw.data_len > 0 { + match streams.get_mut(&stream_id) { + Some(sender) => { + let bytes = unsafe { slice::from_raw_parts(raw.data_ptr, raw.data_len) }.to_vec(); + match sender.unbounded_send(bytes.to_vec()) { + Err(e) => error!("error sending chunk: {}", e), + _ => debug!("chunk streamed"), + } + } + None => unimplemented!(), + }; + } + if msg.done() { + streams.remove(&stream_id); + } + + ok_future(None) +} diff --git a/src/ops/timers.rs b/src/ops/timers.rs new file mode 100644 index 0000000..9f70a41 --- /dev/null +++ b/src/ops/timers.rs @@ -0,0 +1,88 @@ +use crate::msg; +use flatbuffers::FlatBufferBuilder; + +use crate::runtime::{JsRuntime, Runtime}; +use libfly::*; + +use crate::utils::*; + +use futures::{sync::oneshot, Future}; +use std::time::{Duration, Instant}; + +use tokio::timer::Delay; + +pub fn op_timer_start(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + debug!("op_timer_start"); + let msg = base.msg_as_timer_start().unwrap(); + let cmd_id = base.cmd_id(); + let timer_id = msg.id(); + let delay = msg.delay(); + + let timers = &rt.timers; + + let ptr = rt.ptr; + + let fut = { + let (delay_task, cancel_delay) = set_timeout( + move || { + remove_timer(ptr, timer_id); + }, + delay, + ); + + timers.lock().unwrap().insert(timer_id, cancel_delay); + delay_task + }; + // } + Box::new(fut.then(move |result| { + let builder = &mut FlatBufferBuilder::new(); + let msg = msg::TimerReady::create( + builder, + &msg::TimerReadyArgs { + id: timer_id, + canceled: result.is_err(), + ..Default::default() + }, + ); + Ok(serialize_response( + cmd_id, + builder, + msg::BaseArgs { + msg: Some(msg.as_union_value()), + msg_type: msg::Any::TimerReady, + ..Default::default() + }, + )) + })) +} + +fn remove_timer(ptr: JsRuntime, timer_id: u32) { + let rt = ptr.to_runtime(); + rt.timers.lock().unwrap().remove(&timer_id); +} + +pub fn op_timer_clear(rt: &mut Runtime, base: &msg::Base, _raw: fly_buf) -> Box { + let msg = base.msg_as_timer_clear().unwrap(); + debug!("op_timer_clear"); + remove_timer(rt.ptr, msg.id()); + ok_future(None) +} + +fn set_timeout(cb: F, delay: u32) -> (impl Future, oneshot::Sender<()>) +where + F: FnOnce() -> (), +{ + let (cancel_tx, cancel_rx) = oneshot::channel::<()>(); + let when = Instant::now() + Duration::from_millis(delay.into()); + let delay_task = Delay::new(when) + .map_err(|e| panic!("timer failed; err={:?}", e)) + .and_then(|_| { + cb(); + Ok(()) + }) + .select(cancel_rx) + .map(|_| ()) + .map_err(|_| ()); + + (delay_task, cancel_tx) +} diff --git a/src/postgres_data.rs b/src/postgres_data.rs index 9c210f2..29c762e 100644 --- a/src/postgres_data.rs +++ b/src/postgres_data.rs @@ -10,7 +10,10 @@ use postgres_openssl::openssl::ssl::SslMethod; use crate::settings::PostgresStoreConfig; +use serde_json; + use std::collections::HashMap; + use std::sync::Mutex; use futures::{future, Future}; @@ -219,6 +222,37 @@ impl DataStore for PostgresDataStore { })) } + fn incr( + &self, + coll: String, + key: String, + field: String, + amount: i32, + ) -> Box + Send> { + debug!( + "postgres data store incr coll: {}, key: {}, field: {}, amount: {}", + coll, key, field, amount + ); + let pool = self.get_pool(); + Box::new(future::lazy(move || -> DataResult<()> { + let con = pool.get().unwrap(); // TODO: no unwrap + + ensure_coll(&*con, &coll).unwrap(); + + match con.execute( + format!( + "UPDATE {} SET obj = jsonb_set(obj, '{{{}}}', (COALESCE(obj->>'{}', '0')::int + $1)::text::jsonb) WHERE key = $2", + coll, field, field + ) + .as_str(), + &[&amount, &key], + ) { + Ok(_) => Ok(()), + Err(e) => Err(e.into()), + } + })) + } + fn drop_coll(&self, coll: String) -> Box + Send> { debug!("postgres data store drop coll: {}", coll); let pool = self.get_pool(); @@ -338,4 +372,41 @@ mod tests { ); } + #[test] + fn test_pg_incr() { + let dbname = "testflyincr"; + let coll = "coll1"; + let key = "test:key"; + let value = r#"{"counter":0,"foo":"bar"}"#; + + let store = setup(Some(dbname.to_string())); + set_value(&store, coll, key, value); + + store + .incr(coll.to_string(), key.to_string(), "counter".to_string(), 1) + .wait() + .unwrap(); + let got = store + .get(coll.to_string(), key.to_string()) + .wait() + .unwrap() + .unwrap(); + + assert_eq!(got, "{\"foo\": \"bar\", \"counter\": 1}"); + + store + .incr(coll.to_string(), key.to_string(), "counter".to_string(), 15) + .wait() + .unwrap(); + let got = store + .get(coll.to_string(), key.to_string()) + .wait() + .unwrap() + .unwrap(); + + assert_eq!(got, "{\"foo\": \"bar\", \"counter\": 16}"); + + teardown(&dbname); + } + } diff --git a/src/redis_pool.rs b/src/redis_pool.rs index 0f4d2b9..334aed9 100644 --- a/src/redis_pool.rs +++ b/src/redis_pool.rs @@ -16,9 +16,10 @@ pub fn get_pool(url: String) -> r2d2::Pool { .entry(url.clone()) .or_insert_with(move || { r2d2::Pool::builder() - .max_size(50) + .max_size(100) + .min_idle(Some(0)) .build(RedisConnectionManager::new(url.as_str()).unwrap()) - .unwrap() + .unwrap() // should not fail because min_idle set to 0 }) .clone() // that's like Arc::clone, no worries. } diff --git a/src/runtime.rs b/src/runtime.rs index ec919d4..e9dbacc 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,6 +1,3 @@ -extern crate http; -extern crate libc; - use tokio; use tokio::runtime::current_thread; @@ -14,57 +11,34 @@ use std::io::Read; use libfly::*; -use std::sync::mpsc as stdmspc; - -use futures::sync::{mpsc, oneshot}; +use futures::{ + sync::{mpsc, oneshot}, + Future, +}; use std::collections::HashMap; use std::thread; -use tokio::timer::Delay; - -use std::time::{Duration, Instant}; +use std::sync::{Arc, RwLock}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; -use futures::future; - use std::ptr; +use std::slice; -extern crate sha1; // SHA-1 -extern crate sha2; // SHA-256, etc. -#[allow(unused_imports)] -use self::sha1::Digest as Sha1Digest; // puts trait in scope -use self::sha1::Sha1; - -#[allow(unused_imports)] -use self::sha2::Digest; // puts trait in scope -use self::sha2::Sha256; - -extern crate hyper; - -use self::hyper::rt::{Future, Stream}; -use self::hyper::HeaderMap; -use self::hyper::{Body, Method, StatusCode}; +use crate::js::*; use crate::msg; use flatbuffers::FlatBufferBuilder; -use crate::errors::FlyError; +use crate::errors::{ FlyResult, FlyError }; -extern crate log; - -extern crate rand; -use self::rand::{thread_rng, Rng}; - -extern crate bytes; -use self::bytes::BytesMut; +use slog::{slog_debug, slog_error, slog_info, slog_o, slog_trace, slog_warn, Logger}; use crate::acme_store; use crate::cache_store; use crate::data_store; use crate::fs_store; -use crate::ops; use crate::utils::*; use crate::postgres_data; @@ -75,40 +49,26 @@ use crate::sqlite_data; use crate::{disk_fs, redis_fs}; +use crate::v8env::{DEV_TOOLS_SOURCE, FLY_SNAPSHOT}; + +use crate::runtime_permissions::RuntimePermissions; use crate::settings::{ AcmeStoreConfig, CacheStore, CacheStoreNotifier, DataStore, FsStore, Settings, }; +use crate::module_resolver::{ + LoadedModule, LocalDiskModuleResolver, ModuleResolver, ModuleResolverManager, RefererInfo, + StandardModuleResolverManager, +}; + +use crate::runtime_manager::{RuntimeManagerCallbacks}; + use super::NEXT_FUTURE_ID; -use std::net::SocketAddr; use std::str; use std::time; -extern crate trust_dns as dns; - -pub enum JsBody { - BoxedStream(Box, Error = FlyError> + Send>), - Stream(mpsc::UnboundedReceiver>), - BytesStream(mpsc::UnboundedReceiver), - HyperBody(Body), - Static(Vec), -} - -pub struct JsHttpResponse { - pub headers: HeaderMap, - pub status: StatusCode, - pub body: Option, -} - -pub struct JsHttpRequest { - pub id: u32, - pub method: http::Method, - pub remote_addr: SocketAddr, - pub url: String, - pub headers: HeaderMap, - pub body: Option, -} +use crate::msg_handler::{DefaultMessageHandler, MessageHandler}; #[derive(Debug, Copy, Clone)] pub struct JsRuntime(pub *const js_runtime); @@ -143,18 +103,27 @@ pub struct Runtime { pub ptr: JsRuntime, pub name: String, pub version: String, + pub app_logger: Logger, pub event_loop: Mutex, - timers: Mutex>>, + pub timers: Mutex>>, pub responses: Mutex>>, - pub dns_responses: Mutex>>, + pub dns_responses: Mutex>>, + pub service_responses: Mutex>>, pub streams: Mutex>>>, pub cache_store: Box, pub data_store: Box, pub fs_store: Box, pub acme_store: Option>, pub fetch_events: Option>, - pub resolv_events: Option>, + pub resolv_events: Option>, + pub serve_events: Option>, pub last_event_at: AtomicUsize, + pub module_resolver_manager: Box, + pub msg_handler: Box, + pub permissions: RuntimePermissions, + metadata_cache: RwLock>>, + pub manager_callbacks: Option, + uuid: String, ready_ch: Option>, quit_ch: Option>, } @@ -186,16 +155,16 @@ fn init_event_loop( el.spawn( rxready .map_err(|_| error!("error recving ready signal for runtime")) - .and_then(|_| Ok(warn!("ready ch received!"))), + .and_then(|_| Ok(trace!("ready ch received!"))), ); match el.run() { - Ok(_) => warn!("runtime event loop ran fine"), + Ok(_) => trace!("runtime event loop ran fine"), Err(e) => error!("error running runtime event loop: {}", e), }; - warn!("Event loop has run its course."); + trace!("Event loop has run its course."); match txquit.send(()) { - Ok(_) => warn!("Sent quit () in channel successfully."), + Ok(_) => trace!("Sent quit () in channel successfully."), Err(_) => error!("error sending quit signal for runtime"), }; }) @@ -203,36 +172,57 @@ fn init_event_loop( p.wait().unwrap() } +pub struct RuntimeConfig<'a> { + pub name: Option, + pub version: Option, + pub settings: &'a Settings, + pub module_resolvers: Option>>, + pub app_logger: &'a Logger, + pub msg_handler: Option>, + pub permissions: Option, + pub dev_tools: bool, +} + impl Runtime { - pub fn new(name: Option, version: Option, settings: &Settings) -> Box { + pub fn new(config: RuntimeConfig) -> Box { JSINIT.call_once(|| unsafe { js_init() }); - let rt_name = name.unwrap_or("v8".to_string()); - let rt_version = version.unwrap_or("0".to_string()); + let rt_name = config.name.unwrap_or("v8".to_string()); + let rt_version = config.version.unwrap_or("0".to_string()); + let app_logger = config + .app_logger + .new(slog_o!("app_name" => rt_name.to_owned(), "app_version" => rt_version.to_owned())); let (rthandle, txready, rxquit) = init_event_loop(format!("{}-{}", rt_name, rt_version)); + let rt_module_resolvers = + config.module_resolvers.unwrap_or(vec![ + Box::new(LocalDiskModuleResolver::new(None)) as Box + ]); let mut rt = Box::new(Runtime { ptr: JsRuntime(ptr::null() as *const js_runtime), name: rt_name, version: rt_version, + app_logger: app_logger, event_loop: Mutex::new(rthandle.clone()), ready_ch: Some(txready), quit_ch: Some(rxquit), timers: Mutex::new(HashMap::new()), responses: Mutex::new(HashMap::new()), dns_responses: Mutex::new(HashMap::new()), + service_responses: Mutex::new(HashMap::new()), streams: Mutex::new(HashMap::new()), // stream_recv: Mutex::new(HashMap::new()), fetch_events: None, resolv_events: None, - cache_store: match settings.cache_store { + serve_events: None, + cache_store: match config.settings.cache_store { Some(ref store) => match store { CacheStore::Sqlite(conf) => { Box::new(sqlite_cache::SqliteCacheStore::new(conf.filename.clone())) } CacheStore::Redis(conf) => Box::new(redis_cache::RedisCacheStore::new( &conf, - match settings.cache_store_notifier { + match config.settings.cache_store_notifier { None => None, Some(CacheStoreNotifier::Redis(ref csnconf)) => Some(csnconf.clone()), }, @@ -240,7 +230,7 @@ impl Runtime { }, None => Box::new(sqlite_cache::SqliteCacheStore::new("cache.db".to_string())), }, - data_store: match settings.data_store { + data_store: match config.settings.data_store { Some(ref store) => match store { DataStore::Sqlite(conf) => { Box::new(sqlite_data::SqliteDataStore::new(conf.filename.clone())) @@ -249,14 +239,14 @@ impl Runtime { }, None => Box::new(sqlite_data::SqliteDataStore::new("data.db".to_string())), }, - fs_store: match settings.fs_store { + fs_store: match config.settings.fs_store { Some(ref store) => match store { FsStore::Redis(conf) => Box::new(redis_fs::RedisFsStore::new(&conf)), FsStore::Disk => Box::new(disk_fs::DiskFsStore::new()), }, None => Box::new(disk_fs::DiskFsStore::new()), }, - acme_store: match settings.acme_store { + acme_store: match config.settings.acme_store { Some(ref config) => match config { AcmeStoreConfig::Redis(config) => { Some(Box::new(redis_acme::RedisAcmeStore::new(&config))) @@ -265,6 +255,17 @@ impl Runtime { None => None, }, last_event_at: ATOMIC_USIZE_INIT, + module_resolver_manager: Box::new(StandardModuleResolverManager::new( + rt_module_resolvers, + None, + )), + manager_callbacks: None, + uuid: uuid::Uuid::new_v4().to_simple().to_string(), + metadata_cache: RwLock::new(HashMap::new()), + msg_handler: config + .msg_handler + .unwrap_or(Box::new(DefaultMessageHandler {})), + permissions: config.permissions.unwrap_or_default(), }); (*rt).ptr.0 = unsafe { @@ -273,6 +274,7 @@ impl Runtime { data: rt.as_ref() as *const _ as *mut libc::c_void, recv_cb: msg_from_js, print_cb: print_from_js, + resolve_cb: resolve_callback, soft_memory_limit: 128, hard_memory_limit: 256, }); @@ -282,6 +284,13 @@ impl Runtime { ptr }; + if config.dev_tools { + debug!("Loading dev tools"); + rt.eval("dev-tools.js", *DEV_TOOLS_SOURCE); + rt.eval("", "installDevTools();"); + debug!("Loading dev tools done"); + } + rt } @@ -304,6 +313,10 @@ impl Runtime { self.eval(filename, contents.as_str()) } + pub fn eval_file_with_dev_tools(&self, filename: &str) { + self.eval(filename, &format!("dev.run('{}')", filename)); + } + pub fn heap_statistics(&self) -> js_heap_stats { unsafe { js_runtime_heap_statistics(self.ptr.0) } } @@ -314,9 +327,11 @@ impl Runtime { } pub fn dispose(&mut self) { - // stop listening to events - self.fetch_events.take(); - self.resolv_events.take(); + { + // stop listening to events + self.fetch_events.take(); + self.resolv_events.take(); + }; match self.timers.lock() { Ok(mut timers) => timers.clear(), @@ -376,7 +391,7 @@ impl Runtime { None => return None, Some(ref ch) => match self.dns_responses.lock() { Ok(mut guard) => { - let (tx, rx) = oneshot::channel::(); + let (tx, rx) = oneshot::channel::(); guard.insert(id, tx); match ch.unbounded_send(req) { Ok(_) => EventResponseChannel::Dns(rx), @@ -386,6 +401,21 @@ impl Runtime { Err(_) => return Some(Err(EventDispatchError::PoisonedLock)), }, }, + JsEvent::Serve(req) => match self.serve_events { + None => return None, + Some(ref ch) => match self.service_responses.lock() { + Ok (mut guard) => { + debug!("Dispatching service event."); + let (tx, rx) = oneshot::channel::(); + guard.insert(id, tx); + match ch.unbounded_send(req) { + Ok(_) => EventResponseChannel::Service(rx), + Err(e) => return Some(Err(EventDispatchError::Service(e))), + } + }, + Err(_) => return Some(Err(EventDispatchError::PoisonedLock)), + }, + }, }; if let Ok(epoch) = time::SystemTime::now().duration_since(time::UNIX_EPOCH) { @@ -396,94 +426,33 @@ impl Runtime { Some(Ok(res)) } -} - -pub enum JsEvent { - Fetch(JsHttpRequest), - Resolv(ops::dns::JsDnsRequest), -} - -pub enum EventResponseChannel { - Http(oneshot::Receiver), - Dns(oneshot::Receiver), -} - -#[derive(Debug)] -pub enum EventDispatchError { - PoisonedLock, - Http(mpsc::SendError), - Dns(mpsc::SendError), -} -#[cfg(debug_assertions)] -lazy_static! { - static ref V8ENV_SNAPSHOT: Box<[u8]> = { - let filename = "v8env/dist/v8env.js"; - let mut file = File::open(filename).unwrap(); - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); - let snap = unsafe { - let cfilename = CString::new(filename).unwrap(); - let ccontents = CString::new(contents).unwrap(); - js_create_snapshot(cfilename.as_ptr(), ccontents.as_ptr()) + pub fn get_module_metadata(&self, hash: &i32) -> Option> { + return match self.metadata_cache.read().unwrap().get(hash) { + Some(v) => Some((*v).clone()), + None => None, }; - let bytes: Vec = - unsafe { slice::from_raw_parts(snap.ptr as *const u8, snap.len as usize) }.to_vec(); - bytes.into_boxed_slice() - }; -} + } -lazy_static_include_bytes!(V8ENV_SOURCEMAP, "v8env/dist/v8env.js.map"); -#[cfg(not(debug_assertions))] -const V8ENV_SNAPSHOT: &'static [u8] = include_bytes!("../v8env.bin"); + pub fn insert_module_metadata(&mut self, hash: i32, module_metadata: LoadedModule) { + let locked_cache = self.metadata_cache.get_mut().unwrap(); + if locked_cache.contains_key(&hash) { + error!("Attempted to overwrite entry in module metadata cache."); + } else { + locked_cache.insert(hash, Box::new(module_metadata)); + } + } -extern crate sourcemap; -use self::sourcemap::SourceMap; + pub fn register_rt_manager_callbacks(&mut self, manager_callbacks: RuntimeManagerCallbacks) { + self.manager_callbacks = Some(manager_callbacks); + } -type SourceMapId = (u32, u32, String, String); + pub fn get_uuid(&self) -> String { + return self.uuid.clone(); + } +} lazy_static! { - static ref FLY_SNAPSHOT: fly_simple_buf = fly_simple_buf { - ptr: V8ENV_SNAPSHOT.as_ptr() as *const i8, - len: V8ENV_SNAPSHOT.len() as i32 - }; - static ref SM_CHAN: Mutex, oneshot::Sender>)>> = { - let (sender, receiver) = - stdmspc::channel::<(Vec, oneshot::Sender>)>(); - thread::Builder::new() - .name("sourcemapper".to_string()) - .spawn(move || { - let sm = SourceMap::from_reader(*V8ENV_SOURCEMAP).unwrap(); - for tup in receiver.iter() { - let ch = tup.1; - let v = tup.0; - ch.send( - v.iter() - .map(|(line, col, name, filename)| { - if filename == "v8env/dist/v8env.js" { - return match sm.lookup_token(*line, *col) { - Some(t) => { - let newline = t.get_src_line(); - let newcol = t.get_src_col(); - let newfilename = match t.get_source() { - Some(s) => String::from(s), - None => filename.clone(), - }; - (newline, newcol, name.clone(), newfilename) - } - None => (*line, *col, name.clone(), filename.clone()), - }; - } - (*line, *col, name.clone(), filename.clone()) - }) - .collect(), - ) - .unwrap(); - } - }) - .unwrap(); - Mutex::new(sender) - }; static ref GENERIC_EVENT_LOOP: tokio::runtime::Runtime = { let el = tokio::runtime::Runtime::new().unwrap(); el @@ -502,62 +471,22 @@ lazy_static! { }; } -// Buf represents a byte array returned from a "Op". -// The message might be empty (which will be translated into a null object on -// the javascript side) or it is a heap allocated opaque sequence of bytes. -// Usually a flatbuffer message. -pub type Buf = Option>; - -// JS promises in Fly map onto a specific Future -// which yields either a FlyError or a byte array. -pub type Op = Future + Send; -pub type Handler = fn(JsRuntime, &msg::Base, fly_buf) -> Box; - -use std::slice; - pub extern "C" fn msg_from_js(raw: *const js_runtime, buf: fly_buf, raw_buf: fly_buf) { let bytes = unsafe { slice::from_raw_parts(buf.data_ptr, buf.data_len) }; let base = msg::get_root_as_base(bytes); + let ptr = JsRuntime(raw); + let rt = ptr.to_runtime(); + let msg_type = base.msg_type(); - debug!("MSG TYPE: {:?}", msg_type); let cmd_id = base.cmd_id(); - let handler: Handler = match msg_type { - msg::Any::TimerStart => op_timer_start, - msg::Any::TimerClear => op_timer_clear, - msg::Any::HttpRequest => ops::fetch::op_fetch, - msg::Any::HttpResponse => ops::fetch::op_http_response, - msg::Any::StreamChunk => op_stream_chunk, - msg::Any::CacheGet => ops::cache::op_cache_get, - msg::Any::CacheSet => ops::cache::op_cache_set, - msg::Any::CacheDel => ops::cache::op_cache_del, - msg::Any::CacheNotifyDel => ops::cache::op_cache_notify_del, - msg::Any::CacheNotifyPurgeTag => ops::cache::op_cache_notify_purge_tag, - msg::Any::CacheExpire => ops::cache::op_cache_expire, - msg::Any::CacheSetMeta => ops::cache::op_cache_set_meta, - msg::Any::CachePurgeTag => ops::cache::op_cache_purge_tag, - msg::Any::CryptoDigest => op_crypto_digest, - msg::Any::CryptoRandomValues => op_crypto_random_values, - msg::Any::SourceMap => op_source_map, - msg::Any::DataPut => op_data_put, - msg::Any::DataGet => op_data_get, - msg::Any::DataDel => op_data_del, - msg::Any::DataDropCollection => op_data_drop_coll, - msg::Any::DnsQuery => ops::dns::op_dns_query, - msg::Any::DnsResponse => ops::dns::op_dns_response, - msg::Any::AddEventListener => op_add_event_ln, - msg::Any::LoadModule => op_load_module, - msg::Any::ImageApplyTransforms => ops::image::op_image_transform, - msg::Any::AcmeGetChallenge => ops::acme::op_get_challenge, - _ => unimplemented!(), - }; - - let ptr = JsRuntime(raw); - let fut = handler(ptr, &base, raw_buf); - let fut = fut.or_else(move |err| { - error!("error in {:?}: {:?}", msg_type, err); - Ok(build_error(cmd_id, err)) - }); + let fut = rt + .msg_handler + .handle_msg(ptr.to_runtime(), &base, raw_buf) + .or_else(move |err| { + error!("error in {:?}: {:?}", msg_type, err); + Ok(build_error(cmd_id, err)) + }); if base.sync() { // Execute future synchronously. @@ -603,572 +532,78 @@ pub unsafe extern "C" fn print_from_js(raw: *const js_runtime, lvl: i8, msg: *co let rt = Runtime::from_raw(raw); let msg = CStr::from_ptr(msg).to_string_lossy().into_owned(); - let lvl = match lvl { - 0 => log::Level::Error, - 1 => log::Level::Warn, - 2 => log::Level::Info, - 3 => log::Level::Debug, - 4 => log::Level::Trace, - _ => log::Level::Info, + match lvl { + // print to STDOUT, no logging + 0 => println!("{}", msg), + + // runtime messages from logger + 1 => slog_error!(rt.app_logger, #"runtime", "{}", msg; "source" => "v8env"), + 2 => slog_warn!(rt.app_logger, #"runtime", "{}", msg; "source" => "v8env"), + 3 => slog_info!(rt.app_logger, #"runtime", "{}", msg; "source" => "v8env"), + 4 => slog_debug!(rt.app_logger, #"runtime", "{}", msg; "source" => "v8env"), + 5 => slog_trace!(rt.app_logger, #"runtime", "{}", msg; "source" => "v8env"), + + // app messages from console + 11 => slog_error!(rt.app_logger, #"app", "{}", msg; "source" => "app"), + 12 => slog_warn!(rt.app_logger, #"app", "{}", msg; "source" => "app"), + 13 => slog_info!(rt.app_logger, #"app", "{}", msg; "source" => "app"), + 14 => slog_debug!(rt.app_logger, #"app", "{}", msg; "source" => "app"), + 15 => slog_trace!(rt.app_logger, #"app", "{}", msg; "source" => "app"), + + _ => slog_info!(rt.app_logger, #"runtime", "{}", msg; "source" => "v8env"), }; - - log!(lvl, "console/{}: {}", &rt.name, &msg); } -fn op_timer_start(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - debug!("op_timer_start"); - let msg = base.msg_as_timer_start().unwrap(); - let cmd_id = base.cmd_id(); - let timer_id = msg.id(); - let delay = msg.delay(); - - let rt = ptr.to_runtime(); - - let timers = &rt.timers; - - let fut = { - let (delay_task, cancel_delay) = set_timeout( - move || { - remove_timer(ptr, timer_id); - // send_timer_ready(ptr, timer_id, true); - }, - delay, - ); +pub unsafe extern "C" fn resolve_callback( + raw: *const js_runtime, + specifier: *const libc::c_char, + referer_identity_hash: i32, +) -> js_compiled_module { + let rt = Runtime::from_raw(raw); + let specifier_str = CStr::from_ptr(specifier).to_string_lossy().into_owned(); - timers.lock().unwrap().insert(timer_id, cancel_delay); - delay_task + let referer_loaded_module = match rt.get_module_metadata(&referer_identity_hash) { + Some(v) => v, + None => { + error!("Failed to find module hash in metadata cache! Exiting."); + std::process::exit(1); + } }; - // } - Box::new(fut.then(move |result| { - let builder = &mut FlatBufferBuilder::new(); - let msg = msg::TimerReady::create( - builder, - &msg::TimerReadyArgs { - id: timer_id, - canceled: result.is_err(), - ..Default::default() - }, - ); - Ok(serialize_response( - cmd_id, - builder, - msg::BaseArgs { - msg: Some(msg.as_union_value()), - msg_type: msg::Any::TimerReady, - ..Default::default() - }, - )) - })) -} - -fn remove_timer(ptr: JsRuntime, timer_id: u32) { - let rt = ptr.to_runtime(); - rt.timers.lock().unwrap().remove(&timer_id); -} - -fn op_timer_clear(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - let msg = base.msg_as_timer_clear().unwrap(); - debug!("op_timer_clear"); - remove_timer(ptr, msg.id()); - ok_future(None) -} - -fn op_source_map(_ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - let cmd_id = base.cmd_id(); - let msg = base.msg_as_source_map().unwrap(); - - let msg_frames = msg.frames().unwrap(); - let mut frames = Vec::with_capacity(msg_frames.len()); - - for i in 0..msg_frames.len() { - let f = msg_frames.get(i); - - debug!( - "got frame: {:?} {:?} {:?} {:?}", - f.name(), - f.filename(), - f.line(), - f.col() - ); - let name = match f.name() { - Some(n) => n, - None => "", - }; - - let filename = match f.filename() { - Some(f) => f, - None => "", - }; - - let line = f.line(); - let col = f.col(); - - frames.insert(i, (line, col, String::from(name), String::from(filename))); - } - - let (tx, rx) = oneshot::channel::>(); - if let Err(err) = SM_CHAN.lock().unwrap().send((frames, tx)) { - return odd_future(format!("{}", err).into()); - } - - Box::new( - rx.map_err(|e| FlyError::from(format!("{}", e))) - .and_then(move |v| { - let builder = &mut FlatBufferBuilder::new(); - let framed: Vec<_> = v - .iter() - .map(|(line, col, name, filename)| { - let namefbb = builder.create_string(name.as_str()); - let filenamefbb = builder.create_string(filename.as_str()); - msg::Frame::create( - builder, - &msg::FrameArgs { - name: Some(namefbb), - filename: Some(filenamefbb), - line: *line, - col: *col, - }, - ) - }) - .collect(); - let ret_frames = builder.create_vector(&framed); - - let ret_msg = msg::SourceMapReady::create( - builder, - &msg::SourceMapReadyArgs { - frames: Some(ret_frames), - ..Default::default() - }, - ); - Ok(serialize_response( - cmd_id, - builder, - msg::BaseArgs { - msg: Some(ret_msg.as_union_value()), - msg_type: msg::Any::SourceMapReady, - ..Default::default() - }, - )) - }), - ) -} - -fn op_crypto_random_values(_ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - let cmd_id = base.cmd_id(); - let msg = base.msg_as_crypto_random_values().unwrap(); - - let len = msg.len() as usize; - let mut v = vec![0u8; len]; - let arr = v.as_mut_slice(); - - thread_rng().fill(arr); - - let builder = &mut FlatBufferBuilder::new(); - let ret_buffer = builder.create_vector(arr); - - let crypto_rand = msg::CryptoRandomValuesReady::create( - builder, - &msg::CryptoRandomValuesReadyArgs { - buffer: Some(ret_buffer), - ..Default::default() - }, - ); - - ok_future(serialize_response( - cmd_id, - builder, - msg::BaseArgs { - msg: Some(crypto_rand.as_union_value()), - msg_type: msg::Any::CryptoRandomValuesReady, - ..Default::default() - }, - )) -} - -fn op_crypto_digest(_ptr: JsRuntime, base: &msg::Base, raw: fly_buf) -> Box { - let cmd_id = base.cmd_id(); - let msg = base.msg_as_crypto_digest().unwrap(); - - let algo = msg.algo().unwrap().to_uppercase(); - let buffer = unsafe { slice::from_raw_parts(raw.data_ptr, raw.data_len) }.to_vec(); - - Box::new(future::lazy(move || { - let builder = &mut FlatBufferBuilder::new(); - let bytes_vec = match algo.as_str() { - "SHA-256" => { - let mut h = Sha256::default(); - h.input(buffer.as_slice()); - let res = h.result(); - builder.create_vector(res.as_slice()) - } - "SHA-1" => { - let mut h = Sha1::default(); - h.input(buffer.as_slice()); - let res = h.result(); - builder.create_vector(res.as_slice()) - } - _ => unimplemented!(), - }; - - let crypto_ready = msg::CryptoDigestReady::create( - builder, - &msg::CryptoDigestReadyArgs { - buffer: Some(bytes_vec), - ..Default::default() - }, - ); - Ok(serialize_response( - cmd_id, - builder, - msg::BaseArgs { - msg: Some(crypto_ready.as_union_value()), - msg_type: msg::Any::CryptoDigestReady, - ..Default::default() - }, - )) - })) -} - -fn op_add_event_ln(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - let msg = base.msg_as_add_event_listener().unwrap(); - - match msg.event() { - msg::EventType::Fetch => { - let (tx, rx) = mpsc::unbounded::(); - let rt = ptr.to_runtime(); - rt.spawn( - rx.map_err(|_| error!("error event receiving http request")) - .for_each(move |req| { - let builder = &mut FlatBufferBuilder::new(); - - let req_url = builder.create_string(req.url.as_str()); - - let req_method = match req.method { - Method::GET => msg::HttpMethod::Get, - Method::POST => msg::HttpMethod::Post, - Method::HEAD => msg::HttpMethod::Head, - _ => unimplemented!(), - }; - - let headers: Vec<_> = req - .headers - .iter() - .map(|(key, value)| { - let key = builder.create_string(key.as_str()); - let value = builder.create_string(value.to_str().unwrap()); - msg::HttpHeader::create( - builder, - &msg::HttpHeaderArgs { - key: Some(key), - value: Some(value), - ..Default::default() - }, - ) - }) - .collect(); - - let req_headers = builder.create_vector(&headers); - - let req_msg = msg::HttpRequest::create( - builder, - &msg::HttpRequestArgs { - id: req.id, - method: req_method, - url: Some(req_url), - headers: Some(req_headers), - has_body: req.body.is_some(), - ..Default::default() - }, - ); - - let to_send = fly_buf_from( - serialize_response( - 0, - builder, - msg::BaseArgs { - msg: Some(req_msg.as_union_value()), - msg_type: msg::Any::HttpRequest, - ..Default::default() - }, - ) - .unwrap(), - ); - - ptr.send(to_send, None); - - if let Some(stream) = req.body { - send_body_stream(ptr, req.id, stream); - } - - Ok(()) - }) - .and_then(|_| Ok(info!("done listening to http events."))), - ); - rt.fetch_events = Some(tx); - } - msg::EventType::Resolv => { - let (tx, rx) = mpsc::unbounded::(); - let rt = ptr.to_runtime(); - rt.spawn( - rx.map_err(|_| error!("error event receiving http request")) - .for_each(move |req| { - let builder = &mut FlatBufferBuilder::new(); - - let queries: Vec<_> = req - .queries - .iter() - .map(|q| { - debug!("query: {:?}", q); - use self::dns::rr::{DNSClass, Name, RecordType}; - let name = builder.create_string(&Name::from(q.name().clone()).to_utf8()); - let rr_type = match q.query_type() { - RecordType::A => msg::DnsRecordType::A, - RecordType::AAAA => msg::DnsRecordType::AAAA, - RecordType::AXFR => msg::DnsRecordType::AXFR, - RecordType::CAA => msg::DnsRecordType::CAA, - RecordType::CNAME => msg::DnsRecordType::CNAME, - RecordType::IXFR => msg::DnsRecordType::IXFR, - RecordType::MX => msg::DnsRecordType::MX, - RecordType::NS => msg::DnsRecordType::NS, - RecordType::NULL => msg::DnsRecordType::NULL, - RecordType::OPT => msg::DnsRecordType::OPT, - RecordType::PTR => msg::DnsRecordType::PTR, - RecordType::SOA => msg::DnsRecordType::SOA, - RecordType::SRV => msg::DnsRecordType::SRV, - RecordType::TLSA => msg::DnsRecordType::TLSA, - RecordType::TXT => msg::DnsRecordType::TXT, - _ => unimplemented!(), - }; - let dns_class = match q.query_class() { - DNSClass::IN => msg::DnsClass::IN, - DNSClass::CH => msg::DnsClass::CH, - DNSClass::HS => msg::DnsClass::HS, - DNSClass::NONE => msg::DnsClass::NONE, - DNSClass::ANY => msg::DnsClass::ANY, - _ => unimplemented!(), - }; - - msg::DnsQuery::create( - builder, - &msg::DnsQueryArgs { - name: Some(name), - rr_type: rr_type, - dns_class: dns_class, - ..Default::default() - }, - ) - }) - .collect(); - - let req_queries = builder.create_vector(&queries); - - let req_msg = msg::DnsRequest::create( - builder, - &msg::DnsRequestArgs { - id: req.id, - message_type: match req.message_type { - dns::op::MessageType::Query => msg::DnsMessageType::Query, - _ => unimplemented!(), - }, - queries: Some(req_queries), - ..Default::default() - }, - ); - - let to_send = fly_buf_from( - serialize_response( - 0, - builder, - msg::BaseArgs { - msg: Some(req_msg.as_union_value()), - msg_type: msg::Any::DnsRequest, - ..Default::default() - }, - ) - .unwrap(), - ); - - ptr.send(to_send, None); - Ok(()) - }), - ); - rt.resolv_events = Some(tx); + let loaded_module = match rt.module_resolver_manager.resolve_module( + specifier_str, + Some(RefererInfo { + origin_url: referer_loaded_module.origin_url, + is_wasm: Some(referer_loaded_module.loaded_source.is_wasm), + source_code: Some(referer_loaded_module.loaded_source.source), + indentifier_hash: Some(referer_identity_hash), + }), + ) { + Ok(v) => v, + Err(e) => { + error!("Failed to resolve and load module! Exiting. {}", e); + std::process::exit(1); } }; - ok_future(None) -} - -fn op_stream_chunk(ptr: JsRuntime, base: &msg::Base, raw: fly_buf) -> Box { - debug!("handle stream chunk {:?}", raw); - let msg = base.msg_as_stream_chunk().unwrap(); - let stream_id = msg.id(); + let module_data = js_module_data { + origin_url: CString::new(loaded_module.origin_url).unwrap().as_ptr(), + source_map_url: CString::new("").unwrap().as_ptr(), + is_wasm: loaded_module.loaded_source.is_wasm, + source_code: fly_simple_buf { + ptr: CString::new(loaded_module.loaded_source.source.as_str()) + .unwrap() + .as_ptr(), + len: loaded_module.loaded_source.source.len() as i32, + }, + }; - let rt = ptr.to_runtime(); + let compile_result = js_compile_module(raw, module_data); - let mut streams = rt.streams.lock().unwrap(); - if raw.data_len > 0 { - match streams.get_mut(&stream_id) { - Some(sender) => { - let bytes = unsafe { slice::from_raw_parts(raw.data_ptr, raw.data_len) }.to_vec(); - match sender.unbounded_send(bytes.to_vec()) { - Err(e) => error!("error sending chunk: {}", e), - _ => debug!("chunk streamed"), - } - } - None => unimplemented!(), - }; - } - if msg.done() { - streams.remove(&stream_id); + if compile_result.success { + return compile_result.compiled_module; + } else { + error!("Module compile failed! Exiting."); + std::process::exit(1); } - - ok_future(None) -} - -fn set_timeout(cb: F, delay: u32) -> (impl Future, oneshot::Sender<()>) -where - F: FnOnce() -> (), -{ - let (cancel_tx, cancel_rx) = oneshot::channel::<()>(); - let when = Instant::now() + Duration::from_millis(delay.into()); - let delay_task = Delay::new(when) - .map_err(|e| panic!("timer failed; err={:?}", e)) - .and_then(|_| { - cb(); - Ok(()) - }) - .select(cancel_rx) - .map(|_| ()) - .map_err(|_| ()); - - (delay_task, cancel_tx) -} - -fn op_data_put(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - let msg = base.msg_as_data_put().unwrap(); - let coll = msg.collection().unwrap().to_string(); - let key = msg.key().unwrap().to_string(); - let value = msg.json().unwrap().to_string(); - - let rt = ptr.to_runtime(); - - Box::new( - rt.data_store - .put(coll, key, value) - .map_err(|e| format!("{:?}", e).into()) - .and_then(move |_| Ok(None)), - ) -} - -fn op_data_get(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - let cmd_id = base.cmd_id(); - let msg = base.msg_as_data_get().unwrap(); - let coll = msg.collection().unwrap().to_string(); - let key = msg.key().unwrap().to_string(); - - let rt = ptr.to_runtime(); - - Box::new( - rt.data_store - .get(coll, key) - .map_err(|e| format!("error in data store get: {:?}", e).into()) - .and_then(move |s| match s { - None => Ok(None), - Some(s) => { - let builder = &mut FlatBufferBuilder::new(); - let json = builder.create_string(&s); - let msg = msg::DataGetReady::create( - builder, - &msg::DataGetReadyArgs { - json: Some(json), - ..Default::default() - }, - ); - Ok(serialize_response( - cmd_id, - builder, - msg::BaseArgs { - msg: Some(msg.as_union_value()), - msg_type: msg::Any::DataGetReady, - ..Default::default() - }, - )) - } - }), - ) -} - -fn op_data_del(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - let msg = base.msg_as_data_del().unwrap(); - let coll = msg.collection().unwrap().to_string(); - let key = msg.key().unwrap().to_string(); - - let rt = ptr.to_runtime(); - - Box::new( - rt.data_store - .del(coll, key) - .map_err(|e| format!("{:?}", e).into()) - .and_then(move |_| Ok(None)), - ) -} - -fn op_data_drop_coll(ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - let msg = base.msg_as_data_drop_collection().unwrap(); - let coll = msg.collection().unwrap().to_string(); - - let rt = ptr.to_runtime(); - - Box::new( - rt.data_store - .drop_coll(coll) - .map_err(|e| format!("{:?}", e).into()) - .and_then(move |_| Ok(None)), - ) -} - -fn op_load_module(_ptr: JsRuntime, base: &msg::Base, _raw: fly_buf) -> Box { - let cmd_id = base.cmd_id(); - let msg = base.msg_as_load_module().unwrap(); - let module_specifier = msg.module_specifier().unwrap().to_string(); - let containing_file = msg.containing_file().unwrap().to_string(); - - let module = - match crate::compiler::Compiler::new(None).fetch_module(&module_specifier, &containing_file) { - Ok(m) => m, - Err(e) => return odd_future(e.into()), - }; - - Box::new(future::lazy(move || { - let builder = &mut FlatBufferBuilder::new(); - let module_id = builder.create_string(&module.module_id); - let file_name = builder.create_string(&module.file_name); - let source_code = builder.create_string(&module.source_code); - - let msg = msg::LoadModuleResp::create( - builder, - &msg::LoadModuleRespArgs { - module_id: Some(module_id), - file_name: Some(file_name), - source_code: Some(source_code), - }, - ); - Ok(serialize_response( - cmd_id, - builder, - msg::BaseArgs { - msg: Some(msg.as_union_value()), - msg_type: msg::Any::LoadModuleResp, - ..Default::default() - }, - )) - })) -} - -#[cfg(test)] -mod tests { - #[test] - fn test_runtime_dispose() {} } diff --git a/src/runtime_manager.rs b/src/runtime_manager.rs new file mode 100644 index 0000000..49500e8 --- /dev/null +++ b/src/runtime_manager.rs @@ -0,0 +1,38 @@ +use crate::js::JsServiceResponse; +use crate::runtime::{ Runtime, RuntimeConfig }; + +use crate::errors::{ FlyResult }; + +use crate::module_resolver::{ ModuleResolver }; + +use crate::settings::{ Settings }; + +use std::sync::{ RwLock, Arc, Mutex }; + +use uuid::Uuid; + +use futures::sync::oneshot; + +pub struct RuntimeManagerCallbacks { + pub send_message: Box<(Fn(Uuid, String) -> FlyResult>) + Send + Sync>, + pub uuid_by_servicename: Box<(Fn(String) -> FlyResult>) + Send + Sync>, +} + +pub trait RuntimeManager: Send + Sync { + fn new_runtime(&mut self, config: RuntimeConfig) -> Arc>>; + fn remove_runtime(&self, uuid: Uuid) -> Result<(), RuntimeManagerError>; + fn bind_servicename_to(&mut self, uuid: Uuid, servicename: &str) -> Result<(), RuntimeManagerError>; + fn bind_hostname_to(&mut self, uuid: Uuid, hostname: &str) -> Result<(), RuntimeManagerError>; + fn get_by_hostname(&self, hostname: &str) -> Result>>>, RuntimeManagerError>; + fn get_by_servicename(&self, servicename: &str) -> Result>>>, RuntimeManagerError>; + fn get_by_uuid(&self, uuid: Uuid) -> Result>>>, RuntimeManagerError>; +} + +pub fn register_manager_with_rt(manager: Box<&'static RuntimeManager>, runtime: Arc>) { + +} + +#[derive(Debug)] +pub enum RuntimeManagerError { + Failure(String), +} diff --git a/src/runtime_permissions.rs b/src/runtime_permissions.rs new file mode 100644 index 0000000..7bc900c --- /dev/null +++ b/src/runtime_permissions.rs @@ -0,0 +1,26 @@ +use crate::errors::{permission_denied, FlyResult}; + +#[derive(Debug)] +pub struct RuntimePermissions { + pub allow_os: bool, +} + +impl RuntimePermissions { + pub fn new(allow_os: bool) -> Self { + Self { allow_os } + } + + pub fn check_os(&self) -> FlyResult<()> { + if self.allow_os { + Ok(()) + } else { + Err(permission_denied()) + } + } +} + +impl Default for RuntimePermissions { + fn default() -> Self { + RuntimePermissions { allow_os: false } + } +} diff --git a/src/runtime_selector.rs b/src/runtime_selector.rs deleted file mode 100644 index e032dd5..0000000 --- a/src/runtime_selector.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::runtime::Runtime; - -pub trait RuntimeSelector { - fn get_by_hostname(&self, hostname: &str) -> Result, SelectorError>; -} - -#[derive(Debug)] -pub enum SelectorError { - Unknown, - Failure(String), -} diff --git a/src/sqlite_cache.rs b/src/sqlite_cache.rs index 0e0ca06..c282fc6 100644 --- a/src/sqlite_cache.rs +++ b/src/sqlite_cache.rs @@ -59,7 +59,7 @@ impl CacheStore for SqliteCacheStore { let mut stmt = conn .prepare( - "SELECT rowid FROM cache + "SELECT rowid,meta FROM cache WHERE key = ? AND ( expires_at IS NULL OR @@ -70,19 +70,28 @@ impl CacheStore for SqliteCacheStore { let mut rows = stmt.query(&[&key])?; - let rowid: i64 = match rows.next() { - Some(res) => match res { - Ok(row) => row.get(0), - Err(e) => return Err(CacheError::Failure(format!("{}", e))), - }, + let row_res = rows.next(); + + let rowid: i64 = match row_res { + Some(Ok(ref row)) => row.get(0), + Some(Err(e)) => return Err(CacheError::Failure(format!("{}", e))), None => { debug!("row not found"); return Ok(None); } }; + let meta: Option = match row_res { + Some(Ok(ref row)) => row.get(1), + Some(Err(e)) => { + error!("error getting metadata from row: {}", e); + None + } + None => None, + }; + Ok(Some(CacheEntry { - meta: None, + meta: meta, stream: Box::new(stream::unfold(0, move |pos| { debug!("sqlite cache get in stream future, pos: {}", pos); @@ -149,10 +158,10 @@ impl CacheStore for SqliteCacheStore { if let Some(ttl) = opts.ttl { let mut stmt = conn .prepare( - "INSERT INTO cache(key, value, expires_at) - VALUES (?, ?, datetime('now', ?)) + "INSERT INTO cache(key, value, meta, expires_at) + VALUES (?, ?, ?, datetime('now', ?)) ON CONFLICT (key) DO - UPDATE SET value=excluded.value,expires_at=excluded.expires_at + UPDATE SET value=excluded.value,meta=excluded.meta,expires_at=excluded.expires_at ", ) .unwrap(); @@ -161,21 +170,24 @@ impl CacheStore for SqliteCacheStore { .insert(&[ &key as &ToSql, &b as &ToSql, + &opts.meta as &ToSql, &format!("+{} seconds", ttl) as &ToSql, ]) .unwrap() } else { let mut stmt = conn .prepare( - "INSERT INTO cache(key, value, expires_at) - VALUES (?, ?, NULL) + "INSERT INTO cache(key, value, meta, expires_at) + VALUES (?, ?, ?, NULL) ON CONFLICT (key) DO - UPDATE SET value=excluded.value,expires_at=excluded.expires_at + UPDATE SET value=excluded.value,meta=excluded.meta,expires_at=excluded.expires_at ", ) .unwrap(); - stmt.insert(&[&key as &ToSql, &b as &ToSql]).unwrap() + stmt + .insert(&[&key as &ToSql, &b as &ToSql, &opts.meta as &ToSql]) + .unwrap() }; Ok(()) }), diff --git a/src/sqlite_data.rs b/src/sqlite_data.rs index 9bd0ecf..6baae8c 100644 --- a/src/sqlite_data.rs +++ b/src/sqlite_data.rs @@ -97,6 +97,39 @@ impl DataStore for SqliteDataStore { })) } + fn incr( + &self, + coll: String, + key: String, + field: String, + amount: i32, + ) -> Box + Send> { + debug!( + "sqlite data store incr coll: {}, key: {}, amount: {}", + coll, key, amount + ); + let pool = self.pool.clone(); + Box::new(future::lazy(move || -> DataResult<()> { + let con = pool.get().unwrap(); // TODO: no unwrap + + ensure_coll(&*con, &coll).unwrap(); + + let selector = format!("$.{}", field); + + match con.execute( + format!( + "UPDATE {} SET obj = json_set(obj, '{}', COALESCE(json_extract(obj, '{}'), '0') + ?) WHERE key == ?", + coll, selector, selector + ) + .as_str(), + &[&amount.to_string(), &key], + ) { + Ok(_) => Ok(()), + Err(e) => Err(e.into()), + } + })) + } + fn drop_coll(&self, coll: String) -> Box + Send> { debug!("sqlite data store drop coll: {}", coll); let pool = self.pool.clone(); @@ -118,7 +151,8 @@ fn ensure_coll(conn: &rusqlite::Connection, name: &str) -> rusqlite::Result, - ) { - let setfut = store.put(coll.to_string(), key.to_string(), value.to_string()); - - match maybe_el { - Some(el) => el.block_on(setfut).unwrap(), - None => tokio::runtime::Runtime::new() - .unwrap() - .block_on(setfut) - .unwrap(), - }; + fn set_value(store: &SqliteDataStore, coll: &str, key: &str, value: &str) { + store + .put(coll.to_string(), key.to_string(), value.to_string()) + .wait() + .unwrap(); } #[test] - fn test_put_get() { + fn test_sqlite_data_put_get() { let store = setup(); - let mut el = tokio::runtime::Runtime::new().unwrap(); let coll = "coll1"; let key = "test:key"; let value = r#"{"foo": "bar"}"#; - set_value(&store, coll, key, value, Some(&mut el)); + set_value(&store, coll, key, value); - let got = el - .block_on(store.get(coll.to_string(), key.to_string())) + let got = store + .get(coll.to_string(), key.to_string()) + .wait() .unwrap() .unwrap(); @@ -167,13 +190,46 @@ mod tests { } #[test] - fn test_del() { + fn test_sqlite_data_incr() { + let store = setup(); + let coll = "collincr"; + let key = "test:key"; + let value = r#"{"counter": 0, "foo": "bar"}"#; + set_value(&store, coll, key, value); + + store + .incr(coll.to_string(), key.to_string(), "counter".to_string(), 1) + .wait() + .unwrap(); + let got = store + .get(coll.to_string(), key.to_string()) + .wait() + .unwrap() + .unwrap(); + + assert_eq!(got, r#"{"counter":1,"foo":"bar"}"#); + + store + .incr(coll.to_string(), key.to_string(), "counter".to_string(), 15) + .wait() + .unwrap(); + let got = store + .get(coll.to_string(), key.to_string()) + .wait() + .unwrap() + .unwrap(); + + assert_eq!(got, r#"{"counter":16,"foo":"bar"}"#); + } + + #[test] + fn test_sqlite_data_del() { let store = setup(); let mut el = tokio::runtime::Runtime::new().unwrap(); let coll = "coll1"; let key = "test:key"; let value = "{}"; - set_value(&store, coll, key, value, Some(&mut el)); + set_value(&store, coll, key, value); let got_res = el .block_on(store.get(coll.to_string(), key.to_string())) diff --git a/src/standard_runtime_manager.rs b/src/standard_runtime_manager.rs new file mode 100644 index 0000000..4929408 --- /dev/null +++ b/src/standard_runtime_manager.rs @@ -0,0 +1,144 @@ +use crate::runtime::RuntimeConfig; +use crate::runtime::Runtime; +use crate::runtime_manager::{ RuntimeManager, RuntimeManagerError, RuntimeManagerCallbacks }; +use crate::errors::{ FlyError, FlyResult }; + +use crate::{get_next_stream_id}; + +use crate::js::*; +use crate::utils::*; + +use std::collections::HashMap; + +use std::sync::{ Mutex, Arc, RwLock }; + +use uuid::Uuid; + +use futures::future::Future; + +use futures::sync::oneshot; + +pub struct StandardRuntimeManager { + uuid_to_runtime: RwLock>>>>, + hostname_to_uuid: RwLock>, + servicename_to_uuid: RwLock>, + self_ref: Option>>, +} + +impl StandardRuntimeManager { + pub fn new() -> Arc> { + let mut new_self_ref = Arc::new(RwLock::new(Self { + uuid_to_runtime: RwLock::new(HashMap::new()), + hostname_to_uuid: RwLock::new(HashMap::new()), + servicename_to_uuid: RwLock::new(HashMap::new()), + self_ref: None, + })); + new_self_ref.write().unwrap().self_ref = Some(new_self_ref.clone()); + new_self_ref + } +} + +impl RuntimeManager for StandardRuntimeManager { + fn new_runtime( + &mut self, + config: RuntimeConfig, + ) -> Arc>> { + let runtime = Runtime::new(config); + let uuid_map_lock = self.uuid_to_runtime.get_mut().unwrap(); + let uuid = runtime.get_uuid(); + let rt_arc = Arc::new(RwLock::new(runtime)); + uuid_map_lock.insert(uuid, rt_arc.clone()); + let man_arc = match &self.self_ref { + Some(v) => v.clone(), + None => { + warn!("Self ref missing."); + std::process::exit(1); + }, + }; + let man_send_msg_clone = man_arc.clone(); + let rt_send_msg_clone = rt_arc.clone(); + let send_message = Box::new(move |recieiver: Uuid, message: String| -> FlyResult> { + let man_read_lock = man_send_msg_clone.read().unwrap(); + let recieiver_rt = man_read_lock.get_by_uuid(recieiver).unwrap(); + let rt_lock = rt_send_msg_clone.read().unwrap(); + match recieiver_rt { + Some(v) => { + let recieiver_rt_lock = v.read().unwrap(); + let eid = get_next_stream_id(); + if recieiver_rt_lock.get_uuid() == rt_lock.get_uuid() { + return Err("Cannot send requests to the same runtime.(Creates race condition with blocking operations)".to_string().into()); + } + match recieiver_rt_lock.dispatch_event( + eid, + JsEvent::Serve(JsServiceRequest { + id: eid, + sender: recieiver_rt_lock.get_uuid(), + data: message, + }), + ) { + None => Err("Failed to dispatch service request".to_string().into()), + Some(Err(e)) => Err(format!("error sending js service request: {:?}", e).to_string().into()), + Some(Ok(EventResponseChannel::Service(rx))) => Ok(rx), + _ => unimplemented!(), + } + }, + None => Err(FlyError::from("Receiver not found.".to_string())), + } + }); + let man_uuid_by_servicename_clone = man_arc.clone(); + let uuid_by_servicename = Box::new(move |servicename: String| -> FlyResult>{ + return match man_uuid_by_servicename_clone.read().unwrap().get_by_servicename(&servicename) { + Ok(Some(v)) => { + let rt_lock = v.read().unwrap(); + Ok(Some(uuid::Uuid::parse_str(&rt_lock.get_uuid()).unwrap())) + }, + Ok(None) => Ok(None), + Err(err) => Err(FlyError::from(err)), + }; + }); + let rt_mut_clone = rt_arc.clone(); + { + let rt_lock = rt_arc.read().unwrap(); + let rt_mut = rt_lock.ptr.to_runtime(); + rt_mut.register_rt_manager_callbacks(RuntimeManagerCallbacks { + send_message, + uuid_by_servicename, + }); + } + rt_arc.clone() + } + fn remove_runtime(&self, uuid: Uuid) -> Result<(), RuntimeManagerError> { + Err(RuntimeManagerError::Failure("Not implemented".to_string())) + } + fn bind_servicename_to(&mut self, uuid: Uuid, servicename: &str) -> Result<(), RuntimeManagerError> { + let uuid_string = uuid.to_simple().to_string(); + match self.servicename_to_uuid.get_mut().unwrap().insert(servicename.to_string(), uuid_string) { + Some(v) => Ok(()), + None => Ok(()), + } + } + fn bind_hostname_to(&mut self, uuid: Uuid, hostname: &str) -> Result<(), RuntimeManagerError> { + let hostname_map_lock = self.hostname_to_uuid.get_mut().unwrap(); + let uuid_string = uuid.to_simple().to_string(); + hostname_map_lock.insert(hostname.to_string(), uuid_string); + Ok(()) + } + fn get_by_hostname(&self, hostname: &str) -> Result>>>, RuntimeManagerError> { + return match self.hostname_to_uuid.read().unwrap().get(hostname) { + Some(v) => self.get_by_uuid(uuid::Uuid::parse_str(v).unwrap()), + None => Ok(None), + }; + } + fn get_by_servicename(&self, servicename: &str) -> Result>>>, RuntimeManagerError> { + return match self.servicename_to_uuid.read().unwrap().get(servicename) { + Some(v) => self.get_by_uuid(uuid::Uuid::parse_str(v).unwrap()), + None => Ok(None), + }; + } + fn get_by_uuid(&self, uuid: Uuid) -> Result>>>, RuntimeManagerError> { + return match self.uuid_to_runtime.read().unwrap().get(&uuid.to_simple().to_string()) { + Some(v) => Ok(Some(v.clone())), + None => Ok(None), + }; + } +} diff --git a/src/utils.rs b/src/utils.rs index 5707de3..740787d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,14 +1,36 @@ +use crate::errors::FlyError; +use crate::js::*; use crate::msg; +use crate::runtime::{JsRuntime, Runtime}; use flatbuffers::FlatBufferBuilder; +use futures::{ + future, + sync::{mpsc, oneshot}, + Future, Stream, +}; use libfly::*; +use std::ptr; +use tokio_signal::unix::{Signal, SIGINT, SIGTERM}; -use crate::errors::FlyError; +// Buf represents a byte array returned from a "Op". +// The message might be empty (which will be translated into a null object on +// the javascript side) or it is a heap allocated opaque sequence of bytes. +// Usually a flatbuffer message. +pub type Buf = Option>; -use crate::runtime::{Buf, JsBody, JsRuntime, Op}; +// JS promises in Fly map onto a specific Future +// which yields either a FlyError or a byte array. +pub type Op = Future + Send; +pub type Handler = fn(&mut Runtime, &msg::Base, fly_buf) -> Box; -use futures::{future, Future, Stream}; +pub fn take_last_n(str: &str, n: usize) -> Option<&str> { + if str.len() >= n { + Some(&str[str.len() - n..]) + } else { + None + } +} -use std::ptr; pub fn serialize_response( cmd_id: u32, @@ -74,7 +96,8 @@ pub fn send_body_stream(ptr: JsRuntime, req_id: u32, stream: JsBody) { .for_each(move |v| { send_stream_chunk(ptr, req_id, v.as_ptr() as *mut u8, v.len(), false); Ok(()) - }).and_then(move |_| { + }) + .and_then(move |_| { send_done_stream(ptr, req_id); Ok(()) }), @@ -91,38 +114,8 @@ pub fn send_body_stream(ptr: JsRuntime, req_id: u32, stream: JsBody) { .for_each(move |v| { send_stream_chunk(ptr, req_id, v.as_ptr() as *mut u8, v.len(), false); Ok(()) - }).and_then(move |_| { - send_done_stream(ptr, req_id); - Ok(()) - }), - ); - } - JsBody::BytesStream(rx) => { - rt.spawn( - rx.map_err(move |e| error!("error reading from stream channel: {:?}", e)) - .for_each(move |mut b| { - send_stream_chunk(ptr, req_id, b.as_mut_ptr() as *mut u8, b.len(), false); - Ok(()) - }).and_then(move |_| { - send_done_stream(ptr, req_id); - Ok(()) - }), - ); - } - JsBody::HyperBody(b) => { - rt.spawn( - b.map_err(|e| error!("error in hyper body stream read: {:?}", e)) - .for_each(move |chunk| { - let bytes = chunk.into_bytes(); - send_stream_chunk( - ptr, - req_id, - (*bytes).as_ptr() as *mut u8, - bytes.len(), - false, - ); - Ok(()) - }).and_then(move |_| { + }) + .and_then(move |_| { send_done_stream(ptr, req_id); Ok(()) }), @@ -150,7 +143,8 @@ pub fn send_stream_chunk(ptr: JsRuntime, req_id: u32, chunk: *mut u8, len: usize msg_type: msg::Any::StreamChunk, ..Default::default() }, - ).unwrap(), + ) + .unwrap(), ), Some(fly_buf { alloc_ptr: ptr::null_mut() as *mut u8, @@ -180,8 +174,61 @@ pub fn send_done_stream(ptr: JsRuntime, req_id: u32) { msg_type: msg::Any::StreamChunk, ..Default::default() }, - ).unwrap(), + ) + .unwrap(), ), None, ); } + +pub enum EventResponseChannel { + Http(oneshot::Receiver), + Dns(oneshot::Receiver), + Service(oneshot::Receiver), +} + +#[derive(Debug)] +pub enum EventDispatchError { + PoisonedLock, + Http(mpsc::SendError), + Dns(mpsc::SendError), + Service(mpsc::SendError), +} + +pub fn signal_monitor() -> ( + impl Future + Send + 'static, + oneshot::Receiver<()>, +) { + let (sigtx, sigrx) = oneshot::channel(); + ( + Signal::new(SIGTERM) + .join(Signal::new(SIGINT)) + .map_err(|error| { + error!("Failed to set up process signal monitoring: {:?}", error); + }) + .and_then(|(sigterms, sigints)| { + // Stream of all signals we care about + let signals = sigterms.select(sigints); + // Take only the first signal in the stream and log that it was triggered + signals + .take(1) + .map_err(|error| { + error!("Error while listening on process signals: {:?}", error); + }) + .for_each(|signal| { + let signal_name = match signal { + SIGTERM => "SIGTERM", + SIGINT => "SIGINT", + _ => unreachable!(), + }; + info!("Received {}, gracefully shutting down", signal_name); + Ok(()) + }) + }) + .and_then(move |_| { + sigtx.send(()).ok(); // don't care. + Ok(()) + }), + sigrx, + ) +} diff --git a/src/v8env.rs b/src/v8env.rs new file mode 100644 index 0000000..f899811 --- /dev/null +++ b/src/v8env.rs @@ -0,0 +1,37 @@ +use libfly::*; +use std::ffi::CString; +use std::fs::File; +use std::io::Read; +use std::slice; + +#[cfg(not(debug_assertions))] +const V8ENV_SNAPSHOT: &'static [u8] = include_bytes!("../v8env.bin"); + +#[cfg(debug_assertions)] +lazy_static! { + static ref V8ENV_SNAPSHOT: Box<[u8]> = { + let filename = "v8env/dist/v8env.js"; + let mut file = File::open(filename).unwrap(); + let mut contents = String::new(); + file.read_to_string(&mut contents).unwrap(); + let snap = unsafe { + let cfilename = CString::new(filename).unwrap(); + let ccontents = CString::new(contents).unwrap(); + js_create_snapshot(cfilename.as_ptr(), ccontents.as_ptr()) + }; + let bytes: Vec = + unsafe { slice::from_raw_parts(snap.ptr as *const u8, snap.len as usize) }.to_vec(); + bytes.into_boxed_slice() + }; +} + +lazy_static! { + pub static ref FLY_SNAPSHOT: fly_simple_buf = fly_simple_buf { + ptr: V8ENV_SNAPSHOT.as_ptr() as *const i8, + len: V8ENV_SNAPSHOT.len() as i32 + }; +} + +lazy_static_include_bytes!(pub V8ENV_SOURCEMAP, "v8env/dist/v8env.js.map"); + +lazy_static_include_str!(pub DEV_TOOLS_SOURCE, "v8env/dist/dev-tools.js"); diff --git a/test-service-runtime.js b/test-service-runtime.js new file mode 100644 index 0000000..2457284 --- /dev/null +++ b/test-service-runtime.js @@ -0,0 +1,6 @@ + +addEventListener("serve", function (event) { + console.log("Recieved serve request"); + event.respondWith(new ServiceResponse(true, { data: "test" })); +}); + \ No newline at end of file diff --git a/v8env/.vscode/settings.json b/v8env/.vscode/settings.json new file mode 100644 index 0000000..55712c1 --- /dev/null +++ b/v8env/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/v8env/package.json b/v8env/package.json index 535648c..51caf2e 100644 --- a/v8env/package.json +++ b/v8env/package.json @@ -21,30 +21,29 @@ "bundle": "webpack", "doc": "./publish-docs.sh" }, - "dependencies": { - "@stardazed/streams": "^1.0.6", - "cookie": "^0.3.1", - "flatbuffers": "~1.9.0", - "http-cache-semantics": "^4.0.0", - "query-string": "^6.1.0", - "source-map-support": "^0.5.9", - "text-encoding": "0.6.4" - }, + "dependencies": {}, "devDependencies": { + "@chaitin/querystring": "^1.1.0", + "@stardazed/streams": "^1.0.6", "@types/chai": "^4.1.6", "@types/cookie": "^0.3.1", + "@types/cookiejar": "^2.1.1", "@types/expect": "^1.20.3", "@types/flatbuffers": "^1.9.0", "@types/mocha": "^5.2.5", "@types/pako": "^1.0.0", - "@types/query-string": "^6.1.0", "@types/source-map-support": "^0.4.1", "@types/text-encoding": "0.0.33", "chai": "^4.2.0", + "cookie": "^0.3.1", + "cookiejar": "^2.1.2", "expect": "^23.6.0", + "flatbuffers": "~1.9.0", + "http-cache-semantics": "^4.0.0", "magic-string": "^0.25.1", "mocha": "^5.2.0", "pako": "^1.0.7", + "querystring": "^0.2.0", "rollup": "^0.65.0", "rollup-plugin-commonjs": "^9.1.6", "rollup-plugin-node-builtins": "^2.1.2", @@ -54,7 +53,9 @@ "rollup-plugin-typescript2": "^0.18.0", "rollup-plugin-virtual": "^1.0.1", "rollup-pluginutils": "^2.3.3", - "typescript": "3.0.1" + "source-map-support": "^0.5.9", + "text-encoding": "0.6.4", + "typescript": "3.2.2" }, "publishConfig": { "access": "public" diff --git a/v8env/rollup.config.js b/v8env/rollup.config.js index c3a35eb..d8f1a60 100644 --- a/v8env/rollup.config.js +++ b/v8env/rollup.config.js @@ -75,7 +75,7 @@ function runtimeInfo(path) { name: "runtimeInfo", transform: (code, id) => { if (filter(id)) { - const build = execSync('./scripts/build-number.sh', { + const build = execSync('./scripts/build-version.sh', { cwd: '..' }).toString(); @@ -90,6 +90,11 @@ function runtimeInfo(path) { } } +const chaiPath = path.resolve( + __dirname, + "node_modules/chai/lib/chai.js" +); + export default [ { input: 'src/index.ts', @@ -104,6 +109,7 @@ export default [ typescriptPlugin({ useTsconfigDeclarationDir: true }), resolvePlugin({ jsnext: true, + preferBuiltins: false, }), commonjsPlugin({ include: './node_modules/**', @@ -114,31 +120,6 @@ export default [ include: 'src/**', } }, - { - input: "src/test_main.ts", - output: { - file: 'dist/testing.js', - format: 'iife', - name: 'flyTest', - sourcemap: true, - globals: { - mocha: 'mocha' - } - }, - plugins: [ - // builtins(), - resolvePlugin({ - browser: true - // jsnext: true, - // module: true, - }), - commonjsPlugin({ - include: './node_modules/**', - }), - typescriptPlugin({ useTsconfigDeclarationDir: true }), - sourceMaps(), - ] - }, { input: "src/dev-tools/index.ts", output: { @@ -161,14 +142,9 @@ export default [ os: mock, crypto: mock, buffer: mock, - module: mock + module: mock, }), - // alias({ - // path: path.resolve(__dirname, "node_modules/path-browserify/index.js"), - // // rollup: rollupPath - // }), - // Provides inlining of file contents for `js/assets.ts` strings({ include: [ @@ -180,7 +156,8 @@ export default [ resolvePlugin({ jsnext: true, - main: true + main: true, + preferBuiltins: false, // browser: true }), @@ -199,7 +176,10 @@ export default [ "ScriptSnapshot", "ScriptTarget", "version" - ] + ], + [chaiPath]: [ + "expect", + ], } }), diff --git a/v8env/src/body_mixin.ts b/v8env/src/body_mixin.ts index 1bb7a68..4ffd7fd 100644 --- a/v8env/src/body_mixin.ts +++ b/v8env/src/body_mixin.ts @@ -1,6 +1,6 @@ /** @module fly */ -import { parse as queryParse } from 'query-string' +import { parse as queryParse } from 'querystring' import { Blob, FormData, Body, ReadableStream, ReadableStreamReader, BodyInit } from './dom_types'; import { FlyBlob } from './blob'; import { FlyFormData } from './form_data'; @@ -30,7 +30,7 @@ export default class FlyBody implements Body { if (this.bodySource instanceof WhatWGReadableStream) { this.stream = this.bodySource } - if (typeof this.bodySource === "string" || this.bodySource instanceof Uint8Array) { + if (typeof this.bodySource === "string" || this.bodySource instanceof Uint8Array || this.bodySource instanceof ArrayBuffer) { const bodySource = this.bodySource this.stream = new WhatWGReadableStream({ start(controller: ReadableStreamDefaultController) { @@ -49,11 +49,11 @@ export default class FlyBody implements Body { } get isStatic(): boolean { - return (typeof this.bodySource === "string" || this.bodySource instanceof Uint8Array) + return (typeof this.bodySource === "string" || this.bodySource instanceof Uint8Array || this.bodySource instanceof ArrayBuffer) } - get staticBody(): Uint8Array { - if (this.bodySource instanceof Uint8Array) + get staticBody(): BufferSource { + if (this.bodySource instanceof Uint8Array || this.bodySource instanceof ArrayBuffer) return this.bodySource else if (typeof this.bodySource === "string") return new TextEncoder().encode(this.bodySource) diff --git a/v8env/src/bridge.ts b/v8env/src/bridge.ts index fe28138..61082a6 100644 --- a/v8env/src/bridge.ts +++ b/v8env/src/bridge.ts @@ -14,6 +14,7 @@ import { FlyResponse } from "./response"; import { ReadableStream, ReadableStreamSource, StreamStrategy } from "@stardazed/streams"; import { DNSRequest, DNSQuery, DNSResponse, DNSDataA, DNSDataAAAA, DNSDataCNAME, DNSDataMX, DNSDataNS, DNSDataPTR, DNSDataSOA, DNSDataSRV, DNSDataTXT } from './dns'; import { isAcmeChallengeRequest, handleAcmeChallenge } from "./acme"; +import { ServiceRequest, ServiceResponse } from "./service"; let nextCmdId = 1; // 0 is for events const promiseTable = new Map>(); @@ -85,7 +86,8 @@ export function addEventListener(name: string, fn: Function) { for (let i = 0; i < msg.headersLength(); i++) { const h = msg.headers(i); // console.log("header:", h.key(), h.value()); - headersInit.push([h.key(), h.value()]); + // Not null operators to appease the typescript gods. These should never be null as far as I can tell. + headersInit.push([h!.key()!, h!.value()!]); } let req = new FlyRequest(msg.url(), { @@ -106,6 +108,8 @@ export function addEventListener(name: string, fn: Function) { }) : null }) + req.remoteAddr = msg.remoteAddr(); + if (isAcmeChallengeRequest(req)) { handleAcmeChallenge(req) .then(res => handleRes(id, res)) @@ -178,6 +182,42 @@ export function addEventListener(name: string, fn: Function) { event_type = fbs.EventType.Resolv; break; } + case "serve": { + listenerTable.set(fbs.Any.ServiceRequest, (base: fbs.Base) => { + let msg = new fbs.ServiceRequest(); + base.msg(msg); + let id = msg.id(); + + const req = new ServiceRequest(msg.sender(), msg.data()); + + try { + fn.call(window, { + request: req, + respondWith(resfn: any) { + try { + let ret = resfn; + if (typeof ret === "function") { + ret = resfn(); + } + if (ret instanceof Promise) { + ret.then(handleServiceRes.bind(null, id)).catch(handleServiceError.bind(null, id)); + } else if (ret instanceof ServiceResponse) { + handleServiceRes(id, ret); + } + } catch (e) { + console.log("error in serve event respondWith"); + handleServiceError(id, e); + } + } + }) + } catch (e) { + console.log("error in serve event handler function"); + handleServiceError(id, e); + } + }) + event_type = fbs.EventType.Serve; + break; + } } const fbb = flatbuffers.createBuilder(); fbs.AddEventListener.startAddEventListener(fbb); @@ -327,6 +367,31 @@ function handleDNSRes(id: number, res: DNSResponse) { sendAsync(fbb, fbs.Any.DnsResponse, fbs.DnsResponse.endDnsResponse(fbb)); } +function handleServiceRes(id: number, res: ServiceResponse) { + const fbb = flatbuffers.createBuilder(); + + const fbsData = fbb.createString(res.dataJson); + + fbs.ServiceResponse.startServiceResponse(fbb); + fbs.ServiceResponse.addId(fbb, id); + fbs.ServiceResponse.addSuccess(fbb, true); + + fbs.ServiceResponse.addData(fbb, fbsData); + + sendAsync(fbb, fbs.Any.ServiceResponse, fbs.ServiceResponse.endServiceResponse(fbb)); +} + +function handleServiceError(id: number, err: Error) { + console.error("service error:", err.stack); + const fbb = flatbuffers.createBuilder(); + + fbs.ServiceResponse.startServiceResponse(fbb); + fbs.ServiceResponse.addId(fbb, id); + fbs.ServiceResponse.addSuccess(fbb, false); + + sendAsync(fbb, fbs.Any.ServiceResponse, fbs.ServiceResponse.endServiceResponse(fbb)); +} + function handleError(id: number, err: Error) { const fbb = flatbuffers.createBuilder(); @@ -341,21 +406,19 @@ function handleError(id: number, err: Error) { } export async function sendStreamChunks(id: number, stream: ReadableStream) { - console.debug("send stream chunk"); let reader = stream.getReader(); let cur = await reader.read() let done = false while (!done) { - console.debug("done?", cur.done, "typeof value:", typeof cur.value); - let value: ArrayBufferView; + let value: BufferSource; if (typeof cur.value === 'string') value = new TextEncoder().encode(cur.value) - else if (cur.value instanceof Uint8Array) + else if (cur.value instanceof Uint8Array || cur.value instanceof ArrayBuffer) value = cur.value - else if (typeof cur.value === 'undefined') + else if (typeof cur.value === 'undefined' || cur.value === null) value = undefined else - throw new TypeError("wrong body type") + throw new TypeError(`wrong body type: ${typeof cur.value} -> ${cur.value}`) sendStreamChunk(id, cur.done, value); if (cur.done) done = true @@ -364,7 +427,7 @@ export async function sendStreamChunks(id: number, stream: ReadableStream) { } } -export function sendStreamChunk(id: number, done: boolean, value?: ArrayBufferView) { +export function sendStreamChunk(id: number, done: boolean, value?: BufferSource) { const fbb = flatbuffers.createBuilder() fbs.StreamChunk.startStreamChunk(fbb) fbs.StreamChunk.addId(fbb, id); @@ -400,12 +463,12 @@ async function handleRes(id: number, res: FlyResponse) { fbs.HttpResponse.addHeaders(fbb, resHeaders); fbs.HttpResponse.addStatus(fbb, res.status); let resBody = res.body; - let hasBody = resBody != null && (!res.isStatic || res.isStatic && res.staticBody.length > 0) + let hasBody = resBody != null && (!res.isStatic || res.isStatic && res.staticBody.byteLength > 0) fbs.HttpResponse.addHasBody(fbb, hasBody) const resMsg = fbs.HttpResponse.endHttpResponse(fbb); - let staticBody: ArrayBufferView; + let staticBody: BufferSource; if (hasBody && res.isStatic) staticBody = res.staticBody sendSync(fbb, fbs.Any.HttpResponse, resMsg, staticBody); // sync so we can send body chunks when it's ready! @@ -425,7 +488,7 @@ export function sendAsync( fbb: flatbuffers.Builder, msgType: fbs.Any, msg: flatbuffers.Offset, - raw?: ArrayBufferView + raw?: BufferSource ): Promise { const [cmdId, resBuf] = sendInternal(fbb, msgType, msg, false, raw); util.assert(resBuf == null); @@ -439,7 +502,7 @@ export function sendSync( fbb: flatbuffers.Builder, msgType: fbs.Any, msg: flatbuffers.Offset, - raw?: ArrayBufferView + raw?: BufferSource ): null | fbs.Base { const [cmdId, resBuf] = sendInternal(fbb, msgType, msg, true, raw); util.assert(cmdId >= 0); @@ -459,7 +522,7 @@ function sendInternal( msgType: fbs.Any, msg: flatbuffers.Offset, sync = true, - raw?: ArrayBufferView + raw?: BufferSource ): [number, null | Uint8Array] { const cmdId = nextCmdId++; fbs.Base.startBase(fbb); diff --git a/v8env/src/cache.ts b/v8env/src/cache.ts index cf76b3a..b8b475e 100644 --- a/v8env/src/cache.ts +++ b/v8env/src/cache.ts @@ -6,7 +6,7 @@ import CachePolicy from 'http-cache-semantics' import { Request, Response } from './dom_types'; import { FlyResponse } from './response'; -import flyCache from "./fly/cache"; +import * as flyCache from "./fly/cache"; /** * export: @@ -76,8 +76,8 @@ const cache = { const ttl = Math.floor(policy.timeToLive() / 1000) if (policy.storable() && ttl > 0) { - await flyCache.set("httpcache:policy:" + key, JSON.stringify(policy.toObject()), ttl) - await flyCache.set("httpcache:body:" + key, res.body, ttl) + await flyCache.set("httpcache:policy:" + key, JSON.stringify(policy.toObject()), {ttl}) + await flyCache.set("httpcache:body:" + key, res.body, {ttl}) } } } diff --git a/v8env/src/console.ts b/v8env/src/console.ts index f6ac450..c25a883 100644 --- a/v8env/src/console.ts +++ b/v8env/src/console.ts @@ -1,142 +1,26 @@ -// tslint:disable-next-line:no-any -type ConsoleContext = Set; - -// tslint:disable-next-line:no-any -function getClassInstanceName(instance: any): string { - if (typeof instance !== "object") { - return ""; - } - if (instance && instance.__proto__ && instance.__proto__.constructor) { - return instance.__proto__.constructor.name; // could be "Object" or "Array" - } - return ""; -} - -// tslint:disable-next-line:no-any -function stringify(ctx: ConsoleContext, value: any): string { - switch (typeof value) { - case "string": - return value; - case "number": - case "boolean": - case "undefined": - case "symbol": - return String(value); - case "function": - if (value.name && value.name !== "anonymous") { - // from MDN spec - return `[Function: ${value.name}]`; - } - return "[Function]"; - case "object": - if (value === null) { - return "null"; - } - - if (ctx.has(value)) { - return "[Circular]"; - } - - ctx.add(value); - const entries: string[] = []; - - if (Array.isArray(value)) { - for (const el of value) { - entries.push(stringifyWithQuotes(ctx, el)); - } - - ctx.delete(value); - - if (entries.length === 0) { - return "[]"; - } - return `[ ${entries.join(", ")} ]`; - } else { - let baseString = ""; - - const className = getClassInstanceName(value); - let shouldShowClassName = false; - if (className && className !== "Object" && className !== "anonymous") { - shouldShowClassName = true; - } - - for (const key of Object.keys(value)) { - entries.push(`${key}: ${stringifyWithQuotes(ctx, value[key])}`); - } - - ctx.delete(value); - - if (entries.length === 0) { - baseString = "{}"; - } else { - baseString = `{ ${entries.join(", ")} }`; - } - - if (shouldShowClassName) { - baseString = `${className} ${baseString}`; - } - - return baseString; - } - default: - return "[Not Implemented]"; - } -} - -// Print strings when they are inside of arrays or objects with quotes -// tslint:disable-next-line:no-any -function stringifyWithQuotes(ctx: ConsoleContext, value: any): string { - switch (typeof value) { - case "string": - return `"${value}"`; - default: - return stringify(ctx, value); - } -} - -// tslint:disable-next-line:no-any -export function stringifyArgs(args: any[]): string { - const out: string[] = []; - for (const a of args) { - if (typeof a === "string") { - out.push(a); - } else { - // tslint:disable-next-line:no-any - out.push(stringify(new Set(), a)); - } - } - return out.join(" "); -} - -type PrintFunc = (level: number, msg: string) => void; - -const LogLevelError = 0 -const LogLevelWarn = 1 -const LogLevelInfo = 2 -const LogLevelDebug = 3 -const LogLevelTrace = 4 +import { Logger, Level } from "./logging"; export class Console { - constructor(private printFunc: PrintFunc) { } + constructor(private readonly logger: Logger) { } public error(...args: any[]): void { - this.printFunc(LogLevelError, stringifyArgs(args)) + this.logger.log(Level.AppError, ...args); } public warn(...args: any[]): void { - this.printFunc(LogLevelWarn, stringifyArgs(args)) + this.logger.log(Level.AppWarn, ...args); } public info(...args: any[]): void { - this.printFunc(LogLevelInfo, stringifyArgs(args)) + this.logger.log(Level.AppInfo, ...args); } public debug(...args: any[]): void { - this.printFunc(LogLevelDebug, stringifyArgs(args)) + this.logger.log(Level.AppDebug, ...args); } public trace(...args: any[]): void { - this.printFunc(LogLevelTrace, stringifyArgs(args)) + this.logger.log(Level.AppTrace, ...args); } public log = this.info; diff --git a/v8env/src/cookie_jar.ts b/v8env/src/cookie_jar.ts index 6469e63..0bc0d97 100644 --- a/v8env/src/cookie_jar.ts +++ b/v8env/src/cookie_jar.ts @@ -2,9 +2,9 @@ * @module fly * @private */ -import * as cookie from 'cookie' +import * as cookie from "cookie" -const cookieAttributeNames = ['Max-Age', 'Expires', 'HttpOnly', 'Secure', 'Path', 'SameSite', 'Domain'] +const cookieAttributeNames = ["Max-Age", "Expires", "HttpOnly", "Secure", "Path", "SameSite", "Domain"] /** * A jar for storing delicious cookies. @@ -17,18 +17,19 @@ class CookieJar { constructor(parent) { this.parent = parent - if (parent instanceof Request) - this.cookies = parseCookies(parent.headers.get("Cookie")) - else if (parent instanceof Response) - this.cookies = parseCookies(parent.headers.get("Set-Cookie")) + if (parent instanceof Request) { + this.cookies = parseCookies((parent.headers.get("Cookie") || "").split(";")) + } else if (parent instanceof Response) { + this.cookies = parseCookies((parent.headers.get("Set-Cookie") || "").split(",")) + } } /** * Gets a cookie by name * @param {String} name */ - get(name) { - return this.cookies.find((c) => c.name === name) + public get(name) { + return this.cookies.find(c => c.name === name) } /** @@ -37,36 +38,38 @@ class CookieJar { * @param {String} value * @param {Object} [options] */ - append(name, value, options) { + public append(name, value, options) { const cookieStr = cookie.serialize(name, value, options) this.cookies = this.cookies.concat(parseCookie(cookieStr)) - if (this.parent instanceof Request) + if (this.parent instanceof Request) { this.parent.headers.append("Cookie", cookieStr) - else if (this.parent instanceof Response) + } else if (this.parent instanceof Response) { this.parent.headers.append("Set-Cookie", cookieStr) + } } } function parseCookies(rawCookies) { let cookies = [] - for (let c of rawCookies) { + for (const c of rawCookies) { cookies = cookies.concat(parseCookie(c)) } return cookies } function parseCookie(cookieStr) { - let options = {} - let cookies = [] - let parsed = cookie.parse(cookieStr) - for (let k in parsed) { - if (cookieAttributeNames.indexOf(k) != -1) { + const options = {} + const cookies = [] + const parsed = cookie.parse(cookieStr) + // tslint:disable-next-line:forin + for (const k in parsed) { + if (cookieAttributeNames.indexOf(k) !== -1) { options[k] = parsed[k] continue } cookies.push({ name: k, value: parsed[k] }) } - return cookies.map((c) => Object.assign(c, options)) + return cookies.map(c => Object.assign(c, options)) } export { CookieJar } diff --git a/v8env/src/dev-tools.ts b/v8env/src/dev-tools.ts index 04fced1..d43a55a 100644 --- a/v8env/src/dev-tools.ts +++ b/v8env/src/dev-tools.ts @@ -1,16 +1,6 @@ -import { globalEval, GlobalEval } from "./global-eval"; +import { globalEval } from "./global-eval"; import { window } from "./globals"; - -export interface ConfigOptions { - globalEval: GlobalEval; - global: any; -} - -export interface DevTools { - run(path: string); -} - -export type initFn = (config: ConfigOptions) => DevTools; +import { initFn } from "./dev-tools/api"; declare var devTools: initFn | undefined; @@ -26,7 +16,7 @@ export function installDevTools() { if (typeof devTools === "undefined") { throw Error("Dev tools are not available in this environment"); } - window.dev = devTools({ + devTools(window, { global: window, globalEval }); diff --git a/v8env/src/dev-tools/api.ts b/v8env/src/dev-tools/api.ts new file mode 100644 index 0000000..9afeb3d --- /dev/null +++ b/v8env/src/dev-tools/api.ts @@ -0,0 +1,13 @@ +import { GlobalEval } from "src/global-eval"; + +export interface ConfigOptions { + globalEval: GlobalEval; + global: object; +} + +export interface DevTools { + run(path: string): void; + runTests(paths: string[]): void; +} + +export type initFn = (target: object, config: ConfigOptions) => DevTools; \ No newline at end of file diff --git a/v8env/src/dev-tools/assets.ts b/v8env/src/dev-tools/assets.ts index 213b413..3e72427 100644 --- a/v8env/src/dev-tools/assets.ts +++ b/v8env/src/dev-tools/assets.ts @@ -43,7 +43,8 @@ import libWebworkerImportscripts from "node_modules/typescript/lib/lib.webworker import libFlyRuntime from "lib.fly.runtime.d.ts!string"; -export const ContainerName = "$assets$"; +export const AssetsProtocol = "assets"; +export const ContainerName = AssetsProtocol + "://local/"; // < I had to include a host for the url parser to do what I wanted. // // @internal export const assetSourceCode: { [key: string]: string } = { diff --git a/v8env/src/dev-tools/compiler.ts b/v8env/src/dev-tools/compiler.ts index e5b19e7..dd49203 100644 --- a/v8env/src/dev-tools/compiler.ts +++ b/v8env/src/dev-tools/compiler.ts @@ -1,6 +1,6 @@ import * as ts from "typescript" -import { assert } from "./util" +import { assert, assertNotNull, assertNotNullOrUndef, assertNotUndef } from "./util" import { fetchModule } from "./resolver"; import { extname } from "./path"; import { ContainerName } from "./assets"; @@ -52,10 +52,21 @@ enum MediaType { Unknown } +const protocolPathPrefix: string = "protocol_"; +const hostPathPrefix: string = "host_"; + +export function originUrlToFileName(originUrl: string): string { + const parsedUrl = new URL(originUrl); + return "/" + protocolPathPrefix + parsedUrl.protocol + "/" + hostPathPrefix + parsedUrl.host + parsedUrl.pathname + parsedUrl.search + parsedUrl.hash; +}; + +export function fileNameToOriginUrl(fileName: string): string { + const fileNameParts = fileName.split("/"); + // These indexes had me a little confused at first. fileName should always start with a "/" so fileNameParts[0] = "" + return fileNameParts[1].replace(protocolPathPrefix, "") + "//" + fileNameParts[2].replace(hostPathPrefix, "") + "/" + fileNameParts.slice(3).join("/"); +} + class ModuleInfo implements ts.IScriptSnapshot { - public readonly moduleId: ModuleId; - public readonly fileName: ModuleFileName; - public version: number = 1; public inputCode: SourceCode = ""; public outputCode?: OutputCode; public exports = {}; @@ -63,14 +74,12 @@ class ModuleInfo implements ts.IScriptSnapshot { public factory?: AmdFactory; public gatheringDeps = false; public deps?: ModuleId[]; - public readonly mediaType: MediaType; - - public constructor(moduleId: ModuleId, fileName: ModuleFileName, version?: number, type?: MediaType) - { - this.moduleId = moduleId; - this.fileName = fileName; - this.version = version || 1; - this.mediaType = type; + + public constructor( + public readonly originUrl: string, + public version: number = 1, + public readonly mediaType: MediaType = MediaType.Unknown + ) { } reload() { @@ -94,25 +103,38 @@ class ModuleInfo implements ts.IScriptSnapshot { getChangeRange(oldSnapshot: ts.IScriptSnapshot): ts.TextChangeRange | undefined { return } + + get fileName(): string { + return originUrlToFileName(this.originUrl); + } } class ModuleCache { + // Maps module originUrl <==> ModuleInfo private readonly moduleIndex = new Map(); - public get(fileName: ModuleFileName): ModuleInfo { - const moduleInfo = this.moduleIndex.get(fileName); + public get(originUrl: string): ModuleInfo { + const moduleInfo = this.moduleIndex.get(originUrl); if (!moduleInfo) { - throw new Error(`Module ${fileName} not found`) + throw new Error(`Module ${originUrl} not found`) } return moduleInfo } + public getByFileName(fileName: string): ModuleInfo { + return this.get(fileNameToOriginUrl(fileName)); + } + public set(moduleInfo: ModuleInfo) { - this.moduleIndex.set(moduleInfo.fileName, moduleInfo); + this.moduleIndex.set(moduleInfo.originUrl, moduleInfo); } - public has(fileName: ModuleFileName): boolean { - return this.moduleIndex.has(fileName); + public has(originUrl: ModuleFileName): boolean { + return this.moduleIndex.has(originUrl); + } + + public keys(): Array { + return Array.from(this.moduleIndex.keys()); } } @@ -135,47 +157,60 @@ export class Compiler { this.globalEval = options.globalEval; } - public run(moduleSpecifier: ModuleSpecifier, containingFile: ContainingFile) { - trace("run()", { moduleSpecifier, containingFile }); - const moduleMetaData = this.resolveModule(moduleSpecifier, containingFile); + public run(specifierUrl: ModuleSpecifier, containingFile?: ContainingFile) { + trace("run()", { specifierUrl, containingFile }); + // Load entry point module and put it's file name in the scriptFileNames field as a new array + const moduleMetaData = this.resolveModule(specifierUrl, containingFile); this.scriptFileNames = [moduleMetaData.fileName]; + // If the module doesn't have any dependencies(hasn't been loaded before) instantiate it if (!moduleMetaData.deps) { this.instantiateModule(moduleMetaData); } + // this.drainRunQueue(); return moduleMetaData; } - public resolveModule(moduleSpecifier: string, containingFile: string): ModuleInfo { - trace("resolveModule()", { moduleSpecifier, containingFile }) - let fn = this.fileNameCache.get([moduleSpecifier, containingFile]); + public resolveModule(specifierUrl: string, refererOriginUrl?: string): ModuleInfo { + trace("resolveModule()", { specifierUrl, refererOriginUrl }) + // attempt to load module from cache + let fn = this.fileNameCache.get([specifierUrl, refererOriginUrl]); if (fn && this.moduleCache.has(fn)) { + // return if found return this.moduleCache.get(fn); } - let { moduleId, fileName, sourceCode } = fetchModule(moduleSpecifier, containingFile); + let { originUrl, loadedSource } = fetchModule(specifierUrl, refererOriginUrl); - if (!moduleId) { - throw new Error(`Failed to resolve '${moduleSpecifier}' from '${containingFile}'`) + // If module id is null or undef resolve failed. + if (!originUrl) { + throw new Error(`Failed to resolve '${specifierUrl}' from '${refererOriginUrl}'`); } - if (this.moduleCache.has(fileName)) { - return this.moduleCache.get(fileName) + // If module cache already contains module return it + if (this.moduleCache.has(originUrl)) { + return this.moduleCache.get(originUrl) } - const moduleInfo = new ModuleInfo(moduleId, fileName, 0, mediaType(moduleId)) - moduleInfo.inputCode = sourceCode - this.moduleCache.set(moduleInfo) - this.fileNameCache.set([moduleSpecifier, containingFile], fileName); - return moduleInfo + // Create new ModuleInfo object and fill it with info + const moduleInfo = new ModuleInfo(originUrl, 0, mediaType(originUrl)); + moduleInfo.inputCode = loadedSource.source; + // Put module into cache for the next guy to pick it up + this.moduleCache.set(moduleInfo); + this.fileNameCache.set([specifierUrl, refererOriginUrl], originUrl); + return moduleInfo; } - getModuleInfo(fileName: ModuleFileName): ModuleInfo { - if (this.moduleCache.has(fileName)) { - return this.moduleCache.get(fileName); + getModuleInfo(originUrl: string): ModuleInfo { + if (this.moduleCache.has(originUrl)) { + return this.moduleCache.get(originUrl); } - const moduleInfo = this.resolveModule(fileName, "") - this.moduleCache.set(moduleInfo) - return moduleInfo + const moduleInfo = this.resolveModule(originUrl); + this.moduleCache.set(moduleInfo); + return moduleInfo; + } + + getModuleInfoByFileName(fileName: string): ModuleInfo { + return this.getModuleInfo(fileNameToOriginUrl(fileName)); } /** @@ -183,19 +218,22 @@ export class Compiler { * cache the result. Re-compilation can be forced using '--recompile' flag. */ compile(moduleInfo: ModuleInfo): OutputCode { + trace("compile()", { moduleInfo }); const recompile = false; // only relevant for persistent cache + // If module already has ouputCode return that(Nothing to compile). if (!recompile && moduleInfo.outputCode) { return moduleInfo.outputCode; } - const { fileName, inputCode, moduleId } = moduleInfo; + const { originUrl, inputCode, fileName } = moduleInfo; const output = this.languageService.getEmitOutput(fileName); - // Get the relevant diagnostics - this is 3x faster than + // Get the relevant diagnosetics - this is 3x faster than // `getPreEmitDiagnostics`. const diagnostics = [ ...this.languageService.getCompilerOptionsDiagnostics(), ...this.languageService.getSyntacticDiagnostics(fileName), ...this.languageService.getSemanticDiagnostics(fileName) ]; + // If the language service reports log error and throw. if (diagnostics.length > 0) { const errMsg = ts.formatDiagnosticsWithColorAndContext(diagnostics, diagnosticHost); console.error("Compiler error", { errMsg }); @@ -213,6 +251,7 @@ export class Compiler { "Only single file should be output." ); + const [outputFile] = output.outputFiles; const outputCode = (moduleInfo.outputCode = `${ outputFile.text @@ -220,12 +259,13 @@ export class Compiler { moduleInfo.version = 1; // write to persistent cache // this._os.codeCache(fileName, sourceCode, outputCode); + // Return compiled code. return moduleInfo.outputCode; } public transform(moduleId: string): string { trace("transform()", { moduleId }); - const moduleMetaData = this.resolveModule(moduleId, ""); + const moduleMetaData = this.resolveModule(moduleId); this.scriptFileNames = [moduleId]; return this.compile(moduleMetaData) } @@ -237,12 +277,14 @@ export class Compiler { drainRunQueue(): void { trace( "drainRunQueue()", - this.runQueue.map(moduleInfo => moduleInfo.moduleId) + this.runQueue.map(moduleInfo => moduleInfo.originUrl) ); + // For each module in the runQueue let moduleMetaData: ModuleInfo | undefined; while ((moduleMetaData = this.runQueue.shift())) { - assert( - moduleMetaData.factory != null, + // Error if module has no factory or factory is null + assertNotNullOrUndef( + moduleMetaData.factory, "Cannot run module without factory." ); assert(moduleMetaData.hasRun === false, "Module has already been run."); @@ -257,7 +299,7 @@ export class Compiler { * just add the module factory to the run queue. */ instantiateModule(moduleInfo: ModuleInfo): void { - trace("instantiateModule()", moduleInfo.moduleId); + trace("instantiateModule()", moduleInfo.originUrl); // if the module has already run, we can short circuit. // it is intentional though that if we have already resolved dependencies, @@ -268,6 +310,9 @@ export class Compiler { return; } + /** + * I assume the global part has some use but it may be not longer be needed + */ this.global.define = this.makeDefine(moduleInfo); this.globalEval(this.compile(moduleInfo)); this.global.define = undefined; @@ -281,6 +326,7 @@ export class Compiler { if (!moduleMetaData.deps) { throw new Error("Cannot get arguments until dependencies resolved."); } + // For each dependency return moduleMetaData.deps.map(dep => { if (dep === "require") { return this.makeLocalRequire(moduleMetaData); @@ -291,7 +337,7 @@ export class Compiler { // if (dep in DenoCompiler._builtins) { // return DenoCompiler._builtins[dep]; // } - const dependencyMetaData = this.getModuleInfo(dep); + const dependencyMetaData = this.getModuleInfoByFileName(dep); assert(dependencyMetaData != null, `Missing dependency "${dep}".`); // TypeScript does not track assert, therefore using not null operator return dependencyMetaData!.exports; @@ -308,7 +354,7 @@ export class Compiler { // when there are circular dependencies, we need to skip recursing the // dependencies moduleInfo.gatheringDeps = true; - // we will recursively resolve the dependencies for any modules + // we will recursively resolve the dependencies for any modules and store them as file names moduleInfo.deps = deps.map(dep => { if ( dep === "require" || @@ -317,12 +363,15 @@ export class Compiler { ) { return dep; } - const dependencyMetaData = this.resolveModule(dep, moduleInfo.fileName); + // Resolve the dependency and instantiate it if not currently gathering deps to avoid loading deps more than once + const dependencyMetaData = this.resolveModule(dep, moduleInfo.originUrl); if (!dependencyMetaData.gatheringDeps) { this.instantiateModule(dependencyMetaData); } + // Return the resolved dep's fileName return dependencyMetaData.fileName; }); + // Remove gatheringDeps lock and if the runQueue doesn't already contain this module add it. moduleInfo.gatheringDeps = false; if (!this.runQueue.includes(moduleInfo)) { this.runQueue.push(moduleInfo); @@ -340,14 +389,14 @@ export class Compiler { callback: AmdCallback, errback: AmdErrback ): void => { - console.log("compiler.makeLocalRequire()", { moduleInfo, deps }); + console.trace("compiler.makeLocalRequire()", { moduleInfo, deps }); assert( deps.length === 1, "Local require requires exactly one dependency." ); const [moduleSpecifier] = deps; try { - const requiredMetaData = this.run(moduleSpecifier, moduleInfo.fileName); + const requiredMetaData = this.run(moduleSpecifier, moduleInfo.originUrl); callback(requiredMetaData.exports); } catch (e) { errback(e); @@ -361,11 +410,12 @@ const settings: ts.CompilerOptions = { module: ts.ModuleKind.AMD, // module: ts.ModuleKind.ESNext, outDir: "$fly$", + baseUrl: "", inlineSourceMap: true, inlineSources: true, stripComments: true, - target: ts.ScriptTarget.ESNext -} + target: ts.ScriptTarget.ESNext, +}; function createLanguageService(compiler: Compiler): ts.LanguageService { return ts.createLanguageService({ @@ -377,7 +427,7 @@ function createLanguageService(compiler: Compiler): ts.LanguageService { }, getScriptVersion(fileName: string): string { trace("getScriptVersion()", { fileName }) - const moduleInfo = compiler.getModuleInfo(fileName); + const moduleInfo = compiler.getModuleInfoByFileName(fileName); if (!moduleInfo) { return "" } @@ -385,7 +435,7 @@ function createLanguageService(compiler: Compiler): ts.LanguageService { }, getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined { trace("getScriptSnapshot()", { fileName }) - return compiler.getModuleInfo(fileName) + return compiler.getModuleInfoByFileName(fileName); }, getCurrentDirectory(): string { return "" @@ -393,7 +443,7 @@ function createLanguageService(compiler: Compiler): ts.LanguageService { getDefaultLibFileName(options: ts.CompilerOptions): string { trace("getDefaultLibFileName()"); const moduleSpecifier = "lib.fly.runtime.d.ts"; - const moduleInfo = compiler.resolveModule(moduleSpecifier, ContainerName); + const moduleInfo = compiler.resolveModule(ContainerName + moduleSpecifier); return moduleInfo.fileName; }, getNewLine: (): string => { @@ -412,16 +462,16 @@ function createLanguageService(compiler: Compiler): ts.LanguageService { trace("resolveModuleNames()", { moduleNames, containingFile, reusedNames }); return moduleNames.map(moduleName => { - const moduleInfo = compiler.resolveModule(moduleName, containingFile) + const moduleInfo = compiler.resolveModule(moduleName, fileNameToOriginUrl(containingFile)) // an empty string will cause typescript to bomb, maybe fail here instead? - const resolvedFileName = moduleInfo && moduleInfo.moduleId || "" - const isExternal = false; // need cwd/cjs logic for this maybe? - return { resolvedFileName, isExternal } + const resolvedFileName = moduleInfo && moduleInfo.fileName || "" + const isExternalLibraryImport = false; // need cwd/cjs logic for this maybe? + return { resolvedFileName, isExternalLibraryImport } }) }, getScriptKind(fileName: string): ts.ScriptKind { trace("getScriptKind()", { fileName }); - const moduleMetaData = compiler.getModuleInfo(fileName); + const moduleMetaData = compiler.getModuleInfoByFileName(fileName); if (moduleMetaData) { switch (moduleMetaData.mediaType) { case MediaType.TypeScript: @@ -441,7 +491,8 @@ function createLanguageService(compiler: Compiler): ts.LanguageService { return true; }, fileExists(path: string): boolean { - const info = compiler.getModuleInfo(path); + console.trace("Typescript ls doing file exists check."); + const info = compiler.getModuleInfoByFileName(path); const exists = info != null; trace("fileExists()", { path, exists }); return exists; @@ -456,8 +507,8 @@ const diagnosticHost: ts.FormatDiagnosticsHost = { } // TODO: move this to resolver? -function mediaType(moduleId): MediaType { - switch (extname(moduleId)) { +function mediaType(originUrl): MediaType { + switch (extname(originUrl)) { case ".ts": return MediaType.TypeScript; case ".js": return MediaType.JavaScript; case ".json": return MediaType.Json; diff --git a/v8env/src/dev-tools/index.ts b/v8env/src/dev-tools/index.ts index 1dce15b..d103e30 100644 --- a/v8env/src/dev-tools/index.ts +++ b/v8env/src/dev-tools/index.ts @@ -1,6 +1,7 @@ import { Compiler } from "./compiler"; -import { ConfigOptions, DevTools } from "../dev-tools"; - +import { run, globals, loadSuite, printSuiteError } from "./testing"; +import { DevTools, ConfigOptions } from "./api"; +import { exit } from "../os"; class FlyDevTools implements DevTools { private compiler: Compiler; @@ -13,14 +14,31 @@ class FlyDevTools implements DevTools { } run(path: string) { - console.log(`RUN!`, { path }); - this.compiler.run(path, "."); + this.compiler.run(path); + } + + runTests(paths: string[]) { + for (const suitePath of paths) { + loadSuite(suitePath); + try { + this.compiler.run(suitePath); + } catch (err) { + printSuiteError(suitePath, err); + exit(1); + } + } + run() } } /** * Install the fly development tools into the current runtime. */ -export default function init(config: ConfigOptions): DevTools { - return new FlyDevTools(config); +export default function init(target: object, config: ConfigOptions) { + const devTools = new FlyDevTools(config); + + Object.assign(target, { + dev: devTools, + ...globals + }); } \ No newline at end of file diff --git a/v8env/src/dev-tools/resolver.ts b/v8env/src/dev-tools/resolver.ts index 581b0a8..ce880b5 100644 --- a/v8env/src/dev-tools/resolver.ts +++ b/v8env/src/dev-tools/resolver.ts @@ -1,32 +1,42 @@ -import { assetSourceCode, ContainerName } from "./assets"; +import { assetSourceCode, ContainerName, AssetsProtocol } from "./assets"; import { assert } from "./util"; -import { loadModule } from "../module_loader"; +import { loadModule, LoadedModule } from "../module_loader"; +import { URL } from "../url"; -interface LoadModuleResult { - moduleId: string, - fileName: string, - sourceCode: string, -} - -export function fetchModule(moduleSpecifier: string, containingFile: string): LoadModuleResult | null { - console.trace("[resolver] fetchModule()", { moduleSpecifier, containingFile }); - if (isAsset(moduleSpecifier, containingFile)) { - let moduleId = moduleSpecifier.split("/").pop()!; - const assetName = moduleId.includes(".") ? moduleId : `${moduleId}.d.ts`; +export function fetchModule(specifierUrl: string, refererOriginUrl?: string): LoadedModule { + console.trace("[resolver] fetchModule()", { specifierUrl, refererOriginUrl }); + // If module is a "asset" I.E. lib.dom.d.ts + if (isAsset(specifierUrl, refererOriginUrl)) { + const parsedUrl = new URL(specifierUrl, refererOriginUrl); + // Remove the path from the specifier + let moduleFileName = parsedUrl.pathname.split("/").pop()!; + /** + * Not completely sure of the reason for this other than maybe if specifier is just "lib" every other library has at least one "." before the .d.ts. + * "lim.dom" would not become "lib.dom.d.ts" this might be a bug. + */ + const assetName = moduleFileName.includes(".") ? moduleFileName : `${moduleFileName}.d.ts`; + // Check for asset in assetSourceCode object if not error assert(assetName in assetSourceCode, `No such asset "${assetName}"`); + console.trace(`Finished asset module fetch ${parsedUrl.toString()}`); + + // Return LoadModuleResult with asset source code return { - moduleId: `${ContainerName}/${assetName}`, - fileName: `${ContainerName}/${assetName}`, - sourceCode: assetSourceCode[assetName] - } + originUrl: parsedUrl.toString(), + loadedSource: { + isWasm: false, + source: assetSourceCode[assetName], + }, + }; } - - return loadModule(moduleSpecifier, containingFile); + + console.trace(`Finished module fetch ${specifierUrl} from ${refererOriginUrl}`); + // Use std loadModule function to load module + return loadModule(specifierUrl, refererOriginUrl); } -function isAsset(moduleSpecifier: string, containingFile: string): boolean { - return moduleSpecifier.startsWith(ContainerName) || - containingFile.startsWith(ContainerName); +function isAsset(specifierUrl: string, refererOriginUrl: string): boolean { + const parsedUrl = new URL(specifierUrl, refererOriginUrl); // << This might need a little more testing I'm not sure how this will handle some relative specifiers. + return (parsedUrl.protocol === (AssetsProtocol + ":")); } diff --git a/v8env/src/dev-tools/testing.ts b/v8env/src/dev-tools/testing.ts new file mode 100644 index 0000000..ec24902 --- /dev/null +++ b/v8env/src/dev-tools/testing.ts @@ -0,0 +1,411 @@ +import { stringifyTypeName } from "../util/format"; +import { filterStackTrace } from "../source_maps"; +import { isError } from "../util"; +import { expect } from "chai/lib/chai.js"; +import { exit } from "../os"; + +export type DoneFn = (err?: any) => void; +export type RunnableFn = (done?: DoneFn) => Promise | void; + +export type ScopeFn = () => void; + +const DefaultTimeout = 5000; + +interface TestDefinition { + name: string; + fn: RunnableFn; + skip?: boolean; + only?: boolean; + parent: GroupDefinition; + timeout: number; +} + +interface GroupDefinition { + name: string; + parent?: GroupDefinition; + groups: GroupDefinition[]; + tests: TestDefinition[]; + beforeAll: RunnableFn[]; + afterAll: RunnableFn[]; + beforeEach: RunnableFn[]; + afterEach: RunnableFn[]; +} + +export function test(name: string, fn: RunnableFn, timeout: number = DefaultTimeout) { + currentGroup().tests.push({ name, fn, parent: currentGroup(), timeout }); +} + +test.skip = (name: string, fn: RunnableFn, timeout: number = DefaultTimeout) => { + currentGroup().tests.push({ name, fn, skip: true, parent: currentGroup(), timeout }); +} + +test.only = (name: string, fn: RunnableFn, timeout: number = DefaultTimeout) => { + currentGroup().tests.push({ name, fn, only: true, parent: currentGroup(), timeout }); +} + +function beforeAll(fn: RunnableFn) { + currentGroup().beforeAll.push(fn); +} + +function beforeEach(fn: RunnableFn) { + currentGroup().beforeEach.push(fn); +} + +function afterEach(fn: RunnableFn) { + currentGroup().afterEach.push(fn); +} + +function afterAll(fn: RunnableFn) { + currentGroup().afterAll.push(fn); +} + +export function describe(name: string, scopeFn: ScopeFn) { + const group = makeGroup(name); + group.parent = currentGroup(); + pushGroup(group); + scopeFn(); + popGroup(); + currentGroup().groups.push(group); +} + +export const globals = { + describe, + test, + it: test, + beforeAll, + beforeEach, + afterAll, + afterEach, + before: beforeAll, + after: afterAll, + expect, +}; + +export function loadSuite(suitePath: string) { + beginSuite(suitePath); +} + +export async function run() { + const runner = new Runner(suites); + + try { + await runner.run(); + } catch (error) { + printBlankLines(2); + printError(error, 2); + + exit(1); + } + + const { passed, failed, skipped } = runner.stats; + + printBlankLines(2); + + print(2, color(Style.green, `${passed} passing`)); + if (failed > 0) { + print(2, color(Style.red, `${failed} failing`)); + } + if (skipped > 0) { + print(2, color(Style.yellow, `${skipped} skipped`)); + } + + printBlankLines(2); + + printFailures(runner.failures); + + if (failed > 0) { + exit(1); + } +} + +interface TestFailure { + index: number; + test: TestDefinition; + error: Error; +} + +export class Runner { + private passed = 0; + private failed = 0; + private skipped = 0; + + public readonly failures: TestFailure[] = []; + + constructor(public suites: GroupDefinition[]) { } + + public get stats() { + return { + passed: this.passed, + failed: this.failed, + skipped: this.skipped, + }; + } + + public async run() { + for (const suite of this.suites) { + await this.runGroup(suite); + } + } + + async runGroup(group: GroupDefinition) { + const depth = path(group).length; + print(depth, color(Style.groupName, group.name)); + + for (const hook of group.beforeAll) { + await this.runHook(hook) + .catch(error => { + print(depth, color(Style.red, "Error running beforeAll hook")); + throw error; + }); + } + + for (const test of group.tests) { + for (const hook of group.beforeEach) { + await this.runHook(hook) + .catch(error => { + print(depth, color(Style.red, "Error running beforeEach hook")); + throw error; + }); + } + + await this.runTest(test); + + for (const hook of group.afterEach) { + await this.runHook(hook) + .catch(error => { + print(depth, color(Style.red, "Error running afterEach hook")); + throw error; + }); + } + } + + for (const test of group.groups) { + for (const hook of group.beforeEach) { + await this.runHook(hook) + .catch(error => { + print(depth, color(Style.red, "Error running beforeEach hook")); + throw error; + }); + } + + await this.runGroup(test); + + for (const hook of group.afterEach) { + await this.runHook(hook) + .catch(error => { + print(depth, color(Style.red, "Error running afterEach hook")); + throw error; + }); + } + } + for (const hook of group.afterAll) { + await this.runHook(hook) + .catch(error => { + print(depth, color(Style.red, "Error running afterAll hook")); + throw error; + }); + } + } + + runHook(fn: RunnableFn): Promise { + return callFn(fn, DefaultTimeout); + } + + async runTest(test: TestDefinition): Promise { + const depth = path(test).length; + + if (test.skip) { + this.skipped++; + print(depth, `${color(Style.yellow, "○")} ${color(Style.dim, test.name)}`); + return Promise.resolve(); + } + + return callFn(test.fn, test.timeout) + .then(() => { + this.passed++; + print(depth, `${color(Style.green, "✓")} ${color(Style.dim, test.name)}`); + }) + .catch(error => { + this.failed++; + const failure = this.recordFailure(test, error); + const msg = `${failure.index}) ${test.name}`; + print(depth, color(Style.red, msg)); + }); + } + + recordFailure(test: TestDefinition, error: unknown) { + const index = this.failures.length + 1; + + const failure = { + index, + test, + error: isError(error) ? error : normalizeReason(error), + }; + + this.failures.push(failure); + return failure; + } +} + +function print(depth: number, msg: string) { + (window as any).logger.print(" ".repeat(depth) + msg); +} + +let suites: GroupDefinition[] = []; + +let root = makeGroup("") +let groupStack = [root]; + +function beginSuite(name: string) { + const suiteRoot = makeGroup(name); + suites.push(suiteRoot); + groupStack = [suiteRoot]; +} + +// function endSuite() { +// groupStack = []; +// } + +function pushGroup(group: GroupDefinition) { + groupStack.push(group); +} + +function popGroup() { + if (groupStack.length === 1) { + throw new Error("cannot pop root group"); + } + groupStack.pop(); +} + +function currentGroup() { + return groupStack[groupStack.length - 1]; +} + +function makeGroup(name: string): GroupDefinition { + return { + name, + tests: [], + groups: [], + beforeAll: [], + afterAll: [], + beforeEach: [], + afterEach: [], + }; +} + +function callFn(fn: RunnableFn, timeout: number ): Promise { + let timeoutId: number; + return new Promise((resolve, reject) => { + timeoutId = setTimeout( + () => reject(new TestTimeoutError(fn)), + timeout + ); + + // fn expects a done callback + if (fn.length) { + const done = (reason?: Error | string) => { + return reason ? reject(reason) : resolve(); + } + + return fn(done); + } + + let returnVal: any; + try { + returnVal = fn(); + } catch (error) { + return reject(error); + } + + // if fn returns a promise, return it + if (typeof returnVal === "object" && returnVal !== null && typeof returnVal.then === "function") { + return returnVal.then(resolve, reject); + } + + // test is a synchronous function, and if we got here it passed + return resolve(); + }).then(() => { + clearTimeout(timeoutId); + }).catch(error => { + clearTimeout(timeoutId); + throw error; + }); +} + +const enum Style { + pass = 90, + fail = 31, + + yellow = 33, + + groupName = 0, + red = 31, + green = 32, + dim = 90, +} + +function color(style: Style, msg: string) { + return '\x1b[' + style + 'm' + msg + '\x1b[0m'; +} + +function printFailures(failures: TestFailure[]) { + for (const failure of failures) { + print(2, color(Style.red, `${failure.index}) ${failure.test.name}`)); + + printError(failure.error, 2) + + print(0, ""); + } +} + +export function printSuiteError(suitePath: string, error: Error) { + print(2, color(Style.red, `Error loading suite ${suitePath}`)); + + printError(error, 3); +} + +export function printError(error: Error, depth: number = 0) { + if (error.stack) { + const filteredStackTrace = filterStackTrace(error.stack); + if (filteredStackTrace) { + print(depth, color(Style.dim, filteredStackTrace)); + } + } else if (error.message) { + print(depth, color(Style.dim, error.message)); + } else { + print(depth, color(Style.dim, error.toString())); + } +} + +function normalizeReason(err: any) { + return new Error( + `the ${stringifyTypeName(err)} ${JSON.stringify(err)} was thronw, throw an Error :)` + ); +} + +function printBlankLines(count = 1) { + print(0, "\n".repeat(count - 1)); +} + +function path(testOrGroup: TestDefinition | GroupDefinition): Array { + if (testOrGroup.parent) { + return [...path(testOrGroup.parent), testOrGroup]; + } + return [testOrGroup]; +} + +export class HookError extends Error { + constructor() { + super("Error running hook"); + } +} + +export class TestTimeoutError extends Error { + constructor(fn: RunnableFn) { + if (fn.length) { + super("Timeout. Make sure this test is calling the `done` callback!"); + } else { + super("Timeout"); + } + } +} diff --git a/v8env/src/dev-tools/util.ts b/v8env/src/dev-tools/util.ts index 7c81e33..e82c5f7 100644 --- a/v8env/src/dev-tools/util.ts +++ b/v8env/src/dev-tools/util.ts @@ -2,4 +2,25 @@ export function assert(cond: boolean, msg = "assert") { if (!cond) { throw Error(msg); } +} + +export function assertNotNull(value: T | null, msg = "assert not null"): value is T { + if (value === null) { + throw Error(msg); + } + return true; +} + +export function assertNotUndef(value: T | undefined, msg = "assert not undefined"): value is T { + if (typeof value === "undefined") { + throw Error(msg); + } + return true; +} + +export function assertNotNullOrUndef(value: T | null | undefined, msg = "assert not null or undefined"): value is T { + if (!assertNotUndef(value, msg) || !assertNotNull(value, msg)) { + throw Error(msg); + } + return true; } \ No newline at end of file diff --git a/v8env/src/fetch.ts b/v8env/src/fetch.ts index 556b593..71fc61b 100644 --- a/v8env/src/fetch.ts +++ b/v8env/src/fetch.ts @@ -1,14 +1,12 @@ /** * @module fetch */ -import { RequestInit, RequestInfo, HeadersInit } from './dom_types'; +import { RequestInit, RequestInfo } from './dom_types'; import { FlyResponse } from './response'; import { FlyRequest } from './request'; -import { sendAsync, sendSync, streams, sendStreamChunks } from './bridge'; +import { sendAsync, streams, sendStreamChunks } from './bridge'; import * as fbs from "./msg_generated"; -import * as errors from "./errors"; -import * as util from "./util"; import * as flatbuffers from "./flatbuffers" import { ReadableStream } from '@stardazed/streams'; @@ -74,10 +72,10 @@ export function fetch(info: RequestInfo, init?: FlyRequestInit): Promise 0); + let hasBody = reqBody != null && (!req.isStatic || req.isStatic && req.staticBody.byteLength > 0); fbs.HttpRequest.addHasBody(fbb, hasBody); - let staticBody: ArrayBufferView; + let staticBody: BufferSource; if (hasBody && req.isStatic) staticBody = req.staticBody diff --git a/v8env/src/fly/cache/global.ts b/v8env/src/fly/cache/global.ts index 452542b..892e85b 100644 --- a/v8env/src/fly/cache/global.ts +++ b/v8env/src/fly/cache/global.ts @@ -13,11 +13,11 @@ * * @module fly/cache/global */ -/** */ -// declare var bridge: any + import { sendAsync } from '../../bridge' import * as fbs from "../../msg_generated"; import * as flatbuffers from "../../flatbuffers"; + /** * Notifies all caches to delete data at the specified key. * @param key the key to delete @@ -49,8 +49,3 @@ export async function purgeTag(tag: string): Promise { return true }) } - -export default { - del, - purgeTag -} \ No newline at end of file diff --git a/v8env/src/fly/cache/index.ts b/v8env/src/fly/cache/index.ts index 1c578ac..f5637b3 100644 --- a/v8env/src/fly/cache/index.ts +++ b/v8env/src/fly/cache/index.ts @@ -17,10 +17,16 @@ * @module fly/cache */ -/** */ import { sendAsync, streams, sendStreamChunks, sendStreamChunk } from '../../bridge' import * as fbs from "../../msg_generated"; import * as flatbuffers from "../../flatbuffers"; +import { ReadableStream as WhatWGReadableStream } from '@stardazed/streams'; +import { bufferFromStream } from '../../body_mixin'; +import { ReadableStream } from '../../dom_types'; +import { isIterable } from '../../util'; +import * as global from "./global"; + +export { global }; export interface CacheSetOptions { ttl?: number; @@ -55,8 +61,6 @@ export function getStream(key: string): Promise { return _get(key).then(raw => raw[0]) } - - function _get(key: string): Promise<[ReadableStream | null, string | null]> { const fbb = flatbuffers.createBuilder() const keyFbs = fbb.createString(key); @@ -95,14 +99,34 @@ export function getString(key: string): Promise { }) } +/** + * Get multiple values from the cache. + * @param keys list of keys to retrieve + * @returns List of results in the same order as the provided keys + */ +export function getMulti(keys: string[] | IterableIterator): Promise> { + if (isIterable(keys)) { + keys = Array.from(keys); + } + return Promise.all(keys.map(get)); +} + +/** + * Get multiple string values from the cache + * @param keys list of keys to retrieve + * @returns list of results in the same order as the provided keys + */ +export async function getMultiString(keys: string[]): Promise> { + return Promise.all(keys.map(getString)); +} + /** * Sets a value at the specified key, with an optional ttl * @param key The key to add or overwrite * @param value Data to store at the specified key, up to 2MB - * @param ttl Time to live (in seconds) * @returns true if the set was successful */ -export function set(key: string, value: string | ArrayBuffer | ArrayBufferView | WhatWGReadableStream, options?: CacheSetOptions | number): Promise { +export function set(key: string, value: string | ArrayBuffer | ArrayBufferView | WhatWGReadableStream, options?: CacheSetOptions): Promise { // TODO: validate value input const fbb = flatbuffers.createBuilder() @@ -111,7 +135,7 @@ export function set(key: string, value: string | ArrayBuffer | ArrayBufferView | let tags: number; let meta: number; - if (typeof options === 'object') { + if (options != null && typeof options === 'object') { if (Array.isArray(options.tags)) tags = fbs.CacheSet.createTagsVector(fbb, options.tags.map(t => fbb.createString(t))); if (typeof options.meta === 'string') @@ -120,14 +144,12 @@ export function set(key: string, value: string | ArrayBuffer | ArrayBufferView | fbs.CacheSet.startCacheSet(fbb); fbs.CacheSet.addKey(fbb, keyFbb); - - if (typeof options === 'number') // TODO: maybe we don't need multiple ways of doing this - fbs.CacheSet.addTtl(fbb, options) - else if (typeof options === 'object' && typeof options.ttl === 'number') + if (typeof options === 'object' && typeof options.ttl === 'number') { fbs.CacheSet.addTtl(fbb, options.ttl) - - if (typeof meta != 'undefined') + } + if (typeof meta !== 'undefined') { fbs.CacheSet.addMeta(fbb, meta); + } fbs.CacheSet.addTags(fbb, tags); return sendAsync(fbb, fbs.Any.CacheSet, fbs.CacheSet.endCacheSet(fbb)).then(async baseMsg => { @@ -235,37 +257,3 @@ export function del(key: string) { return true }) } - -/** - * A library for caching/retrieving Response objects - * - * See {@link fly/cache/response} - */ -// export { default as responseCache } from "./response" - -/** - * API for sending global cache notifications - * - * See {@link fly/cache/global} - */ -import { default as global } from "./global" -import { ReadableStream as WhatWGReadableStream } from '@stardazed/streams'; -import { bufferFromStream } from '../../body_mixin'; -import { ReadableStream } from '../../dom_types'; - -const cache = { - get, - getString, - getStream, - getEntry, // w/ meta - // getMulti, - // getMultiString, - set, - setMeta, - expire, - del, - global, - setTags, - purgeTag, -} -export default cache \ No newline at end of file diff --git a/v8env/src/fly/data.ts b/v8env/src/fly/data.ts index 8a8e2e8..6a3952c 100644 --- a/v8env/src/fly/data.ts +++ b/v8env/src/fly/data.ts @@ -5,11 +5,9 @@ * @module fly/data */ -import { assert } from "../util"; -import * as util from "../util"; import * as fbs from "../msg_generated"; import * as flatbuffers from "../flatbuffers"; -import { sendSync, sendAsync } from "../bridge"; +import { sendAsync } from "../bridge"; /** * A collection of keys and values. @@ -30,7 +28,11 @@ export class Collection { * @param key key for data * @param obj value to store */ - put(key: string, obj: string): Promise { + async put(key: string, obj: any): Promise { + if (typeof obj === "number" || obj === undefined || obj === null) { + throw new TypeError("value must be a string, object, or array"); + } + const fbb = flatbuffers.createBuilder(); const fbbColl = fbb.createString(this.name); const fbbKey = fbb.createString(key); @@ -39,9 +41,10 @@ export class Collection { fbs.DataPut.addCollection(fbb, fbbColl); fbs.DataPut.addKey(fbb, fbbKey); fbs.DataPut.addJson(fbb, fbbObj); - return sendAsync(fbb, fbs.Any.DataPut, fbs.DataPut.endDataPut(fbb)).then(_baseRes => { - return true - }) + + await sendAsync(fbb, fbs.Any.DataPut, fbs.DataPut.endDataPut(fbb)); + + return true; } /** @@ -79,21 +82,37 @@ export class Collection { return true }) } -} -const data = { - collection(name: string) { - return new Collection(name) - }, - dropCollection(name: string): Promise { + increment(key: string, field: string, amount?: number): Promise { const fbb = flatbuffers.createBuilder(); const fbbColl = fbb.createString(this.name); - fbs.DataDropCollection.startDataDropCollection(fbb); - fbs.DataDropCollection.addCollection(fbb, fbbColl); - return sendAsync(fbb, fbs.Any.DataDropCollection, fbs.DataDropCollection.endDataDropCollection(fbb)).then(_baseRes => { + const fbbKey = fbb.createString(key); + const fbbField = fbb.createString(field); + fbs.DataIncr.startDataIncr(fbb); + fbs.DataIncr.addCollection(fbb, fbbColl); + fbs.DataIncr.addKey(fbb, fbbKey); + fbs.DataIncr.addField(fbb, fbbField); + fbs.DataIncr.addAmount(fbb, amount || 1); + return sendAsync(fbb, fbs.Any.DataIncr, fbs.DataIncr.endDataIncr(fbb)).then(_baseRes => { return true }) } } -export default data; \ No newline at end of file +export function collection(name: string) { + return new Collection(name) +} + +export function dropCollection(name: string): Promise { + const fbb = flatbuffers.createBuilder(); + const fbbColl = fbb.createString(name); + fbs.DataDropCollection.startDataDropCollection(fbb); + fbs.DataDropCollection.addCollection(fbb, fbbColl); + return sendAsync(fbb, fbs.Any.DataDropCollection, fbs.DataDropCollection.endDataDropCollection(fbb)).then(_baseRes => { + return true + }) +} + +function assertValueType(val: any) { + // if (val === ) +} diff --git a/v8env/src/fly/image/index.ts b/v8env/src/fly/image/index.ts index 1bb1374..c916fc3 100644 --- a/v8env/src/fly/image/index.ts +++ b/v8env/src/fly/image/index.ts @@ -1,4 +1,4 @@ -import { sendAsync, streams, sendStreamChunks, sendStreamChunk } from '../../bridge' +import { sendAsync, streams, sendStreamChunks } from '../../bridge' import * as fbs from "../../msg_generated"; import * as flatbuffers from "../../flatbuffers"; import { ReadableStream } from '@stardazed/streams'; @@ -10,8 +10,14 @@ export class Image { this.src = src; } - webp(opts: Image.WebPOptions) { + webp(opts: Image.WebPOptions = {}) { this.operations.push({ type: Image.OperationType.WebPEncode, options: opts }); + return this + } + + resize(opts: Image.ResizeOptions = {}) { + this.operations.push({ type: Image.OperationType.Resize, options: opts }); + return this } transform(): Promise { @@ -21,18 +27,32 @@ export class Image { let i = 0; for (const op of this.operations) { if (op.type == Image.OperationType.WebPEncode) { + let opts = op.options; fbs.ImageWebPEncode.startImageWebPEncode(fbb); - fbs.ImageWebPEncode.addLossless(fbb, op.options.lossless); - fbs.ImageWebPEncode.addNearLossless(fbb, op.options.nearLossless); - fbs.ImageWebPEncode.addQuality(fbb, op.options.quality || 75); - fbs.ImageWebPEncode.addAlphaQuality(fbb, op.options.alphaQuality || 75); + fbs.ImageWebPEncode.addLossless(fbb, !!opts.lossless); + fbs.ImageWebPEncode.addNearLossless(fbb, !!opts.nearLossless); + fbs.ImageWebPEncode.addQuality(fbb, opts.quality || 75); + fbs.ImageWebPEncode.addAlphaQuality(fbb, opts.alphaQuality || 75); let fbbOpts = fbs.ImageWebPEncode.endImageWebPEncode(fbb); fbs.ImageTransform.startImageTransform(fbb); - fbs.ImageTransform.addTransform(fbb, fbs.ImageTransformType.ImageWebPEncode); + fbs.ImageTransform.addTransform(fbb, fbs.ImageTransformType.WebPEncode); fbs.ImageTransform.addOptionsType(fbb, fbs.ImageTransformOptions.ImageWebPEncode); fbs.ImageTransform.addOptions(fbb, fbbOpts); fbbTransforms[i++] = fbs.ImageTransform.endImageTransform(fbb); } + else if (op.type === Image.OperationType.Resize) { + let opts = op.options; + fbs.ImageResize.startImageResize(fbb); + fbs.ImageResize.addWidth(fbb, opts.width || 1); + fbs.ImageResize.addHeight(fbb, opts.height || 1); + fbs.ImageResize.addFilter(fbb, opts.filter || fbs.ImageSamplingFilter.Nearest); + let fbbOpts = fbs.ImageResize.endImageResize(fbb); + fbs.ImageTransform.startImageTransform(fbb); + fbs.ImageTransform.addTransform(fbb, fbs.ImageTransformType.Resize); + fbs.ImageTransform.addOptionsType(fbb, fbs.ImageTransformOptions.ImageResize); + fbs.ImageTransform.addOptions(fbb, fbbOpts); + fbbTransforms[i++] = fbs.ImageTransform.endImageTransform(fbb); + } } const transforms = fbs.ImageApplyTransforms.createTransformsVector(fbb, fbbTransforms); fbs.ImageApplyTransforms.startImageApplyTransforms(fbb); @@ -63,9 +83,10 @@ export class Image { export namespace Image { export enum OperationType { WebPEncode, + Resize, } - type OperationOptions = WebPOptions; + type OperationOptions = WebPOptions | ResizeOptions; export interface Operation { type: OperationType, @@ -84,4 +105,18 @@ export namespace Image { /** force WebP output, otherwise attempt to use input format, defaults to true */ force?: boolean } + + export interface ResizeOptions { + width?: number, + height?: number, + filter?: fbs.ImageSamplingFilter, + } + + export const SamplingFilter = { + Nearest: fbs.ImageSamplingFilter.Nearest, + Triangle: fbs.ImageSamplingFilter.Triangle, + CatmullRom: fbs.ImageSamplingFilter.CatmullRom, + Gaussian: fbs.ImageSamplingFilter.Gaussian, + Lanczos3: fbs.ImageSamplingFilter.Lanczos3, + } } \ No newline at end of file diff --git a/v8env/src/fly/cache/response.ts b/v8env/src/fly/response.ts similarity index 92% rename from v8env/src/fly/cache/response.ts rename to v8env/src/fly/response.ts index ce38d16..8c23906 100644 --- a/v8env/src/fly/cache/response.ts +++ b/v8env/src/fly/response.ts @@ -20,9 +20,15 @@ */ /** */ -import cache, { CacheSetOptions } from "." -import { Response } from '../../dom_types' -import { FlyResponse } from "../../response" +import * as cache from "./cache" +import { Response } from '../dom_types' +import { FlyResponse } from "../response" + +export const { + del, + expire, + setTags +} = cache; /** * Response metadata suitable for caching @@ -35,7 +41,7 @@ export interface Metadata { tags?: string[] } -export interface ResponseCacheSetOptions extends CacheSetOptions { +export interface ResponseCacheSetOptions extends cache.CacheSetOptions { skipCacheHeaders?: string[] } @@ -95,6 +101,8 @@ export async function set(key: string, resp: Response, options?: ResponseCacheSe } else if (typeof options === "object") { tags = options.tags; skipHeaderOption = [...skipHeaderOption, ...(options.skipCacheHeaders || []).map((headerKey) => headerKey.toLowerCase())]; + } else { + options = {} } const meta = { @@ -143,15 +151,6 @@ export async function touch(key: string) { return await cache.setMeta(key, JSON.stringify(meta)) } -export default { - get, - set, - setTags: cache.setTags, // backwards compat - touch, - expire: cache.expire, // backwards compat - del: cache.del // backwards compat -} - // converts a buffer to hex, mainly for hashes function hex(buffer: ArrayBuffer) { let hexCodes = []; diff --git a/v8env/src/form_data.ts b/v8env/src/form_data.ts index 3219449..a4ec936 100644 --- a/v8env/src/form_data.ts +++ b/v8env/src/form_data.ts @@ -2,6 +2,7 @@ import * as domTypes from "./dom_types"; import * as blob from "./blob"; import { DomIterableMixin } from "./mixins/dom_iterable"; +import { stringify } from "querystring" const dataSymbol = Symbol("data"); @@ -96,6 +97,19 @@ class FormDataBase { this[dataSymbol].push([name, String(value)]); // } } + + public toString(): string { + return stringify(this[dataSymbol].reduce((acc, [name, value]) => { + let found = acc[name]; + if (typeof found === 'undefined') + acc[name] = value + else if (Array.isArray(found)) + acc[name].push(value) + else + acc[name] = [found, value] + return acc + }, {})) + } } // tslint:disable-next-line:variable-name @@ -103,4 +117,4 @@ export class FlyFormData extends DomIterableMixin< string, domTypes.FormDataEntryValue, typeof FormDataBase - >(FormDataBase, dataSymbol) { }; \ No newline at end of file +>(FormDataBase, dataSymbol) { }; \ No newline at end of file diff --git a/v8env/src/globals.ts b/v8env/src/globals.ts index ab4d7c0..819fc42 100644 --- a/v8env/src/globals.ts +++ b/v8env/src/globals.ts @@ -9,21 +9,31 @@ import * as textEncoding from "./text-encoding"; import { FlyResponse } from "./response"; import * as fetch_ from './fetch'; import * as resolv_ from './resolv'; +import * as serviceRequest_ from "./service_request"; import * as dns from './dns'; +import * as service from "./service"; import * as crypto_ from "./crypto"; import cache_ from "./cache"; import { Image } from "./fly/image"; import * as url from './url'; import { FlyRequest } from "./request"; -import flyData from './fly/data'; -import flyCache from './fly/cache'; +import * as flyData from './fly/data'; +import * as flyCache from './fly/cache'; +import * as flyResponseCache from './fly/response'; import flyHttp from './fly/http' import { loadModule } from "./module_loader"; import { installDevTools } from "./dev-tools"; import * as streams from "./streams"; import { AppRelease } from "./app"; import { runtime, Runtime } from "./runtime"; +import { Logger } from "./logging"; + +import * as domTypes from './dom_types'; +import * as formData from "./form_data"; +import * as headers from './headers'; +import { arrayBufferToString, stringToArrayBuffer } from "./util"; +import { bufferFromStream } from "./body_mixin"; declare global { interface Window { @@ -46,6 +56,8 @@ declare global { const fetch: typeof fetch_.fetch; + const serviceRequest: typeof serviceRequest_.serviceRequest; + // tslint:disable:variable-name let TextEncoder: typeof textEncoding.TextEncoder; let TextDecoder: typeof textEncoding.TextDecoder; @@ -59,6 +71,7 @@ declare global { interface Fly { cache: typeof flyCache + responseCache: typeof flyResponseCache data: typeof flyData http: typeof flyHttp Image: typeof Image @@ -76,6 +89,8 @@ declare global { const DNSMessageType: typeof dns.DNSMessageType; const DNSOpCode: typeof dns.DNSOpCode; const DNSResponseCode: typeof dns.DNSResponseCode; + const ServiceRequest: typeof service.ServiceRequest; + const ServiceResponse: typeof service.ServiceResponse; } // A reference to the global object. @@ -96,20 +111,30 @@ window.Request = FlyRequest; window.addEventListener = bridge.addEventListener; -window.console = new Console(libfly.print); +const logger = new Logger(libfly.print); +window.logger = logger; +window.console = new Console(logger); window.TextEncoder = textEncoding.TextEncoder; window.TextDecoder = textEncoding.TextDecoder; window.URL = url.URL; window.URLSearchParams = url.URLSearchParams; +window.Headers = headers.FlyHeaders as domTypes.HeadersConstructor; +export type Headers = domTypes.Headers; + +window.FormData = formData.FlyFormData as domTypes.FormDataConstructor; +export type FormData = domTypes.FormData; + window.fetch = fetch_.fetch; window.resolv = resolv_.resolv; +window.serviceRequest = serviceRequest_.serviceRequest; window.crypto = crypto_.crypto; window.cache = cache_; window.loadModule = loadModule; window.fly = { cache: flyCache, + responseCache: flyResponseCache, data: flyData, http: flyHttp, Image: Image, @@ -123,7 +148,18 @@ window.DNSRecordType = dns.DNSRecordType; window.DNSMessageType = dns.DNSMessageType; window.DNSOpCode = dns.DNSOpCode; window.DNSResponseCode = dns.DNSResponseCode; +window.ServiceRequest = service.ServiceRequest; +window.ServiceResponse = service.ServiceResponse; + +const conversionUtils = { + arrayBufferToStr: arrayBufferToString, + stringToArrayBuffer, + ab2str: arrayBufferToString, + str2ab: stringToArrayBuffer, + streamToBuffer: bufferFromStream, +}; Object.assign(window, { ...streams, + ...conversionUtils }); diff --git a/v8env/src/libfly.ts b/v8env/src/libfly.ts index e79dc47..e7f9663 100644 --- a/v8env/src/libfly.ts +++ b/v8env/src/libfly.ts @@ -1,4 +1,3 @@ -import { RawSourceMap } from './types' import { globalEval } from './global-eval' type MessageCallback = (msg: Uint8Array, raw: Uint8Array) => void; diff --git a/v8env/src/logging.ts b/v8env/src/logging.ts new file mode 100644 index 0000000..f23ab96 --- /dev/null +++ b/v8env/src/logging.ts @@ -0,0 +1,152 @@ +type ConsoleContext = Set; + +type PrintFunc = (level: number, msg: string) => void; + +export const enum Level { + Print = 0, + RuntimeError = 1, + RuntimeWarn = 2, + RuntimeInfo = 3, + RuntimeDebug = 4, + RuntimeTrace = 5, + AppError = 11, + AppWarn = 12, + AppInfo = 13, + AppDebug = 14, + AppTrace = 15, +} + +export class Logger { + constructor(private printFunc: PrintFunc) { } + + public log(level: Level, ...args: unknown[]) { + this.printFunc(level, stringifyArgs(args)); + } + + public print(...args: unknown[]): void { + this.printFunc(Level.Print, stringifyArgs(args)); + } + + public error(...args: unknown[]): void { + this.printFunc(Level.RuntimeError, stringifyArgs(args)) + } + + public warn(...args: unknown[]): void { + this.printFunc(Level.RuntimeWarn, stringifyArgs(args)) + } + + public info(...args: unknown[]): void { + this.printFunc(Level.RuntimeInfo, stringifyArgs(args)) + } + + public debug(...args: unknown[]): void { + this.printFunc(Level.RuntimeDebug, stringifyArgs(args)) + } + + public trace(...args: unknown[]): void { + this.printFunc(Level.RuntimeTrace, stringifyArgs(args)) + } +} + +// Print strings when they are inside of arrays or objects with quotes +function stringifyWithQuotes(ctx: ConsoleContext, value: unknown): string { + switch (typeof value) { + case "string": + return `"${value}"`; + default: + return stringify(ctx, value); + } +} + +function stringifyArgs(args: unknown[]): string { + const out: string[] = []; + for (const a of args) { + if (typeof a === "string") { + out.push(a); + } else { + out.push(stringify(new Set(), a)); + } + } + return out.join(" "); +} + +// tslint:disable-next-line:no-any +function getClassInstanceName(instance: any): string { + if (typeof instance !== "object") { + return ""; + } + if (instance && instance.__proto__ && instance.__proto__.constructor) { + return instance.__proto__.constructor.name; // could be "Object" or "Array" + } + return ""; +} + +function stringify(ctx: ConsoleContext, value: unknown): string { + switch (typeof value) { + case "string": + return value; + case "number": + case "boolean": + case "undefined": + case "symbol": + return String(value); + case "function": + if (value.name && value.name !== "anonymous") { + // from MDN spec + return `[Function: ${value.name}]`; + } + return "[Function]"; + case "object": + if (value === null) { + return "null"; + } + + if (ctx.has(value)) { + return "[Circular]"; + } + + ctx.add(value); + const entries: string[] = []; + + if (Array.isArray(value)) { + for (const el of value) { + entries.push(stringifyWithQuotes(ctx, el)); + } + + ctx.delete(value); + + if (entries.length === 0) { + return "[]"; + } + return `[ ${entries.join(", ")} ]`; + } else { + let baseString = ""; + + const className = getClassInstanceName(value); + let shouldShowClassName = false; + if (className && className !== "Object" && className !== "anonymous") { + shouldShowClassName = true; + } + + for (const key of Object.keys(value)) { + entries.push(`${key}: ${stringifyWithQuotes(ctx, value[key])}`); + } + + ctx.delete(value); + + if (entries.length === 0) { + baseString = "{}"; + } else { + baseString = `{ ${entries.join(", ")} }`; + } + + if (shouldShowClassName) { + baseString = `${className} ${baseString}`; + } + + return baseString; + } + default: + return "[Not Implemented]"; + } +} \ No newline at end of file diff --git a/v8env/src/module_loader.ts b/v8env/src/module_loader.ts index 0c9b306..114a2b2 100644 --- a/v8env/src/module_loader.ts +++ b/v8env/src/module_loader.ts @@ -2,25 +2,69 @@ import { sendSync } from './bridge'; import * as fbs from "./msg_generated"; import * as flatbuffers from "./flatbuffers" -export interface ModuleInfo { - moduleId: string; - fileName: string; - sourceCode: string; +export interface LoadedSourceCode { + isWasm: boolean; + sourceMap?: string; + source: string; } -export function loadModule(moduleSpecifier: string, containingFile: string): ModuleInfo { +export interface LoadedModule { + originUrl: string; + loadedSource: LoadedSourceCode; +} + +export function loadModule(specifierUrl: string, refererOriginUrl?: string): LoadedModule { + if (refererOriginUrl) { + return loadModuleStandard(specifierUrl, refererOriginUrl); + } else { + return loadModuleWithoutReferer(specifierUrl); + } +} + +function loadModuleWithoutReferer(specifierUrl: string): LoadedModule { + // Allocate new message and fill it with data const fbb = flatbuffers.createBuilder(); - const fbModuleSpecifier = fbb.createString(moduleSpecifier); - const fbContainingFile = fbb.createString(containingFile); + const fbSpcecifierUrl = fbb.createString(specifierUrl); + // Fill message handle with data fbs.LoadModule.startLoadModule(fbb); - fbs.LoadModule.addModuleSpecifier(fbb, fbModuleSpecifier); - fbs.LoadModule.addContainingFile(fbb, fbContainingFile); + fbs.LoadModule.addSpecifierUrl(fbb, fbSpcecifierUrl); + // Send flatbuffer messaage and collect response const resp = sendSync(fbb, fbs.Any.LoadModule, fbs.LoadModule.endLoadModule(fbb)); + // Allocate new LoadModuleResp handle const msg = new fbs.LoadModuleResp(); + // Write message data to handle resp.msg(msg); + // Transform data into local format and return. return { - moduleId: msg.moduleId(), - fileName: msg.fileName(), - sourceCode: msg.sourceCode(), - } + originUrl: msg.originUrl(), + loadedSource: { + isWasm: false, + source: msg.sourceCode(), + }, + }; +} + +function loadModuleStandard(specifierUrl: string, refererOriginUrl: string): LoadedModule { + // Allocate new message handle + const fbb = flatbuffers.createBuilder(); + const fbSpcecifierUrl = fbb.createString(specifierUrl); + const fbRefererOriginUrl = fbb.createString(refererOriginUrl); + // Fill message handle with data + fbs.LoadModule.startLoadModule(fbb); + fbs.LoadModule.addSpecifierUrl(fbb, fbSpcecifierUrl); + fbs.LoadModule.addRefererOriginUrl(fbb, fbRefererOriginUrl); + // Send flatbuffer messaage and collect response + const resp = sendSync(fbb, fbs.Any.LoadModule, fbs.LoadModule.endLoadModule(fbb)); + // Allocate new LoadModuleResp handle + const msg = new fbs.LoadModuleResp(); + // Write message data to handle + resp.msg(msg); + // Return data from handle + return { + originUrl: msg.originUrl(), + loadedSource: { + isWasm: false, + source: msg.sourceCode(), + }, + }; } \ No newline at end of file diff --git a/v8env/src/msg_generated.ts b/v8env/src/msg_generated.ts index 3bc669a..d62a210 100644 --- a/v8env/src/msg_generated.ts +++ b/v8env/src/msg_generated.ts @@ -97,7 +97,19 @@ export enum DnsRecordData{ * @enum */ export enum ImageTransformType{ - ImageWebPEncode= 0 + WebPEncode= 0, + Resize= 1 +}; + +/** + * @enum + */ +export enum ImageSamplingFilter{ + Nearest= 0, + Triangle= 1, + CatmullRom= 2, + Gaussian= 3, + Lanczos3= 4 }; /** @@ -105,7 +117,8 @@ export enum ImageTransformType{ */ export enum ImageTransformOptions{ NONE= 0, - ImageWebPEncode= 1 + ImageWebPEncode= 1, + ImageResize= 2 }; /** @@ -142,17 +155,23 @@ export enum Any{ DataGet= 27, DataGetReady= 28, DataDel= 29, - DataDropCollection= 30, - DnsQuery= 31, - DnsRequest= 32, - DnsResponse= 33, - AddEventListener= 34, - LoadModule= 35, - LoadModuleResp= 36, - ImageApplyTransforms= 37, - ImageReady= 38, - AcmeGetChallenge= 39, - AcmeGetChallengeReady= 40 + DataIncr= 30, + DataDropCollection= 31, + DnsQuery= 32, + DnsRequest= 33, + DnsResponse= 34, + AddEventListener= 35, + LoadModule= 36, + LoadModuleResp= 37, + ImageApplyTransforms= 38, + ImageReady= 39, + AcmeGetChallenge= 40, + AcmeGetChallengeReady= 41, + ServiceRequest= 42, + ServiceResponse= 43, + RequestServiceRequest= 44, + RequestServiceResponse= 45, + OsExit= 46 }; /** @@ -216,7 +235,8 @@ export enum HttpMethod{ */ export enum EventType{ Fetch= 0, - Resolv= 1 + Resolv= 1, + Serve= 2 }; /** @@ -3115,16 +3135,16 @@ static endCachePurgeTag(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class ImageWebPEncode { +export class DataPut { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns ImageWebPEncode + * @returns DataPut */ -__init(i:number, bb:flatbuffers.ByteBuffer):ImageWebPEncode { +__init(i:number, bb:flatbuffers.ByteBuffer):DataPut { this.bb_pos = i; this.bb = bb; return this; @@ -3132,149 +3152,82 @@ __init(i:number, bb:flatbuffers.ByteBuffer):ImageWebPEncode { /** * @param flatbuffers.ByteBuffer bb - * @param ImageWebPEncode= obj - * @returns ImageWebPEncode - */ -static getRootAsImageWebPEncode(bb:flatbuffers.ByteBuffer, obj?:ImageWebPEncode):ImageWebPEncode { - return (obj || new ImageWebPEncode).__init(bb.readInt32(bb.position()) + bb.position(), bb); -}; - -/** - * @returns number + * @param DataPut= obj + * @returns DataPut */ -quality():number { - var offset = this.bb!.__offset(this.bb_pos, 4); - return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0; +static getRootAsDataPut(bb:flatbuffers.ByteBuffer, obj?:DataPut):DataPut { + return (obj || new DataPut).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; /** - * @param number value - * @returns boolean + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null */ -mutate_quality(value:number):boolean { +collection():string|null +collection(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +collection(optionalEncoding?:any):string|Uint8Array|null { var offset = this.bb!.__offset(this.bb_pos, 4); - - if (offset === 0) { - return false; - } - - this.bb!.writeFloat32(this.bb_pos + offset, value); - return true; -}; - -/** - * @returns number - */ -alphaQuality():number { - var offset = this.bb!.__offset(this.bb_pos, 6); - return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0; + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; /** - * @param number value - * @returns boolean + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null */ -mutate_alpha_quality(value:number):boolean { +key():string|null +key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +key(optionalEncoding?:any):string|Uint8Array|null { var offset = this.bb!.__offset(this.bb_pos, 6); - - if (offset === 0) { - return false; - } - - this.bb!.writeFloat32(this.bb_pos + offset, value); - return true; -}; - -/** - * @returns boolean - */ -lossless():boolean { - var offset = this.bb!.__offset(this.bb_pos, 8); - return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; /** - * @param boolean value - * @returns boolean + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null */ -mutate_lossless(value:boolean):boolean { +json():string|null +json(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +json(optionalEncoding?:any):string|Uint8Array|null { var offset = this.bb!.__offset(this.bb_pos, 8); - - if (offset === 0) { - return false; - } - - this.bb!.writeInt8(this.bb_pos + offset, +value); - return true; -}; - -/** - * @returns boolean - */ -nearLossless():boolean { - var offset = this.bb!.__offset(this.bb_pos, 10); - return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; -}; - -/** - * @param boolean value - * @returns boolean - */ -mutate_near_lossless(value:boolean):boolean { - var offset = this.bb!.__offset(this.bb_pos, 10); - - if (offset === 0) { - return false; - } - - this.bb!.writeInt8(this.bb_pos + offset, +value); - return true; -}; - -/** - * @param flatbuffers.Builder builder - */ -static startImageWebPEncode(builder:flatbuffers.Builder) { - builder.startObject(4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; /** * @param flatbuffers.Builder builder - * @param number quality */ -static addQuality(builder:flatbuffers.Builder, quality:number) { - builder.addFieldFloat32(0, quality, 0.0); +static startDataPut(builder:flatbuffers.Builder) { + builder.startObject(3); }; /** * @param flatbuffers.Builder builder - * @param number alphaQuality + * @param flatbuffers.Offset collectionOffset */ -static addAlphaQuality(builder:flatbuffers.Builder, alphaQuality:number) { - builder.addFieldFloat32(1, alphaQuality, 0.0); +static addCollection(builder:flatbuffers.Builder, collectionOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, collectionOffset, 0); }; /** * @param flatbuffers.Builder builder - * @param boolean lossless + * @param flatbuffers.Offset keyOffset */ -static addLossless(builder:flatbuffers.Builder, lossless:boolean) { - builder.addFieldInt8(2, +lossless, +false); +static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, keyOffset, 0); }; /** * @param flatbuffers.Builder builder - * @param boolean nearLossless + * @param flatbuffers.Offset jsonOffset */ -static addNearLossless(builder:flatbuffers.Builder, nearLossless:boolean) { - builder.addFieldInt8(3, +nearLossless, +false); +static addJson(builder:flatbuffers.Builder, jsonOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, jsonOffset, 0); }; /** * @param flatbuffers.Builder builder * @returns flatbuffers.Offset */ -static endImageWebPEncode(builder:flatbuffers.Builder):flatbuffers.Offset { +static endDataPut(builder:flatbuffers.Builder):flatbuffers.Offset { var offset = builder.endObject(); return offset; }; @@ -3283,16 +3236,16 @@ static endImageWebPEncode(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class ImageTransform { +export class DataGet { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns ImageTransform + * @returns DataGet */ -__init(i:number, bb:flatbuffers.ByteBuffer):ImageTransform { +__init(i:number, bb:flatbuffers.ByteBuffer):DataGet { this.bb_pos = i; this.bb = bb; return this; @@ -3300,104 +3253,63 @@ __init(i:number, bb:flatbuffers.ByteBuffer):ImageTransform { /** * @param flatbuffers.ByteBuffer bb - * @param ImageTransform= obj - * @returns ImageTransform - */ -static getRootAsImageTransform(bb:flatbuffers.ByteBuffer, obj?:ImageTransform):ImageTransform { - return (obj || new ImageTransform).__init(bb.readInt32(bb.position()) + bb.position(), bb); -}; - -/** - * @returns ImageTransformType + * @param DataGet= obj + * @returns DataGet */ -transform():ImageTransformType { - var offset = this.bb!.__offset(this.bb_pos, 4); - return offset ? /** */ (this.bb!.readInt8(this.bb_pos + offset)) : ImageTransformType.ImageWebPEncode; +static getRootAsDataGet(bb:flatbuffers.ByteBuffer, obj?:DataGet):DataGet { + return (obj || new DataGet).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; /** - * @param ImageTransformType value - * @returns boolean + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null */ -mutate_transform(value:ImageTransformType):boolean { +collection():string|null +collection(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +collection(optionalEncoding?:any):string|Uint8Array|null { var offset = this.bb!.__offset(this.bb_pos, 4); - - if (offset === 0) { - return false; - } - - this.bb!.writeInt8(this.bb_pos + offset, value); - return true; -}; - -/** - * @returns ImageTransformOptions - */ -optionsType():ImageTransformOptions { - var offset = this.bb!.__offset(this.bb_pos, 6); - return offset ? /** */ (this.bb!.readUint8(this.bb_pos + offset)) : ImageTransformOptions.NONE; + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; /** - * @param ImageTransformOptions value - * @returns boolean + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null */ -mutate_options_type(value:ImageTransformOptions):boolean { +key():string|null +key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +key(optionalEncoding?:any):string|Uint8Array|null { var offset = this.bb!.__offset(this.bb_pos, 6); - - if (offset === 0) { - return false; - } - - this.bb!.writeUint8(this.bb_pos + offset, value); - return true; -}; - -/** - * @param flatbuffers.Table obj - * @returns ?flatbuffers.Table - */ -options(obj:T):T|null { - var offset = this.bb!.__offset(this.bb_pos, 8); - return offset ? this.bb!.__union(obj, this.bb_pos + offset) : null; -}; - -/** - * @param flatbuffers.Builder builder - */ -static startImageTransform(builder:flatbuffers.Builder) { - builder.startObject(3); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; /** * @param flatbuffers.Builder builder - * @param ImageTransformType transform */ -static addTransform(builder:flatbuffers.Builder, transform:ImageTransformType) { - builder.addFieldInt8(0, transform, ImageTransformType.ImageWebPEncode); +static startDataGet(builder:flatbuffers.Builder) { + builder.startObject(2); }; /** * @param flatbuffers.Builder builder - * @param ImageTransformOptions optionsType + * @param flatbuffers.Offset collectionOffset */ -static addOptionsType(builder:flatbuffers.Builder, optionsType:ImageTransformOptions) { - builder.addFieldInt8(1, optionsType, ImageTransformOptions.NONE); +static addCollection(builder:flatbuffers.Builder, collectionOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, collectionOffset, 0); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset optionsOffset + * @param flatbuffers.Offset keyOffset */ -static addOptions(builder:flatbuffers.Builder, optionsOffset:flatbuffers.Offset) { - builder.addFieldOffset(2, optionsOffset, 0); +static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, keyOffset, 0); }; /** * @param flatbuffers.Builder builder * @returns flatbuffers.Offset */ -static endImageTransform(builder:flatbuffers.Builder):flatbuffers.Offset { +static endDataGet(builder:flatbuffers.Builder):flatbuffers.Offset { var offset = builder.endObject(); return offset; }; @@ -3406,16 +3318,16 @@ static endImageTransform(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class ImageApplyTransforms { +export class DataGetReady { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns ImageApplyTransforms + * @returns DataGetReady */ -__init(i:number, bb:flatbuffers.ByteBuffer):ImageApplyTransforms { +__init(i:number, bb:flatbuffers.ByteBuffer):DataGetReady { this.bb_pos = i; this.bb = bb; return this; @@ -3423,15 +3335,783 @@ __init(i:number, bb:flatbuffers.ByteBuffer):ImageApplyTransforms { /** * @param flatbuffers.ByteBuffer bb - * @param ImageApplyTransforms= obj - * @returns ImageApplyTransforms + * @param DataGetReady= obj + * @returns DataGetReady */ -static getRootAsImageApplyTransforms(bb:flatbuffers.ByteBuffer, obj?:ImageApplyTransforms):ImageApplyTransforms { - return (obj || new ImageApplyTransforms).__init(bb.readInt32(bb.position()) + bb.position(), bb); +static getRootAsDataGetReady(bb:flatbuffers.ByteBuffer, obj?:DataGetReady):DataGetReady { + return (obj || new DataGetReady).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; /** - * @param number index + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +json():string|null +json(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +json(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param flatbuffers.Builder builder + */ +static startDataGetReady(builder:flatbuffers.Builder) { + builder.startObject(1); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset jsonOffset + */ +static addJson(builder:flatbuffers.Builder, jsonOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, jsonOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @returns flatbuffers.Offset + */ +static endDataGetReady(builder:flatbuffers.Builder):flatbuffers.Offset { + var offset = builder.endObject(); + return offset; +}; + +} +/** + * @constructor + */ +export class DataDel { + bb: flatbuffers.ByteBuffer|null = null; + + bb_pos:number = 0; +/** + * @param number i + * @param flatbuffers.ByteBuffer bb + * @returns DataDel + */ +__init(i:number, bb:flatbuffers.ByteBuffer):DataDel { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param flatbuffers.ByteBuffer bb + * @param DataDel= obj + * @returns DataDel + */ +static getRootAsDataDel(bb:flatbuffers.ByteBuffer, obj?:DataDel):DataDel { + return (obj || new DataDel).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +collection():string|null +collection(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +collection(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +key():string|null +key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +key(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param flatbuffers.Builder builder + */ +static startDataDel(builder:flatbuffers.Builder) { + builder.startObject(2); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset collectionOffset + */ +static addCollection(builder:flatbuffers.Builder, collectionOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, collectionOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset keyOffset + */ +static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, keyOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @returns flatbuffers.Offset + */ +static endDataDel(builder:flatbuffers.Builder):flatbuffers.Offset { + var offset = builder.endObject(); + return offset; +}; + +} +/** + * @constructor + */ +export class DataDropCollection { + bb: flatbuffers.ByteBuffer|null = null; + + bb_pos:number = 0; +/** + * @param number i + * @param flatbuffers.ByteBuffer bb + * @returns DataDropCollection + */ +__init(i:number, bb:flatbuffers.ByteBuffer):DataDropCollection { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param flatbuffers.ByteBuffer bb + * @param DataDropCollection= obj + * @returns DataDropCollection + */ +static getRootAsDataDropCollection(bb:flatbuffers.ByteBuffer, obj?:DataDropCollection):DataDropCollection { + return (obj || new DataDropCollection).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +collection():string|null +collection(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +collection(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param flatbuffers.Builder builder + */ +static startDataDropCollection(builder:flatbuffers.Builder) { + builder.startObject(1); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset collectionOffset + */ +static addCollection(builder:flatbuffers.Builder, collectionOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, collectionOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @returns flatbuffers.Offset + */ +static endDataDropCollection(builder:flatbuffers.Builder):flatbuffers.Offset { + var offset = builder.endObject(); + return offset; +}; + +} +/** + * @constructor + */ +export class DataIncr { + bb: flatbuffers.ByteBuffer|null = null; + + bb_pos:number = 0; +/** + * @param number i + * @param flatbuffers.ByteBuffer bb + * @returns DataIncr + */ +__init(i:number, bb:flatbuffers.ByteBuffer):DataIncr { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param flatbuffers.ByteBuffer bb + * @param DataIncr= obj + * @returns DataIncr + */ +static getRootAsDataIncr(bb:flatbuffers.ByteBuffer, obj?:DataIncr):DataIncr { + return (obj || new DataIncr).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +collection():string|null +collection(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +collection(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +key():string|null +key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +key(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +field():string|null +field(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +field(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @returns number + */ +amount():number { + var offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +}; + +/** + * @param number value + * @returns boolean + */ +mutate_amount(value:number):boolean { + var offset = this.bb!.__offset(this.bb_pos, 10); + + if (offset === 0) { + return false; + } + + this.bb!.writeInt32(this.bb_pos + offset, value); + return true; +}; + +/** + * @param flatbuffers.Builder builder + */ +static startDataIncr(builder:flatbuffers.Builder) { + builder.startObject(4); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset collectionOffset + */ +static addCollection(builder:flatbuffers.Builder, collectionOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, collectionOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset keyOffset + */ +static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, keyOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset fieldOffset + */ +static addField(builder:flatbuffers.Builder, fieldOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, fieldOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param number amount + */ +static addAmount(builder:flatbuffers.Builder, amount:number) { + builder.addFieldInt32(3, amount, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @returns flatbuffers.Offset + */ +static endDataIncr(builder:flatbuffers.Builder):flatbuffers.Offset { + var offset = builder.endObject(); + return offset; +}; + +} +/** + * @constructor + */ +export class ImageWebPEncode { + bb: flatbuffers.ByteBuffer|null = null; + + bb_pos:number = 0; +/** + * @param number i + * @param flatbuffers.ByteBuffer bb + * @returns ImageWebPEncode + */ +__init(i:number, bb:flatbuffers.ByteBuffer):ImageWebPEncode { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param flatbuffers.ByteBuffer bb + * @param ImageWebPEncode= obj + * @returns ImageWebPEncode + */ +static getRootAsImageWebPEncode(bb:flatbuffers.ByteBuffer, obj?:ImageWebPEncode):ImageWebPEncode { + return (obj || new ImageWebPEncode).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns number + */ +quality():number { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @param number value + * @returns boolean + */ +mutate_quality(value:number):boolean { + var offset = this.bb!.__offset(this.bb_pos, 4); + + if (offset === 0) { + return false; + } + + this.bb!.writeFloat32(this.bb_pos + offset, value); + return true; +}; + +/** + * @returns number + */ +alphaQuality():number { + var offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0; +}; + +/** + * @param number value + * @returns boolean + */ +mutate_alpha_quality(value:number):boolean { + var offset = this.bb!.__offset(this.bb_pos, 6); + + if (offset === 0) { + return false; + } + + this.bb!.writeFloat32(this.bb_pos + offset, value); + return true; +}; + +/** + * @returns boolean + */ +lossless():boolean { + var offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +}; + +/** + * @param boolean value + * @returns boolean + */ +mutate_lossless(value:boolean):boolean { + var offset = this.bb!.__offset(this.bb_pos, 8); + + if (offset === 0) { + return false; + } + + this.bb!.writeInt8(this.bb_pos + offset, +value); + return true; +}; + +/** + * @returns boolean + */ +nearLossless():boolean { + var offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +}; + +/** + * @param boolean value + * @returns boolean + */ +mutate_near_lossless(value:boolean):boolean { + var offset = this.bb!.__offset(this.bb_pos, 10); + + if (offset === 0) { + return false; + } + + this.bb!.writeInt8(this.bb_pos + offset, +value); + return true; +}; + +/** + * @param flatbuffers.Builder builder + */ +static startImageWebPEncode(builder:flatbuffers.Builder) { + builder.startObject(4); +}; + +/** + * @param flatbuffers.Builder builder + * @param number quality + */ +static addQuality(builder:flatbuffers.Builder, quality:number) { + builder.addFieldFloat32(0, quality, 0.0); +}; + +/** + * @param flatbuffers.Builder builder + * @param number alphaQuality + */ +static addAlphaQuality(builder:flatbuffers.Builder, alphaQuality:number) { + builder.addFieldFloat32(1, alphaQuality, 0.0); +}; + +/** + * @param flatbuffers.Builder builder + * @param boolean lossless + */ +static addLossless(builder:flatbuffers.Builder, lossless:boolean) { + builder.addFieldInt8(2, +lossless, +false); +}; + +/** + * @param flatbuffers.Builder builder + * @param boolean nearLossless + */ +static addNearLossless(builder:flatbuffers.Builder, nearLossless:boolean) { + builder.addFieldInt8(3, +nearLossless, +false); +}; + +/** + * @param flatbuffers.Builder builder + * @returns flatbuffers.Offset + */ +static endImageWebPEncode(builder:flatbuffers.Builder):flatbuffers.Offset { + var offset = builder.endObject(); + return offset; +}; + +} +/** + * @constructor + */ +export class ImageResize { + bb: flatbuffers.ByteBuffer|null = null; + + bb_pos:number = 0; +/** + * @param number i + * @param flatbuffers.ByteBuffer bb + * @returns ImageResize + */ +__init(i:number, bb:flatbuffers.ByteBuffer):ImageResize { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param flatbuffers.ByteBuffer bb + * @param ImageResize= obj + * @returns ImageResize + */ +static getRootAsImageResize(bb:flatbuffers.ByteBuffer, obj?:ImageResize):ImageResize { + return (obj || new ImageResize).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns number + */ +width():number { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0; +}; + +/** + * @param number value + * @returns boolean + */ +mutate_width(value:number):boolean { + var offset = this.bb!.__offset(this.bb_pos, 4); + + if (offset === 0) { + return false; + } + + this.bb!.writeUint32(this.bb_pos + offset, value); + return true; +}; + +/** + * @returns number + */ +height():number { + var offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0; +}; + +/** + * @param number value + * @returns boolean + */ +mutate_height(value:number):boolean { + var offset = this.bb!.__offset(this.bb_pos, 6); + + if (offset === 0) { + return false; + } + + this.bb!.writeUint32(this.bb_pos + offset, value); + return true; +}; + +/** + * @returns ImageSamplingFilter + */ +filter():ImageSamplingFilter { + var offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? /** */ (this.bb!.readInt8(this.bb_pos + offset)) : ImageSamplingFilter.Nearest; +}; + +/** + * @param ImageSamplingFilter value + * @returns boolean + */ +mutate_filter(value:ImageSamplingFilter):boolean { + var offset = this.bb!.__offset(this.bb_pos, 8); + + if (offset === 0) { + return false; + } + + this.bb!.writeInt8(this.bb_pos + offset, value); + return true; +}; + +/** + * @param flatbuffers.Builder builder + */ +static startImageResize(builder:flatbuffers.Builder) { + builder.startObject(3); +}; + +/** + * @param flatbuffers.Builder builder + * @param number width + */ +static addWidth(builder:flatbuffers.Builder, width:number) { + builder.addFieldInt32(0, width, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param number height + */ +static addHeight(builder:flatbuffers.Builder, height:number) { + builder.addFieldInt32(1, height, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param ImageSamplingFilter filter + */ +static addFilter(builder:flatbuffers.Builder, filter:ImageSamplingFilter) { + builder.addFieldInt8(2, filter, ImageSamplingFilter.Nearest); +}; + +/** + * @param flatbuffers.Builder builder + * @returns flatbuffers.Offset + */ +static endImageResize(builder:flatbuffers.Builder):flatbuffers.Offset { + var offset = builder.endObject(); + return offset; +}; + +} +/** + * @constructor + */ +export class ImageTransform { + bb: flatbuffers.ByteBuffer|null = null; + + bb_pos:number = 0; +/** + * @param number i + * @param flatbuffers.ByteBuffer bb + * @returns ImageTransform + */ +__init(i:number, bb:flatbuffers.ByteBuffer):ImageTransform { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param flatbuffers.ByteBuffer bb + * @param ImageTransform= obj + * @returns ImageTransform + */ +static getRootAsImageTransform(bb:flatbuffers.ByteBuffer, obj?:ImageTransform):ImageTransform { + return (obj || new ImageTransform).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns ImageTransformType + */ +transform():ImageTransformType { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? /** */ (this.bb!.readInt8(this.bb_pos + offset)) : ImageTransformType.WebPEncode; +}; + +/** + * @param ImageTransformType value + * @returns boolean + */ +mutate_transform(value:ImageTransformType):boolean { + var offset = this.bb!.__offset(this.bb_pos, 4); + + if (offset === 0) { + return false; + } + + this.bb!.writeInt8(this.bb_pos + offset, value); + return true; +}; + +/** + * @returns ImageTransformOptions + */ +optionsType():ImageTransformOptions { + var offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? /** */ (this.bb!.readUint8(this.bb_pos + offset)) : ImageTransformOptions.NONE; +}; + +/** + * @param ImageTransformOptions value + * @returns boolean + */ +mutate_options_type(value:ImageTransformOptions):boolean { + var offset = this.bb!.__offset(this.bb_pos, 6); + + if (offset === 0) { + return false; + } + + this.bb!.writeUint8(this.bb_pos + offset, value); + return true; +}; + +/** + * @param flatbuffers.Table obj + * @returns ?flatbuffers.Table + */ +options(obj:T):T|null { + var offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__union(obj, this.bb_pos + offset) : null; +}; + +/** + * @param flatbuffers.Builder builder + */ +static startImageTransform(builder:flatbuffers.Builder) { + builder.startObject(3); +}; + +/** + * @param flatbuffers.Builder builder + * @param ImageTransformType transform + */ +static addTransform(builder:flatbuffers.Builder, transform:ImageTransformType) { + builder.addFieldInt8(0, transform, ImageTransformType.WebPEncode); +}; + +/** + * @param flatbuffers.Builder builder + * @param ImageTransformOptions optionsType + */ +static addOptionsType(builder:flatbuffers.Builder, optionsType:ImageTransformOptions) { + builder.addFieldInt8(1, optionsType, ImageTransformOptions.NONE); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset optionsOffset + */ +static addOptions(builder:flatbuffers.Builder, optionsOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, optionsOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @returns flatbuffers.Offset + */ +static endImageTransform(builder:flatbuffers.Builder):flatbuffers.Offset { + var offset = builder.endObject(); + return offset; +}; + +} +/** + * @constructor + */ +export class ImageApplyTransforms { + bb: flatbuffers.ByteBuffer|null = null; + + bb_pos:number = 0; +/** + * @param number i + * @param flatbuffers.ByteBuffer bb + * @returns ImageApplyTransforms + */ +__init(i:number, bb:flatbuffers.ByteBuffer):ImageApplyTransforms { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param flatbuffers.ByteBuffer bb + * @param ImageApplyTransforms= obj + * @returns ImageApplyTransforms + */ +static getRootAsImageApplyTransforms(bb:flatbuffers.ByteBuffer, obj?:ImageApplyTransforms):ImageApplyTransforms { + return (obj || new ImageApplyTransforms).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param number index * @param ImageTransform= obj * @returns ImageTransform */ @@ -3775,6 +4455,81 @@ static endAcmeGetChallengeReady(builder:flatbuffers.Builder):flatbuffers.Offset return offset; }; +} +/** + * @constructor + */ +export class OsExit { + bb: flatbuffers.ByteBuffer|null = null; + + bb_pos:number = 0; +/** + * @param number i + * @param flatbuffers.ByteBuffer bb + * @returns OsExit + */ +__init(i:number, bb:flatbuffers.ByteBuffer):OsExit { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param flatbuffers.ByteBuffer bb + * @param OsExit= obj + * @returns OsExit + */ +static getRootAsOsExit(bb:flatbuffers.ByteBuffer, obj?:OsExit):OsExit { + return (obj || new OsExit).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns number + */ +code():number { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +}; + +/** + * @param number value + * @returns boolean + */ +mutate_code(value:number):boolean { + var offset = this.bb!.__offset(this.bb_pos, 4); + + if (offset === 0) { + return false; + } + + this.bb!.writeInt32(this.bb_pos + offset, value); + return true; +}; + +/** + * @param flatbuffers.Builder builder + */ +static startOsExit(builder:flatbuffers.Builder) { + builder.startObject(1); +}; + +/** + * @param flatbuffers.Builder builder + * @param number code + */ +static addCode(builder:flatbuffers.Builder, code:number) { + builder.addFieldInt32(0, code, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @returns flatbuffers.Offset + */ +static endOsExit(builder:flatbuffers.Builder):flatbuffers.Offset { + var offset = builder.endObject(); + return offset; +}; + } /** * @constructor @@ -4565,11 +5320,22 @@ headersLength():number { return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; }; +/** + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +remoteAddr():string|null +remoteAddr(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +remoteAddr(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + /** * @returns boolean */ hasBody():boolean { - var offset = this.bb!.__offset(this.bb_pos, 12); + var offset = this.bb!.__offset(this.bb_pos, 14); return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; }; @@ -4578,7 +5344,7 @@ hasBody():boolean { * @returns boolean */ mutate_has_body(value:boolean):boolean { - var offset = this.bb!.__offset(this.bb_pos, 12); + var offset = this.bb!.__offset(this.bb_pos, 14); if (offset === 0) { return false; @@ -4592,7 +5358,7 @@ mutate_has_body(value:boolean):boolean { * @param flatbuffers.Builder builder */ static startHttpRequest(builder:flatbuffers.Builder) { - builder.startObject(5); + builder.startObject(6); }; /** @@ -4648,12 +5414,20 @@ static startHeadersVector(builder:flatbuffers.Builder, numElems:number) { builder.startVector(4, numElems, 4); }; +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset remoteAddrOffset + */ +static addRemoteAddr(builder:flatbuffers.Builder, remoteAddrOffset:flatbuffers.Offset) { + builder.addFieldOffset(4, remoteAddrOffset, 0); +}; + /** * @param flatbuffers.Builder builder * @param boolean hasBody */ static addHasBody(builder:flatbuffers.Builder, hasBody:boolean) { - builder.addFieldInt8(4, +hasBody, +false); + builder.addFieldInt8(5, +hasBody, +false); }; /** @@ -5772,16 +6546,16 @@ static endSourceMapReady(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class DataPut { +export class AddEventListener { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns DataPut + * @returns AddEventListener */ -__init(i:number, bb:flatbuffers.ByteBuffer):DataPut { +__init(i:number, bb:flatbuffers.ByteBuffer):AddEventListener { this.bb_pos = i; this.bb = bb; return this; @@ -5789,82 +6563,56 @@ __init(i:number, bb:flatbuffers.ByteBuffer):DataPut { /** * @param flatbuffers.ByteBuffer bb - * @param DataPut= obj - * @returns DataPut + * @param AddEventListener= obj + * @returns AddEventListener */ -static getRootAsDataPut(bb:flatbuffers.ByteBuffer, obj?:DataPut):DataPut { - return (obj || new DataPut).__init(bb.readInt32(bb.position()) + bb.position(), bb); +static getRootAsAddEventListener(bb:flatbuffers.ByteBuffer, obj?:AddEventListener):AddEventListener { + return (obj || new AddEventListener).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; /** - * @param flatbuffers.Encoding= optionalEncoding - * @returns string|Uint8Array|null + * @returns EventType */ -collection():string|null -collection(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -collection(optionalEncoding?:any):string|Uint8Array|null { +event():EventType { var offset = this.bb!.__offset(this.bb_pos, 4); - return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; -}; - -/** - * @param flatbuffers.Encoding= optionalEncoding - * @returns string|Uint8Array|null - */ -key():string|null -key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -key(optionalEncoding?:any):string|Uint8Array|null { - var offset = this.bb!.__offset(this.bb_pos, 6); - return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; + return offset ? /** */ (this.bb!.readInt8(this.bb_pos + offset)) : EventType.Fetch; }; /** - * @param flatbuffers.Encoding= optionalEncoding - * @returns string|Uint8Array|null + * @param EventType value + * @returns boolean */ -json():string|null -json(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -json(optionalEncoding?:any):string|Uint8Array|null { - var offset = this.bb!.__offset(this.bb_pos, 8); - return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; -}; +mutate_event(value:EventType):boolean { + var offset = this.bb!.__offset(this.bb_pos, 4); -/** - * @param flatbuffers.Builder builder - */ -static startDataPut(builder:flatbuffers.Builder) { - builder.startObject(3); -}; + if (offset === 0) { + return false; + } -/** - * @param flatbuffers.Builder builder - * @param flatbuffers.Offset collectionOffset - */ -static addCollection(builder:flatbuffers.Builder, collectionOffset:flatbuffers.Offset) { - builder.addFieldOffset(0, collectionOffset, 0); + this.bb!.writeInt8(this.bb_pos + offset, value); + return true; }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset keyOffset */ -static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { - builder.addFieldOffset(1, keyOffset, 0); +static startAddEventListener(builder:flatbuffers.Builder) { + builder.startObject(1); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset jsonOffset + * @param EventType event */ -static addJson(builder:flatbuffers.Builder, jsonOffset:flatbuffers.Offset) { - builder.addFieldOffset(2, jsonOffset, 0); +static addEvent(builder:flatbuffers.Builder, event:EventType) { + builder.addFieldInt8(0, event, EventType.Fetch); }; /** * @param flatbuffers.Builder builder * @returns flatbuffers.Offset */ -static endDataPut(builder:flatbuffers.Builder):flatbuffers.Offset { +static endAddEventListener(builder:flatbuffers.Builder):flatbuffers.Offset { var offset = builder.endObject(); return offset; }; @@ -5873,16 +6621,16 @@ static endDataPut(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class DataGet { +export class LoadModule { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns DataGet + * @returns LoadModule */ -__init(i:number, bb:flatbuffers.ByteBuffer):DataGet { +__init(i:number, bb:flatbuffers.ByteBuffer):LoadModule { this.bb_pos = i; this.bb = bb; return this; @@ -5890,126 +6638,63 @@ __init(i:number, bb:flatbuffers.ByteBuffer):DataGet { /** * @param flatbuffers.ByteBuffer bb - * @param DataGet= obj - * @returns DataGet - */ -static getRootAsDataGet(bb:flatbuffers.ByteBuffer, obj?:DataGet):DataGet { - return (obj || new DataGet).__init(bb.readInt32(bb.position()) + bb.position(), bb); -}; - -/** - * @param flatbuffers.Encoding= optionalEncoding - * @returns string|Uint8Array|null - */ -collection():string|null -collection(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -collection(optionalEncoding?:any):string|Uint8Array|null { - var offset = this.bb!.__offset(this.bb_pos, 4); - return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; -}; - -/** - * @param flatbuffers.Encoding= optionalEncoding - * @returns string|Uint8Array|null - */ -key():string|null -key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -key(optionalEncoding?:any):string|Uint8Array|null { - var offset = this.bb!.__offset(this.bb_pos, 6); - return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; -}; - -/** - * @param flatbuffers.Builder builder - */ -static startDataGet(builder:flatbuffers.Builder) { - builder.startObject(2); -}; - -/** - * @param flatbuffers.Builder builder - * @param flatbuffers.Offset collectionOffset - */ -static addCollection(builder:flatbuffers.Builder, collectionOffset:flatbuffers.Offset) { - builder.addFieldOffset(0, collectionOffset, 0); -}; - -/** - * @param flatbuffers.Builder builder - * @param flatbuffers.Offset keyOffset - */ -static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { - builder.addFieldOffset(1, keyOffset, 0); -}; - -/** - * @param flatbuffers.Builder builder - * @returns flatbuffers.Offset - */ -static endDataGet(builder:flatbuffers.Builder):flatbuffers.Offset { - var offset = builder.endObject(); - return offset; -}; - -} -/** - * @constructor - */ -export class DataGetReady { - bb: flatbuffers.ByteBuffer|null = null; - - bb_pos:number = 0; -/** - * @param number i - * @param flatbuffers.ByteBuffer bb - * @returns DataGetReady - */ -__init(i:number, bb:flatbuffers.ByteBuffer):DataGetReady { - this.bb_pos = i; - this.bb = bb; - return this; + * @param LoadModule= obj + * @returns LoadModule + */ +static getRootAsLoadModule(bb:flatbuffers.ByteBuffer, obj?:LoadModule):LoadModule { + return (obj || new LoadModule).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; /** - * @param flatbuffers.ByteBuffer bb - * @param DataGetReady= obj - * @returns DataGetReady + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null */ -static getRootAsDataGetReady(bb:flatbuffers.ByteBuffer, obj?:DataGetReady):DataGetReady { - return (obj || new DataGetReady).__init(bb.readInt32(bb.position()) + bb.position(), bb); +specifierUrl():string|null +specifierUrl(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +specifierUrl(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; /** * @param flatbuffers.Encoding= optionalEncoding * @returns string|Uint8Array|null */ -json():string|null -json(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -json(optionalEncoding?:any):string|Uint8Array|null { - var offset = this.bb!.__offset(this.bb_pos, 4); +refererOriginUrl():string|null +refererOriginUrl(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +refererOriginUrl(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 6); return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; /** * @param flatbuffers.Builder builder */ -static startDataGetReady(builder:flatbuffers.Builder) { - builder.startObject(1); +static startLoadModule(builder:flatbuffers.Builder) { + builder.startObject(2); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset jsonOffset + * @param flatbuffers.Offset specifierUrlOffset */ -static addJson(builder:flatbuffers.Builder, jsonOffset:flatbuffers.Offset) { - builder.addFieldOffset(0, jsonOffset, 0); +static addSpecifierUrl(builder:flatbuffers.Builder, specifierUrlOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, specifierUrlOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset refererOriginUrlOffset + */ +static addRefererOriginUrl(builder:flatbuffers.Builder, refererOriginUrlOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, refererOriginUrlOffset, 0); }; /** * @param flatbuffers.Builder builder * @returns flatbuffers.Offset */ -static endDataGetReady(builder:flatbuffers.Builder):flatbuffers.Offset { +static endLoadModule(builder:flatbuffers.Builder):flatbuffers.Offset { var offset = builder.endObject(); return offset; }; @@ -6018,16 +6703,16 @@ static endDataGetReady(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class DataDel { +export class LoadModuleResp { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns DataDel + * @returns LoadModuleResp */ -__init(i:number, bb:flatbuffers.ByteBuffer):DataDel { +__init(i:number, bb:flatbuffers.ByteBuffer):LoadModuleResp { this.bb_pos = i; this.bb = bb; return this; @@ -6035,20 +6720,20 @@ __init(i:number, bb:flatbuffers.ByteBuffer):DataDel { /** * @param flatbuffers.ByteBuffer bb - * @param DataDel= obj - * @returns DataDel + * @param LoadModuleResp= obj + * @returns LoadModuleResp */ -static getRootAsDataDel(bb:flatbuffers.ByteBuffer, obj?:DataDel):DataDel { - return (obj || new DataDel).__init(bb.readInt32(bb.position()) + bb.position(), bb); +static getRootAsLoadModuleResp(bb:flatbuffers.ByteBuffer, obj?:LoadModuleResp):LoadModuleResp { + return (obj || new LoadModuleResp).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; /** * @param flatbuffers.Encoding= optionalEncoding * @returns string|Uint8Array|null */ -collection():string|null -collection(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -collection(optionalEncoding?:any):string|Uint8Array|null { +originUrl():string|null +originUrl(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +originUrl(optionalEncoding?:any):string|Uint8Array|null { var offset = this.bb!.__offset(this.bb_pos, 4); return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; @@ -6057,9 +6742,9 @@ collection(optionalEncoding?:any):string|Uint8Array|null { * @param flatbuffers.Encoding= optionalEncoding * @returns string|Uint8Array|null */ -key():string|null -key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -key(optionalEncoding?:any):string|Uint8Array|null { +sourceCode():string|null +sourceCode(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +sourceCode(optionalEncoding?:any):string|Uint8Array|null { var offset = this.bb!.__offset(this.bb_pos, 6); return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; @@ -6067,31 +6752,31 @@ key(optionalEncoding?:any):string|Uint8Array|null { /** * @param flatbuffers.Builder builder */ -static startDataDel(builder:flatbuffers.Builder) { +static startLoadModuleResp(builder:flatbuffers.Builder) { builder.startObject(2); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset collectionOffset + * @param flatbuffers.Offset originUrlOffset */ -static addCollection(builder:flatbuffers.Builder, collectionOffset:flatbuffers.Offset) { - builder.addFieldOffset(0, collectionOffset, 0); +static addOriginUrl(builder:flatbuffers.Builder, originUrlOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, originUrlOffset, 0); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset keyOffset + * @param flatbuffers.Offset sourceCodeOffset */ -static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) { - builder.addFieldOffset(1, keyOffset, 0); +static addSourceCode(builder:flatbuffers.Builder, sourceCodeOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, sourceCodeOffset, 0); }; /** * @param flatbuffers.Builder builder * @returns flatbuffers.Offset */ -static endDataDel(builder:flatbuffers.Builder):flatbuffers.Offset { +static endLoadModuleResp(builder:flatbuffers.Builder):flatbuffers.Offset { var offset = builder.endObject(); return offset; }; @@ -6100,16 +6785,16 @@ static endDataDel(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class DataDropCollection { +export class ServiceRequest { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns DataDropCollection + * @returns ServiceRequest */ -__init(i:number, bb:flatbuffers.ByteBuffer):DataDropCollection { +__init(i:number, bb:flatbuffers.ByteBuffer):ServiceRequest { this.bb_pos = i; this.bb = bb; return this; @@ -6117,44 +6802,94 @@ __init(i:number, bb:flatbuffers.ByteBuffer):DataDropCollection { /** * @param flatbuffers.ByteBuffer bb - * @param DataDropCollection= obj - * @returns DataDropCollection + * @param ServiceRequest= obj + * @returns ServiceRequest */ -static getRootAsDataDropCollection(bb:flatbuffers.ByteBuffer, obj?:DataDropCollection):DataDropCollection { - return (obj || new DataDropCollection).__init(bb.readInt32(bb.position()) + bb.position(), bb); +static getRootAsServiceRequest(bb:flatbuffers.ByteBuffer, obj?:ServiceRequest):ServiceRequest { + return (obj || new ServiceRequest).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns number + */ +id():number { + var offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0; +}; + +/** + * @param number value + * @returns boolean + */ +mutate_id(value:number):boolean { + var offset = this.bb!.__offset(this.bb_pos, 4); + + if (offset === 0) { + return false; + } + + this.bb!.writeUint32(this.bb_pos + offset, value); + return true; }; /** * @param flatbuffers.Encoding= optionalEncoding * @returns string|Uint8Array|null */ -collection():string|null -collection(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -collection(optionalEncoding?:any):string|Uint8Array|null { - var offset = this.bb!.__offset(this.bb_pos, 4); +sender():string|null +sender(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +sender(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + +/** + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +data():string|null +data(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +data(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 8); return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; /** * @param flatbuffers.Builder builder */ -static startDataDropCollection(builder:flatbuffers.Builder) { - builder.startObject(1); +static startServiceRequest(builder:flatbuffers.Builder) { + builder.startObject(3); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset collectionOffset + * @param number id */ -static addCollection(builder:flatbuffers.Builder, collectionOffset:flatbuffers.Offset) { - builder.addFieldOffset(0, collectionOffset, 0); +static addId(builder:flatbuffers.Builder, id:number) { + builder.addFieldInt32(0, id, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset senderOffset + */ +static addSender(builder:flatbuffers.Builder, senderOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, senderOffset, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset dataOffset + */ +static addData(builder:flatbuffers.Builder, dataOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, dataOffset, 0); }; /** * @param flatbuffers.Builder builder * @returns flatbuffers.Offset */ -static endDataDropCollection(builder:flatbuffers.Builder):flatbuffers.Offset { +static endServiceRequest(builder:flatbuffers.Builder):flatbuffers.Offset { var offset = builder.endObject(); return offset; }; @@ -6163,16 +6898,16 @@ static endDataDropCollection(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class AddEventListener { +export class ServiceResponse { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns AddEventListener + * @returns ServiceResponse */ -__init(i:number, bb:flatbuffers.ByteBuffer):AddEventListener { +__init(i:number, bb:flatbuffers.ByteBuffer):ServiceResponse { this.bb_pos = i; this.bb = bb; return this; @@ -6180,56 +6915,106 @@ __init(i:number, bb:flatbuffers.ByteBuffer):AddEventListener { /** * @param flatbuffers.ByteBuffer bb - * @param AddEventListener= obj - * @returns AddEventListener + * @param ServiceResponse= obj + * @returns ServiceResponse */ -static getRootAsAddEventListener(bb:flatbuffers.ByteBuffer, obj?:AddEventListener):AddEventListener { - return (obj || new AddEventListener).__init(bb.readInt32(bb.position()) + bb.position(), bb); +static getRootAsServiceResponse(bb:flatbuffers.ByteBuffer, obj?:ServiceResponse):ServiceResponse { + return (obj || new ServiceResponse).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; /** - * @returns EventType + * @returns number */ -event():EventType { +id():number { var offset = this.bb!.__offset(this.bb_pos, 4); - return offset ? /** */ (this.bb!.readInt8(this.bb_pos + offset)) : EventType.Fetch; + return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0; }; /** - * @param EventType value + * @param number value * @returns boolean */ -mutate_event(value:EventType):boolean { +mutate_id(value:number):boolean { var offset = this.bb!.__offset(this.bb_pos, 4); if (offset === 0) { return false; } - this.bb!.writeInt8(this.bb_pos + offset, value); + this.bb!.writeUint32(this.bb_pos + offset, value); + return true; +}; + +/** + * @returns boolean + */ +success():boolean { + var offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +}; + +/** + * @param boolean value + * @returns boolean + */ +mutate_success(value:boolean):boolean { + var offset = this.bb!.__offset(this.bb_pos, 6); + + if (offset === 0) { + return false; + } + + this.bb!.writeInt8(this.bb_pos + offset, +value); return true; }; +/** + * @param flatbuffers.Encoding= optionalEncoding + * @returns string|Uint8Array|null + */ +data():string|null +data(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +data(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +}; + /** * @param flatbuffers.Builder builder */ -static startAddEventListener(builder:flatbuffers.Builder) { - builder.startObject(1); +static startServiceResponse(builder:flatbuffers.Builder) { + builder.startObject(3); }; /** * @param flatbuffers.Builder builder - * @param EventType event + * @param number id */ -static addEvent(builder:flatbuffers.Builder, event:EventType) { - builder.addFieldInt8(0, event, EventType.Fetch); +static addId(builder:flatbuffers.Builder, id:number) { + builder.addFieldInt32(0, id, 0); +}; + +/** + * @param flatbuffers.Builder builder + * @param boolean success + */ +static addSuccess(builder:flatbuffers.Builder, success:boolean) { + builder.addFieldInt8(1, +success, +false); +}; + +/** + * @param flatbuffers.Builder builder + * @param flatbuffers.Offset dataOffset + */ +static addData(builder:flatbuffers.Builder, dataOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, dataOffset, 0); }; /** * @param flatbuffers.Builder builder * @returns flatbuffers.Offset */ -static endAddEventListener(builder:flatbuffers.Builder):flatbuffers.Offset { +static endServiceResponse(builder:flatbuffers.Builder):flatbuffers.Offset { var offset = builder.endObject(); return offset; }; @@ -6238,16 +7023,16 @@ static endAddEventListener(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class LoadModule { +export class RequestServiceRequest { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns LoadModule + * @returns RequestServiceRequest */ -__init(i:number, bb:flatbuffers.ByteBuffer):LoadModule { +__init(i:number, bb:flatbuffers.ByteBuffer):RequestServiceRequest { this.bb_pos = i; this.bb = bb; return this; @@ -6255,20 +7040,20 @@ __init(i:number, bb:flatbuffers.ByteBuffer):LoadModule { /** * @param flatbuffers.ByteBuffer bb - * @param LoadModule= obj - * @returns LoadModule + * @param RequestServiceRequest= obj + * @returns RequestServiceRequest */ -static getRootAsLoadModule(bb:flatbuffers.ByteBuffer, obj?:LoadModule):LoadModule { - return (obj || new LoadModule).__init(bb.readInt32(bb.position()) + bb.position(), bb); +static getRootAsRequestServiceRequest(bb:flatbuffers.ByteBuffer, obj?:RequestServiceRequest):RequestServiceRequest { + return (obj || new RequestServiceRequest).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; /** * @param flatbuffers.Encoding= optionalEncoding * @returns string|Uint8Array|null */ -moduleSpecifier():string|null -moduleSpecifier(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -moduleSpecifier(optionalEncoding?:any):string|Uint8Array|null { +destinationName():string|null +destinationName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +destinationName(optionalEncoding?:any):string|Uint8Array|null { var offset = this.bb!.__offset(this.bb_pos, 4); return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; @@ -6277,9 +7062,9 @@ moduleSpecifier(optionalEncoding?:any):string|Uint8Array|null { * @param flatbuffers.Encoding= optionalEncoding * @returns string|Uint8Array|null */ -containingFile():string|null -containingFile(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -containingFile(optionalEncoding?:any):string|Uint8Array|null { +data():string|null +data(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +data(optionalEncoding?:any):string|Uint8Array|null { var offset = this.bb!.__offset(this.bb_pos, 6); return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; @@ -6287,31 +7072,31 @@ containingFile(optionalEncoding?:any):string|Uint8Array|null { /** * @param flatbuffers.Builder builder */ -static startLoadModule(builder:flatbuffers.Builder) { +static startRequestServiceRequest(builder:flatbuffers.Builder) { builder.startObject(2); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset moduleSpecifierOffset + * @param flatbuffers.Offset destinationNameOffset */ -static addModuleSpecifier(builder:flatbuffers.Builder, moduleSpecifierOffset:flatbuffers.Offset) { - builder.addFieldOffset(0, moduleSpecifierOffset, 0); +static addDestinationName(builder:flatbuffers.Builder, destinationNameOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, destinationNameOffset, 0); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset containingFileOffset + * @param flatbuffers.Offset dataOffset */ -static addContainingFile(builder:flatbuffers.Builder, containingFileOffset:flatbuffers.Offset) { - builder.addFieldOffset(1, containingFileOffset, 0); +static addData(builder:flatbuffers.Builder, dataOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, dataOffset, 0); }; /** * @param flatbuffers.Builder builder * @returns flatbuffers.Offset */ -static endLoadModule(builder:flatbuffers.Builder):flatbuffers.Offset { +static endRequestServiceRequest(builder:flatbuffers.Builder):flatbuffers.Offset { var offset = builder.endObject(); return offset; }; @@ -6320,16 +7105,16 @@ static endLoadModule(builder:flatbuffers.Builder):flatbuffers.Offset { /** * @constructor */ -export class LoadModuleResp { +export class RequestServiceResponse { bb: flatbuffers.ByteBuffer|null = null; bb_pos:number = 0; /** * @param number i * @param flatbuffers.ByteBuffer bb - * @returns LoadModuleResp + * @returns RequestServiceResponse */ -__init(i:number, bb:flatbuffers.ByteBuffer):LoadModuleResp { +__init(i:number, bb:flatbuffers.ByteBuffer):RequestServiceResponse { this.bb_pos = i; this.bb = bb; return this; @@ -6337,82 +7122,75 @@ __init(i:number, bb:flatbuffers.ByteBuffer):LoadModuleResp { /** * @param flatbuffers.ByteBuffer bb - * @param LoadModuleResp= obj - * @returns LoadModuleResp + * @param RequestServiceResponse= obj + * @returns RequestServiceResponse */ -static getRootAsLoadModuleResp(bb:flatbuffers.ByteBuffer, obj?:LoadModuleResp):LoadModuleResp { - return (obj || new LoadModuleResp).__init(bb.readInt32(bb.position()) + bb.position(), bb); +static getRootAsRequestServiceResponse(bb:flatbuffers.ByteBuffer, obj?:RequestServiceResponse):RequestServiceResponse { + return (obj || new RequestServiceResponse).__init(bb.readInt32(bb.position()) + bb.position(), bb); }; /** - * @param flatbuffers.Encoding= optionalEncoding - * @returns string|Uint8Array|null + * @returns boolean */ -moduleId():string|null -moduleId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -moduleId(optionalEncoding?:any):string|Uint8Array|null { +success():boolean { var offset = this.bb!.__offset(this.bb_pos, 4); - return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; }; /** - * @param flatbuffers.Encoding= optionalEncoding - * @returns string|Uint8Array|null + * @param boolean value + * @returns boolean */ -fileName():string|null -fileName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -fileName(optionalEncoding?:any):string|Uint8Array|null { - var offset = this.bb!.__offset(this.bb_pos, 6); - return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +mutate_success(value:boolean):boolean { + var offset = this.bb!.__offset(this.bb_pos, 4); + + if (offset === 0) { + return false; + } + + this.bb!.writeInt8(this.bb_pos + offset, +value); + return true; }; /** * @param flatbuffers.Encoding= optionalEncoding * @returns string|Uint8Array|null */ -sourceCode():string|null -sourceCode(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null -sourceCode(optionalEncoding?:any):string|Uint8Array|null { - var offset = this.bb!.__offset(this.bb_pos, 8); +data():string|null +data(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +data(optionalEncoding?:any):string|Uint8Array|null { + var offset = this.bb!.__offset(this.bb_pos, 6); return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; }; /** * @param flatbuffers.Builder builder */ -static startLoadModuleResp(builder:flatbuffers.Builder) { - builder.startObject(3); -}; - -/** - * @param flatbuffers.Builder builder - * @param flatbuffers.Offset moduleIdOffset - */ -static addModuleId(builder:flatbuffers.Builder, moduleIdOffset:flatbuffers.Offset) { - builder.addFieldOffset(0, moduleIdOffset, 0); +static startRequestServiceResponse(builder:flatbuffers.Builder) { + builder.startObject(2); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset fileNameOffset + * @param boolean success */ -static addFileName(builder:flatbuffers.Builder, fileNameOffset:flatbuffers.Offset) { - builder.addFieldOffset(1, fileNameOffset, 0); +static addSuccess(builder:flatbuffers.Builder, success:boolean) { + builder.addFieldInt8(0, +success, +false); }; /** * @param flatbuffers.Builder builder - * @param flatbuffers.Offset sourceCodeOffset + * @param flatbuffers.Offset dataOffset */ -static addSourceCode(builder:flatbuffers.Builder, sourceCodeOffset:flatbuffers.Offset) { - builder.addFieldOffset(2, sourceCodeOffset, 0); +static addData(builder:flatbuffers.Builder, dataOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, dataOffset, 0); }; /** * @param flatbuffers.Builder builder * @returns flatbuffers.Offset */ -static endLoadModuleResp(builder:flatbuffers.Builder):flatbuffers.Offset { +static endRequestServiceResponse(builder:flatbuffers.Builder):flatbuffers.Offset { var offset = builder.endObject(); return offset; }; diff --git a/v8env/src/os.ts b/v8env/src/os.ts new file mode 100644 index 0000000..75bc9dc --- /dev/null +++ b/v8env/src/os.ts @@ -0,0 +1,13 @@ +import * as fbs from "./msg_generated"; +import * as flatbuffers from "./flatbuffers"; +import { sendSync } from "./bridge"; +import { assert } from "./util"; + +export function exit(code: number) { + const builder = flatbuffers.createBuilder(); + fbs.OsExit.startOsExit(builder); + fbs.OsExit.addCode(builder, code); + const msg = fbs.OsExit.endOsExit(builder); + const res = sendSync(builder, fbs.Any.OsExit, msg); + assert(res == null); +} \ No newline at end of file diff --git a/v8env/src/response.ts b/v8env/src/response.ts index a7ff4e8..fba1124 100644 --- a/v8env/src/response.ts +++ b/v8env/src/response.ts @@ -36,7 +36,10 @@ export class FlyResponse extends FlyBody implements Response { if (arguments.length < 1) body = ''; - super(body) + if (init instanceof FlyResponse) + super(body || init.body) + else + super(body) init = Object(init) || {}; diff --git a/v8env/src/service.ts b/v8env/src/service.ts new file mode 100644 index 0000000..a7405f5 --- /dev/null +++ b/v8env/src/service.ts @@ -0,0 +1,28 @@ + +export class ServiceRequest { + + constructor( + readonly sender: string, + private readonly dataJson: string, + ) { + } + + get data(): any { + return JSON.parse(this.dataJson); + } + +} + +export class ServiceResponse { + + constructor( + readonly success: boolean, + readonly data: any, + ) { + } + + get dataJson(): string { + return JSON.stringify(this.data); + } + +} \ No newline at end of file diff --git a/v8env/src/service_request.ts b/v8env/src/service_request.ts new file mode 100644 index 0000000..0dcee65 --- /dev/null +++ b/v8env/src/service_request.ts @@ -0,0 +1,35 @@ +import * as fbs from "./msg_generated"; +import * as flatbuffers from "./flatbuffers" +import { sendSync } from "./bridge"; + +export interface ServiceResponse { + success: boolean; + data: any; +} + +/** + * + * @param destinationName The `ServiceName` of the service you want to send this to. + * @param data The data retured by said service. + */ +export function serviceRequest(destinationName: string, data: any): ServiceResponse { + const fbb = flatbuffers.createBuilder(); + + const destinationNameString = fbb.createString(destinationName); + const dataString = fbb.createString(JSON.stringify(data)); + + fbs.RequestServiceRequest.startRequestServiceRequest(fbb); + fbs.RequestServiceRequest.addDestinationName(fbb, destinationNameString); + fbs.RequestServiceRequest.addData(fbb, dataString); + + const resp = sendSync(fbb, fbs.Any.RequestServiceRequest, fbs.RequestServiceRequest.endRequestServiceRequest(fbb)); + + const msg = new fbs.RequestServiceResponse(); + // Write message data to handle + resp.msg(msg); + + return { + success: msg.success(), + data: JSON.parse(msg.data()), + } +} \ No newline at end of file diff --git a/v8env/src/source_maps.ts b/v8env/src/source_maps.ts index 672ea7e..1749479 100644 --- a/v8env/src/source_maps.ts +++ b/v8env/src/source_maps.ts @@ -52,4 +52,13 @@ export function prepareStackTrace(error: Error, stack: CallSite[]): string { frames[i] = `\n at ${frame.name()} (${frame.filename()}:${frame.line()}:${frame.col()})`; } return error.toString() + frames.join(""); +} + +const v8envFilter = /v8env/; + +/** + * Remove non-app frames from a stack trace + */ +export function filterStackTrace(stackTrace: string) { + return stackTrace.split("\n").filter(l => !v8envFilter.test(l)).join("\n").trim(); } \ No newline at end of file diff --git a/v8env/src/test_main.ts b/v8env/src/test_main.ts deleted file mode 100644 index e0e7866..0000000 --- a/v8env/src/test_main.ts +++ /dev/null @@ -1,42 +0,0 @@ - -import { globalEval } from './global-eval' -// import * as expect from "expect" -// import * as Mocha from "mocha" -// import * as chai from "chai" -// var expect = require('chai').expect - -declare var mocha: any - -const window = globalEval("this"); -if (window.global === undefined) { - window.global = window -} - -window.global.global.location = {} - -// window.expect = chai.expect - -// console.log("mocha", Mocha) -// console.log("mocha", mocha) -// console.log("window", window) -// console.log("expect", expect) - -// const mocha = new Mocha({ -// ui: 'bdd', -// reporter: 'spec', -// useColors: true -// }) -// mocha.suite. -// window.expect = expect -// window.mocha = mocha -// window.Mocha = mocha - -// window.test = Mocha.test -// window.it = Mocha.it -// window.describe = Mocha.describe - - -// window.runTests = function testMain() { -// mocha.run() -// } -// export default \ No newline at end of file diff --git a/v8env/src/typescript-compiler-service/index.ts b/v8env/src/typescript-compiler-service/index.ts new file mode 100644 index 0000000..aaf6725 --- /dev/null +++ b/v8env/src/typescript-compiler-service/index.ts @@ -0,0 +1,5 @@ + + +class FlyTypescriptCompilerService { + +} \ No newline at end of file diff --git a/v8env/src/url.ts b/v8env/src/url.ts index 6fc7d82..c758f6b 100644 --- a/v8env/src/url.ts +++ b/v8env/src/url.ts @@ -1,3 +1,8 @@ +/** + * @module fetch + * @ignore + */ + /* inspired from https://raw.githubusercontent.com/github/url-polyfill/master/url.js @@ -126,7 +131,7 @@ export class URL { password: baseParts.password, hostname: baseParts.hostname, port: baseParts.port, - path: urlParts.path || baseParts.path, + path: resolvePathFromBase(urlParts.path, baseParts.path), query: urlParts.query || baseParts.query, hash: urlParts.hash } @@ -205,6 +210,7 @@ export class URL { .toString() .split("/") .map(encodePathSegment) + .map(segment => segment.replace(/%25/g, "%")) if (chunks[0]) { // ensure joined string starts with slash. chunks.unshift("") @@ -275,4 +281,15 @@ export class URL { } } +/* one off logic to fix buggy url implementation */ +function resolvePathFromBase(path: string, basePath: string) { + if (path.startsWith("/")) { + return path + } + if (basePath.endsWith("/")) { + return basePath + path + } + return basePath + "/" + path +} + URL.init() diff --git a/v8env/src/util.ts b/v8env/src/util.ts index b4c0da7..8cf6265 100644 --- a/v8env/src/util.ts +++ b/v8env/src/util.ts @@ -33,11 +33,18 @@ export function typedArrayToArrayBuffer(ta: TypedArray): ArrayBuffer { return ab as ArrayBuffer; } -// @internal -export function arrayToStr(ui8: Uint8Array): string { +export function arrayBufferToString(ab: ArrayBuffer): string { + return new TextDecoder("utf-8").decode(ab); +} + +export function arrayToString(ui8: Uint8Array): string { return String.fromCharCode(...ui8); } +export function stringToArrayBuffer(str: string): ArrayBuffer { + return new TextEncoder().encode(str); +} + /** * A `Resolvable` is a Promise with the `reject` and `resolve` functions * placed as methods on the promise object itself. It allows you to do: @@ -100,4 +107,19 @@ export function containsOnlyASCII(str: string): boolean { return false; } return /^[\x00-\x7F]*$/.test(str); -} \ No newline at end of file +} + +// @internal +export function isError(err: any): err is Error { + return err instanceof Error || (err && typeof err.message === 'string'); +} + +export function isIterable(obj: Array | IterableIterator | any): obj is IterableIterator { + if (obj == null) { + return false; + } + if (typeof obj !== "object") { + return false; + } + return typeof obj[Symbol.iterator] === 'function'; +} diff --git a/v8env/src/util/format.ts b/v8env/src/util/format.ts new file mode 100644 index 0000000..d23498a --- /dev/null +++ b/v8env/src/util/format.ts @@ -0,0 +1,14 @@ + +export function stringifyTypeName(value: any): string { + if (value === undefined) { + return 'undefined'; + } else if (value === null) { + return 'null'; + // } else if (Buffer.isBuffer(value)) { + // return 'buffer'; + } + return Object.prototype.toString + .call(value) + .replace(/^\[.+\s(.+?)]$/, '$1') + .toLowerCase(); +} diff --git a/v8env/testing/run.js b/v8env/testing/run.js deleted file mode 100644 index bbba525..0000000 --- a/v8env/testing/run.js +++ /dev/null @@ -1,6 +0,0 @@ -// mocha will complain otherwise -global.location = {} - -mocha.run((failures) => { - _mocha_done.apply(null, [failures]) -}) \ No newline at end of file diff --git a/v8env/testing/setup.js b/v8env/testing/setup.js deleted file mode 100644 index 7054a9b..0000000 --- a/v8env/testing/setup.js +++ /dev/null @@ -1 +0,0 @@ -mocha.setup({ ui: 'bdd', reporter: 'spec', useColors: true }) \ No newline at end of file diff --git a/v8env/tests/async.spec.ts b/v8env/tests/async.spec.ts new file mode 100644 index 0000000..4818972 --- /dev/null +++ b/v8env/tests/async.spec.ts @@ -0,0 +1,31 @@ +declare var test: any; +declare var expect: any; + +test("allow promise handlers after rejection", (done) => { + const promise = Promise.reject("boom").then(_ => { + done("`then` should not be excuted"); + }).catch(err => { + if (err !== "boom") { + done("Expected error to === boom"); + } else { + done(); + } + }); +}) + +test("catch in async function", (done) => { + async function thrower() { + throw new Error("boom"); + } + + async function caller() { + try { + await thrower(); + expect.fail("catch block not invoked") + } catch (err) { + expect(err.message).to.eql("boom"); + } + } + + caller().then(done).catch(done); +}) \ No newline at end of file diff --git a/v8env/tests/cookie_jar.spec.js b/v8env/tests/cookie_jar.spec.js new file mode 100644 index 0000000..871bb2c --- /dev/null +++ b/v8env/tests/cookie_jar.spec.js @@ -0,0 +1,25 @@ +describe("cookies", () => { + it("gets cookie values", () => { + const req = new Request("http://example.com", { + headers: { + cookie: "foo=bar;hello=world;" + } + }) + const foo = req.cookies.get("foo").value + const hello = req.cookies.get("hello").value + const no = req.cookies.get("no") + + expect(foo).to.eq("bar") + expect(hello).to.eq("world") + expect(no).to.eq(undefined) + }) + + it("creates right set-cookie header", () => { + const resp = new Response("hello") + resp.cookies.append("test1", "val1", { maxAge: 1000 }) + resp.cookies.append("test2", "val2") + + const setCookie = resp.headers.get("set-cookie") + expect(setCookie).to.eq("test1=val1; Max-Age=1000, test2=val2") + }) +}) diff --git a/v8env/tests/crypto.spec.js b/v8env/tests/crypto.spec.js index 1502430..bc8c44e 100644 --- a/v8env/tests/crypto.spec.js +++ b/v8env/tests/crypto.spec.js @@ -10,26 +10,6 @@ describe("crypto", () => { expect(hash).to.be.instanceof(ArrayBuffer) }) - it("creates a hash synchronously", () => { - let hash = crypto.subtle.digestSync("SHA-1", (new TextEncoder('utf-8')).encode("hello world")) - expect(hash).to.be.instanceof(ArrayBuffer) - }) - - it("creates a hash synchronously from a string", () => { - let hash = crypto.subtle.digestSync("SHA-1", "hello world") - expect(hash).to.be.instanceof(ArrayBuffer) - }) - - it("produces a string with encoding", async () => { - let hash = await crypto.subtle.digest("SHA-1", "hello world", "hex") - expect(typeof hash).to.equal("string") - }) - - it("produces a string with encoding synchronously", () => { - let hash = crypto.subtle.digestSync("SHA-1", "hello world", "hex") - expect(typeof hash).to.equal("string") - }) - it.skip("errors on bad algo", (done) => { let ret = crypto.subtle.digest("SHA-123", '') .then(() => { done(new Error("should've thrown!")) }) @@ -38,10 +18,6 @@ describe("crypto", () => { done() }) }) - - it.skip("errors on bad algo (sync)", () => { - expect(function () { crypto.subtle.digestSync("SHA-123", '') }).to.throw("Digest method not supported") - }) }) describe("getRandomValues", () => { it("fills the Uint8Array", () => { diff --git a/v8env/tests/data.spec.js b/v8env/tests/data.spec.js index 1334753..b3dc008 100644 --- a/v8env/tests/data.spec.js +++ b/v8env/tests/data.spec.js @@ -1,46 +1,154 @@ -// import db, { Collection } from '@fly/data' - -// describe('@fly/data', () => { -// describe('.collection', () => { -// it("returns a Collection", () => { -// expect(db.collection("testing")).to.be.instanceOf(Collection) -// }) -// }) - -// describe("Collection", () => { -// describe(".put", () => { -// it("upserts data", async () => { -// const coll = db.collection("testing") - -// // insert initial object -// let ok = await coll.put("yo", { some: "json" }) -// expect(ok).to.be.true - -// // replace the object -// ok = await coll.put("yo", { some: "json2" }) -// expect(ok).to.be.true - -// // get the obj, to assert its value -// const res = await coll.get("yo") -// expect(res).to.deep.equal({ some: "json2" }) -// }) -// after(async () => { -// await db.dropCollection("testing") -// }) -// }) - -// describe(".del", () => { -// it("delete data", async () => { -// const coll = db.collection("testing") -// const ok = await coll.put("yo", { some: "json" }) -// expect(ok).to.be.true - -// const okDel = await coll.del("yo") -// expect(okDel).to.equal(true) - -// const res = await coll.get("yo") -// expect(res).to.equal(null) -// }) -// }) -// }) -// }) \ No newline at end of file +const db = fly.data; + +describe('@fly/data', () => { + describe("collection()", () => { + test("returns a Collection", () => { + expect(db.collection("testing")).to.be.instanceOf(fly.data.Collection) + }) + }) + + describe("Collection", () => { + describe("put+get", () => { + afterEach(async () => db.dropCollection("testing")) + + describe("accepts value type", () => { + const cases = [ + ["Object", { name: "Michael" }], + ["String", "Michael"], + ["Array", ["Michael", "Dwan"]], + ] + + for (const [name, val] of cases) { + test(name, async () => { + const coll = db.collection("testing") + + expect( + await coll.put("key", val) + ).to.be.true + + expect( + await coll.get("key") + ).to.eql(val) + }) + } + }) + + describe("rejects value type", () => { + const cases = [ + ["Number", 123], + ["undefined", undefined], + ["null", null], + ] + + for (const [name, val] of cases) { + test(name, async () => { + const coll = db.collection("testing") + + try { + await coll.put("key", val) + expect.fail(`value type ${name} should be rejected`) + } catch (err) { + expect(err).to.be.an.instanceOf(TypeError) + } + }) + } + }) + + test("upserts data", async () => { + const coll = db.collection("testing") + + // insert initial object + let ok = await coll.put("yo", { some: "json" }) + expect(ok).to.be.true + + // replace the object + ok = await coll.put("yo", { some: "json2" }) + expect(ok).to.be.true + + // get the obj, to assert its value + const res = await coll.get("yo") + expect(res).to.deep.equal({ some: "json2" }) + }) + + test("get with missing key", async () => { + const coll = db.collection("testing") + + let result = await coll.get("missing-key"); + expect(result).to.be.null; + }) + }) + + describe(".del", () => { + it("delete data", async () => { + const coll = db.collection("testing") + const ok = await coll.put("yo", { some: "json" }) + expect(ok).to.be.true + + const okDel = await coll.del("yo") + expect(okDel).to.equal(true) + + const res = await coll.get("yo") + expect(res).to.equal(null) + }) + }) + + describe("increment", () => { + test("works", async () => { + const coll = db.collection("testing") + + expect( + await coll.put("inc-test", { count: 1 }) + ).to.eq(true) + + expect( + await coll.increment("inc-test", "count") + ).to.be.true + + expect( + await coll.get("inc-test") + ).to.eql({ count: 2 }) + + expect( + await coll.increment("inc-test", "count", 5) + ).to.be.true + + expect( + await coll.get("inc-test") + ).to.eql({ count: 7 }) + }) + + test("with negative number", async () => { + const coll = db.collection("testing") + + expect( + await coll.put("inc-test", { count: 8 }) + ).to.eq(true) + + expect( + await coll.increment("inc-test", "count", -5) + ).to.be.true + + expect( + await coll.get("inc-test") + ).to.eql({ count: 3 }) + }) + + + test("preserves other keys", async () => { + const coll = db.collection("testing") + + expect( + await coll.put("inc-test", { another:"key", count: 1 }) + ).to.eq(true) + + expect( + await coll.increment("inc-test", "count") + ).to.be.true + + expect( + await coll.get("inc-test") + ).to.eql({ another: "key", count: 2 }) + }) + }) + }) +}) \ No newline at end of file diff --git a/v8env/tests/fetch.mount.spec.js b/v8env/tests/fetch.mount.spec.js deleted file mode 100644 index 4d2a862..0000000 --- a/v8env/tests/fetch.mount.spec.js +++ /dev/null @@ -1,29 +0,0 @@ -// import mount from '@fly/fetch/mount' - -// const mounts = mount({ -// "/root/first-path/": (req, init) => new Response("/first-path/"), -// "/root/first-path/impossible": (req, init) => { throw new Error("no yuo") }, -// "/root/another/": (req, init) => new Response("/another/"), -// "/root/": (req, init) => new Response("root") -// }) -// describe("mount", () => { -// it("finds early path", async () => { -// const resp = await mounts("http://test/root/first-path/") -// const body = await resp.text() -// expect(body).to.eq("/first-path/") -// }) -// it("finds later path", async () => { -// const resp = await mounts("http://test/root/another/thing/") -// const body = await resp.text() -// expect(body).to.eq("/another/") -// }) -// it('falls through to default', async () => { -// const resp = await mounts("http://test/root/") -// const body = await resp.text() -// expect(body).to.eq("root") -// }) -// it("404s when no match", async () => { -// const resp = await mounts("http://test/") -// expect(resp.status).to.eq(404) -// }) -// }) \ No newline at end of file diff --git a/v8env/tests/fetch.pipeline.spec.js b/v8env/tests/fetch.pipeline.spec.js deleted file mode 100644 index 063af38..0000000 --- a/v8env/tests/fetch.pipeline.spec.js +++ /dev/null @@ -1,55 +0,0 @@ -// import { expect } from 'chai' - -// import pipeline from '@fly/fetch/pipeline' - -// function outer(fetch) { -// return async function outerFetch(req, init) { -// req.headers.set("Outer-Fn", "woop!") -// return fetch(req, init) -// } -// } - -// function inner(fetch) { -// return async function innerFetch(req, init) { -// req.headers.set("Inner-Fn", "woowoo!") -// return fetch(req, init) -// } -// } - -// function echo(req, init) { -// const headers = Object.assign({ -// stages: JSON.stringify(fn.stages.map((s) => { -// if (typeof s === "function") { -// return s.name -// } -// return typeof s -// })) -// }, req.headers.toJSON()) -// return new Response("hi", { headers: headers }) -// } - -// const p = pipeline(outer, inner) -// const fn = p(echo) - -// describe("pipeline", () => { -// it("should make stages available", () => { -// expect(p.stages).to.exist -// expect(p.stages.length).to.eq(2) -// expect(p.stages[0]).to.eq(outer) -// expect(p.stages[1]).to.eq(inner) -// }) - -// it("should make stages available after fetch is generated", () => { -// expect(fn.stages).to.exist -// expect(fn.stages.length).to.eq(2) -// expect(fn.stages[0]).to.eq(outer) -// expect(fn.stages[1]).to.eq(inner) -// }) - -// it('should run pipeline functions', async () => { -// const resp = await fn(new Request("http://localhost")) -// expect(resp.headers.get("Outer-Fn")).to.eq("woop!") -// expect(resp.headers.get("Inner-Fn")).to.eq("woowoo!") -// expect(resp.headers.get("stages")).to.eq('["outer","inner"]') -// }) -// }) \ No newline at end of file diff --git a/v8env/tests/fetch.proxy.spec.js b/v8env/tests/fetch.proxy.spec.js deleted file mode 100644 index 0ed5817..0000000 --- a/v8env/tests/fetch.proxy.spec.js +++ /dev/null @@ -1,29 +0,0 @@ -// import { expect } from 'chai' - -// import * as proxy from '@fly/proxy' - -// const origin = "https://fly.io/proxy/" -// const req = new Request("https://wat.com/path/to/thing", { headers: { "host": "notwat.com" } }) -// describe("proxy", () => { -// it('includes host header and base path properly', () => { -// const breq = proxy.buildProxyRequest(origin, {}, req) -// const url = new URL(breq.url) -// expect(breq.headers.get("host")).to.eq("fly.io") -// expect(breq.headers.get("x-forwarded-host")).to.eq("notwat.com") -// expect(url.pathname).to.eq("/proxy/path/to/thing") -// }) - -// it('includes host header from request when forwardHostHeader', () => { -// const breq = proxy.buildProxyRequest(origin, { forwardHostHeader: true }, req) -// const url = new URL(breq.url) -// expect(breq.headers.get("host")).to.eq("notwat.com") -// expect(breq.headers.get("x-forwarded-host")).to.eq("notwat.com") -// expect(url.pathname).to.eq("/proxy/path/to/thing") -// }) - -// it('rewrite paths properly', () => { -// const breq = proxy.buildProxyRequest(origin, { stripPath: "/path/to/" }, req) -// const url = new URL(breq.url) -// expect(url.pathname).to.eq("/proxy/thing") -// }) -// }) \ No newline at end of file diff --git a/v8env/tests/fixtures/test-stream.ts b/v8env/tests/fixtures/test-stream.ts new file mode 100644 index 0000000..f39209c --- /dev/null +++ b/v8env/tests/fixtures/test-stream.ts @@ -0,0 +1,25 @@ +export function testStream(content: string, delay: 5) { + return new ReadableStream({ + start(controller) { + const encoder = new TextEncoder(); + const chunkSize = 1; + let pos = 0; + + function push() { + if (pos >= content.length) { + controller.close(); + return; + } + + controller.enqueue( + encoder.encode(content.slice(pos, pos + chunkSize)) + ); + + pos += chunkSize; + + setTimeout(push, delay); + } + push(); + } + }); +} diff --git a/v8env/tests/fly.cache.notifier.spec.js b/v8env/tests/fly.cache.notifier.spec.js index 1a24651..08c7fd4 100644 --- a/v8env/tests/fly.cache.notifier.spec.js +++ b/v8env/tests/fly.cache.notifier.spec.js @@ -1,33 +1,31 @@ -// import { expect } from "chai" +const cache = fly.cache; -// import cache from "@fly/cache" +function sleep(timeout) { + return new Promise((resolve, ) => { + setTimeout(resolve, timeout) + }) +} +describe("@fly/cache/global", () => { + it.skip("sends del notification", async () => { + const key = "notifier_test_key_" + Math.random() + await cache.set(key, "asdf") + await cache.global.del(key) -// function sleep(timeout) { -// return new Promise((resolve, ) => { -// setTimeout(resolve, timeout) -// }) -// } -// describe("@fly/cache/global", () => { -// it("sends del notification", async () => { -// const key = "notifier_test_key_" + Math.random() -// await cache.set(key, "asdf") -// await cache.global.del(key) + // TODO: this can be race-y, global del is not guaranteed to happen before the next read + await sleep(20) + const res = await cache.getString(key) + expect(res).to.eq(null) -// // TODO: this can be race-y, global del is not guaranteed to happen before the next read -// await sleep(20) -// const res = await cache.getString(key) -// expect(res).to.eq(null) + }) -// }) + it.skip("sends purgeTag notifications", async () => { + const key = "purge_test_key_" + Math.random() + await cache.set(key, "jklm", { tags: ["purge_test"] }) -// it("sends purgeTag notifications", async () => { -// const key = "purge_test_key_" + Math.random() -// await cache.set(key, "jklm", { tags: ["purge_test"] }) + await cache.global.purgeTag("purge_test") -// await cache.global.purgeTag("purge_test") - -// await sleep(20) -// const res = await cache.getString(key) -// expect(res).to.eq(null) -// }) -// }) \ No newline at end of file + await sleep(20) + const res = await cache.getString(key) + expect(res).to.eq(null) + }) +}) \ No newline at end of file diff --git a/v8env/tests/fly.cache.response.spec.js b/v8env/tests/fly.cache.response.spec.js index 0edcf83..a2f051c 100644 --- a/v8env/tests/fly.cache.response.spec.js +++ b/v8env/tests/fly.cache.response.spec.js @@ -1,81 +1,77 @@ -// import { expect } from 'chai' - -// import cache, { responseCache } from "@fly/cache" - -// let counter = 0 -// async function makeResponse(initResponseOptions, setCacheOptions) { -// let key = `cache-test-key-${counter++}` -// const responseInitOptions = Object.assign({ status: 404 }, initResponseOptions) -// const resp = new Response("hi", responseInitOptions) -// const setResult = await responseCache.set(key, resp, setCacheOptions) - -// expect(setResult).to.eq(true) -// return [key, resp] -// } -// describe("@fly/cache/response", () => { -// it("sets a Response", async () => { -// const [key, resp] = await makeResponse() -// const cachedResponse = await responseCache.get(key) - -// expect(cachedResponse).instanceOf(Response) -// const cachedBody = await cachedResponse.text() -// const body = await resp.text() - -// expect(cachedBody).to.eq(body) -// expect(cachedResponse.status).to.eq(404) -// }) - -// it("sets a Response with headers", async () => { -// const [key, resp] = await makeResponse({ headers: { "authorization": "foo", "content-type": "text/plain; charset=utf-8" } }) -// const cachedResponse = await responseCache.get(key) - -// expect(cachedResponse).instanceOf(Response) -// const cachedBody = await cachedResponse.text() -// const body = await resp.text() - -// expect(cachedBody).to.eq(body) -// expect(cachedResponse.status).to.eq(404) - -// const meta = await responseCache.getMeta(key) -// expect(meta.headers["authorization"]).to.eq(undefined) -// expect(meta.headers["content-type"]).to.eq("text/plain; charset=utf-8") -// }) - -// it("sets a Response with headers, and custom skip-headers", async () => { -// const [key, resp] = await makeResponse({ -// headers: { -// "authorization": "foo", -// "content-type": "text/plain; charset=utf-8", -// "content-length": "538", -// "content-encoding": "gzip" -// } -// }, { skipCacheHeaders: ["content-length"] }) -// const cachedResponse = await responseCache.get(key) - -// expect(cachedResponse).instanceOf(Response) -// const cachedBody = await cachedResponse.text() -// const body = await resp.text() - -// expect(cachedBody).to.eq(body) -// expect(cachedResponse.status).to.eq(404) - -// const meta = await responseCache.getMeta(key) -// expect(meta.headers["authorization"]).to.eq(undefined) -// expect(meta.headers["content-length"]).to.eq(undefined) -// expect(meta.headers["content-type"]).to.eq("text/plain; charset=utf-8") -// expect(meta.headers["content-encoding"]).to.eq("gzip") -// }) - -// it("deletes a response", async () => { -// const [key, resp] = await makeResponse() -// const delResult = await responseCache.del(key) -// expect(delResult).to.eq(true) - -// const meta = await cache.get(key + ":meta") -// expect(meta).to.eq(null) - -// const body = await cache.get(key + ":body") -// expect(body).to.eq(null) -// }) - -// }) \ No newline at end of file +const cache = fly.cache; +const responseCache = fly.responseCache; + +let counter = 0 +async function makeResponse(initResponseOptions, setCacheOptions) { + let key = `cache-test-key-${counter++}` + const responseInitOptions = Object.assign({ status: 404 }, initResponseOptions) + const resp = new Response("hi", responseInitOptions) + const setResult = await responseCache.set(key, resp, setCacheOptions) + + expect(setResult).to.eq(true) + return [key, resp] +} +describe("@fly/cache/response", () => { + it("sets a Response", async () => { + const [key, resp] = await makeResponse() + const cachedResponse = await responseCache.get(key) + + expect(cachedResponse).instanceOf(Response) + const cachedBody = await cachedResponse.text() + const body = await resp.text() + + expect(cachedBody).to.eq(body) + expect(cachedResponse.status).to.eq(404) + }) + + it("sets a Response with headers", async () => { + const [key, resp] = await makeResponse({ headers: { "authorization": "foo", "content-type": "text/plain; charset=utf-8" } }) + const cachedResponse = await responseCache.get(key) + + expect(cachedResponse).instanceOf(Response) + const cachedBody = await cachedResponse.text() + const body = await resp.text() + + expect(cachedBody).to.eq(body) + expect(cachedResponse.status).to.eq(404) + expect(cachedResponse.headers.get("authorization")).to.be.null + expect(cachedResponse.headers.get("content-type")).to.eq("text/plain; charset=utf-8") + }) + + it("sets a Response with headers, and custom skip-headers", async () => { + const [key, resp] = await makeResponse({ + headers: { + "authorization": "foo", + "content-type": "text/plain; charset=utf-8", + "content-length": "538", + "content-encoding": "gzip" + } + }, { skipCacheHeaders: ["content-length"] }) + const cachedResponse = await responseCache.get(key) + + expect(cachedResponse).instanceOf(Response) + const cachedBody = await cachedResponse.text() + const body = await resp.text() + + expect(cachedBody).to.eq(body) + expect(cachedResponse.status).to.eq(404) + + expect(cachedResponse.headers.get("authorization")).to.be.null + expect(cachedResponse.headers.get("content-length")).to.be.null + expect(cachedResponse.headers.get("content-type")).to.eq("text/plain; charset=utf-8") + expect(cachedResponse.headers.get("content-encoding")).to.eq("gzip") + }) + + it("deletes a response", async () => { + const [key, resp] = await makeResponse() + const delResult = await responseCache.del(key) + expect(delResult).to.eq(true) + + const meta = await cache.get(key + ":meta") + expect(meta).to.be.null + + const body = await cache.get(key + ":body") + expect(body).to.be.null + }) + +}) \ No newline at end of file diff --git a/v8env/tests/fly.cache.spec.js b/v8env/tests/fly.cache.spec.js index ffa8373..908e5de 100644 --- a/v8env/tests/fly.cache.spec.js +++ b/v8env/tests/fly.cache.spec.js @@ -1,76 +1,195 @@ -// import { expect } from 'chai' -// import cache from '@fly/cache' - -// describe("@fly/cache", () => { -// it('allows fly.cache global access', () => { -// const c = fly.cache -// expect(typeof c.get).to.eq("function") -// }) - -// it("gets a string", async () => { -// const v = `cache-value-woo! ${Math.random()}` - -// const setResult = await cache.set("cache-test-key", v) -// expect(setResult).to.eq(true, "couldn't set test value") -// const result = await cache.getString("cache-test-key") - -// expect(result).to.eq(v) -// }) - -// it("deletes from cache", async () => { -// const v = `cache-value-woo! ${Math.random()}` - -// const setResult = await cache.set("cache-delete-key", v) -// expect(setResult).to.eq(true) - -// const result = await cache.del("cache-delete-key") - -// expect(result).to.eq(true, "del should return true") - -// let newVal = await cache.get("cache-delete-key") -// expect(newVal).to.eq(null, "previously deleted key should be null") -// }) - -// it("accepts empty arrayBuffer", async () => { -// const k = `cache-test${Math.random()}` - -// await cache.set(k, new ArrayBuffer(0)) - -// const result = await cache.get(k) -// expect(result).to.be.a('ArrayBuffer') -// expect(result.byteLength).to.eq(0) -// }) - -// it("handles blank strings", async () => { -// const k = `cache-test${Math.random()}` -// await cache.set(k, '') -// const result = await cache.getString(k) -// expect(result).to.eq('') -// }) - -// it("handles set.onlyIfEmpty", async () => { -// const k = `cache-test${Math.random()}` -// await cache.set(k, 'asdf') - -// const setResult = await cache.set(k, 'jklm', { onlyIfEmpty: true }) -// const v = await cache.getString(k) - -// expect(setResult).to.eq(false) -// expect(v).to.eq("asdf") -// }) - -// it("gets multiple values", async () => { -// const k = `cache-test${Math.random()}` -// const k2 = `cache-test${Math.random()}` - -// await cache.set(k, "multi-1") -// await cache.set(k2, "multi-2") - -// const result = await cache.getMultiString([k, k2]) -// expect(result).to.be.an('array') - -// const [r1, r2] = result; -// expect(r1).to.eq("multi-1") -// expect(r2).to.eq("multi-2") -// }) -// }) \ No newline at end of file +import { testStream } from "./fixtures/test-stream"; + +describe("fly.cache", () => { + describe("set+get", () => { + test("String->ArrayBuffer", async () => { + const [key, value] = kv(); + + const setResult = await fly.cache.set(key, value) + expect(setResult).to.eq(true, "couldn't set test value") + const result = await fly.cache.get(key) + expect(result).to.be.a("ArrayBuffer") + expect(ab2str(result)).to.eq(value) + }) + + test("ArrayBuffer->ArrayBuffer", async () => { + const [key, value] = kv(); + + const setResult = await fly.cache.set(key, value) + expect(setResult).to.eq(true, "couldn't set test value") + const result = await fly.cache.get(key) + expect(result).to.be.a("ArrayBuffer") + expect(ab2str(result)).to.eq(value) + }) + + test("Stream->ArrayBuffer", async () => { + const [key, value] = kv("this-is-a-value-that-will-be-streamed"); + const stream = testStream(value); + + const setResult = await fly.cache.set(key, stream) + expect(setResult).to.eq(true, "couldn't set test value") + const result = await fly.cache.get(key) + expect(result).to.be.a("ArrayBuffer") + expect(ab2str(result)).to.eq(value) + }) + + test("Missing key", async () => { + const [k, _] = kv(); + expect(await fly.cache.get(k)).to.be.null + }) + + test("Empty ArrayBuffer", async () => { + const k = `cache-test${Math.random()}` + + await fly.cache.set(k, new ArrayBuffer(0)) + + const result = await fly.cache.get(k) + expect(result).to.be.a('ArrayBuffer') + expect(result.byteLength).to.eq(0) + }) + + test("Empty string", async () => { + const k = `cache-test${Math.random()}` + await fly.cache.set(k, '') + const result = await fly.cache.getString(k) + expect(result).to.eq('') + }) + }) + + describe("getMulti()", () => { + test("returns results in order", async () => { + const entries = new Map([kv(), kv(), kv()]); + + for (const [k, v] of entries) { + const result = await fly.cache.set(k, v) + expect(result).to.eq(true, `couldn't set key`) + } + + const results = await fly.cache.getMulti(Array.from(entries.keys())); + expect(results).to.be.an.instanceOf(Array) + expect(results.map(ab2str)).to.have.ordered.members(Array.from(entries.values())); + }) + + test("handles missing keys", async () => { + const entries = new Map([kv(), kv(), kv()]); + + for (const [k, v] of entries) { + const result = await fly.cache.set(k, v) + expect(result).to.eq(true, `couldn't set key`) + } + + entries.set("missing", null) + + const results = await fly.cache.getMulti(Array.from(entries.keys())); + expect(results).to.be.an.instanceOf(Array) + expect(results.map(r => r && ab2str(r))).to.have.ordered.members(Array.from(entries.values())); + }) + }) + + describe("getMultiString()", () => { + test("returns results in order", async () => { + const entries = new Map([kv(), kv(), kv()]); + + for (const [k, v] of entries) { + const result = await fly.cache.set(k, v) + expect(result).to.eq(true, `couldn't set key`) + } + + const results = await fly.cache.getMultiString(Array.from(entries.keys())); + expect(results).to.be.an.instanceOf(Array) + expect(results).to.have.ordered.members(Array.from(entries.values())); + }) + + test("handles missing keys", async () => { + const entries = new Map([kv(), kv(), kv()]); + + for (const [k, v] of entries) { + const result = await fly.cache.set(k, v) + expect(result).to.eq(true, `couldn't set key`) + } + + entries.set("missing", null) + + const results = await fly.cache.getMultiString(Array.from(entries.keys())); + expect(results).to.be.an.instanceOf(Array) + expect(results).to.have.ordered.members(Array.from(entries.values())); + }) + }) + + test("getString()", async () => { + const [key, value] = kv(); + + const setResult = await fly.cache.set(key, value) + expect(setResult).to.eq(true, "couldn't set test value") + const result = await fly.cache.getString(key) + expect(result).to.eq(value) + }) + + test("getStream()", async () => { + const [key, value] = kv(); + + const setResult = await fly.cache.set(key, value) + expect(setResult).to.eq(true, "couldn't set test value") + const result = await fly.cache.getStream(key) + expect(result).to.be.an.instanceOf(ReadableStream) + const buffer = await streamToBuffer(result.getReader()) + expect(ab2str(buffer)).to.eq(value) + }) + + test("del()", async () => { + const [key, value] = kv(); + const setResult = await fly.cache.set(key, value) + expect(setResult).to.eq(true) + + expect( + await fly.cache.del(key) + ).to.eq(true, "del should return true") + + let newVal = await fly.cache.get(key) + expect(newVal).to.eq(null, "previously deleted key should be null") + }) + + describe("TTL", () => { + test("set with ttl", async () => { + const [key, value] = kv(); + + const setResult = await fly.cache.set(key, value, { ttl: 1 }) + expect(setResult).to.eq(true) + + while (await fly.cache.getString(key)) { + await new Promise(r => setTimeout(r, 50)) + } + }) + + test("expire", async () => { + const [key, value] = kv(); + + expect( + await fly.cache.set(key, value) + ).to.eq(true) + + expect( + await fly.cache.expire(key, 1) + ).to.eq(true) + + while (await fly.cache.getString(key)) { + await new Promise(r => setTimeout(r, 50)) + } + }) + }) + + test.skip("handles set.onlyIfEmpty", async () => { + const k = `cache-test${Math.random()}` + await fly.cache.set(k, 'asdf') + + const setResult = await fly.cache.set(k, 'jklm', { onlyIfEmpty: true }) + const v = await fly.cache.getString(k) + + expect(setResult).to.eq(false) + expect(v).to.eq("asdf") + }) +}) + +function kv(value = "value") { + return [`k:${Math.random()}`, `v:${Math.random()}:${value}`]; +} diff --git a/v8env/tests/fly.cache.tags.spec.js b/v8env/tests/fly.cache.tags.spec.js index b116775..3b63001 100644 --- a/v8env/tests/fly.cache.tags.spec.js +++ b/v8env/tests/fly.cache.tags.spec.js @@ -1,41 +1,39 @@ +const cache = fly.cache -// import { expect } from 'chai' -// import cache from '@fly/cache' +describe("@fly/cache#tags", () => { + it.skip("purges tags", async () => { + const k = `cache-test${Math.random()}` + const v = `cache-value-woo! ${Math.random()}` -// describe("@fly/cache#tags", () => { -// it("purges tags", async () => { -// const k = `cache-test${Math.random()}` -// const v = `cache-value-woo! ${Math.random()}` + const s = `cache-test${Math.random()}` + await cache.set(k, v, { tags: [s] }) -// const s = `cache-test${Math.random()}` -// await cache.set(k, v, { tags: [s] }) + let r = await cache.getString(k) + expect(r).to.eq(v) -// let r = await cache.getString(k) -// expect(r).to.eq(v) + const purged = await cache.purgeTag(s) + expect(purged).to.includes(k) + r = await cache.getString(k) + expect(r).to.eq(null) + }) -// const purged = await cache.purgeTag(s) -// expect(purged).to.includes(k) -// r = await cache.getString(k) -// expect(r).to.eq(null) -// }) + it.skip("ignores stale tags", async () => { + const k = `cache-test${Math.random()}` + let v = `cache-value-woo! ${Math.random()}` + const s = `cache-test${Math.random()}` -// it("ignores stale tags", async () => { -// const k = `cache-test${Math.random()}` -// let v = `cache-value-woo! ${Math.random()}` -// const s = `cache-test${Math.random()}` + // set it with tags + await cache.set(k, v, { tags: [s] }) -// // set it with tags -// await cache.set(k, v, { tags: [s] }) + // set it without + await cache.set(k, v) -// // set it without -// await cache.set(k, v) + const purged = await cache.purgeTag(s) + expect(purged).to.not.includes(k) -// const purged = await cache.purgeTag(s) -// expect(purged).to.not.includes(k) + let v2 = await cache.getString(k) -// let v2 = await cache.getString(k) - -// expect(v2).to.not.be.null -// expect(v2).to.eq(v, "post-purge value is wrong") -// }) -// }) \ No newline at end of file + expect(v2).to.not.be.null + expect(v2).to.eq(v, "post-purge value is wrong") + }) +}) \ No newline at end of file diff --git a/v8env/tests/form_data.spec.js b/v8env/tests/form_data.spec.js index 1726865..341ac06 100644 --- a/v8env/tests/form_data.spec.js +++ b/v8env/tests/form_data.spec.js @@ -56,7 +56,7 @@ describe('FormData', () => { expect(typeof fd.keys()[Symbol.iterator]).to.equal('function') let keys = [] - for(let key of fd.keys()) { + for (let key of fd.keys()) { keys.push(key) } expect(keys).to.eql(['param1', 'param2']) @@ -73,7 +73,7 @@ describe('FormData', () => { expect(typeof fd.values()[Symbol.iterator]).to.equal('function') let values = [] - for(let val of fd.values()) { + for (let val of fd.values()) { values.push(val) } expect(values).to.eql(['value1234', 'anothervalue', 'val431']) @@ -90,12 +90,13 @@ describe('FormData', () => { expect(typeof fd.entries()[Symbol.iterator]).to.equal('function') let entries = [] - for(let entry of fd.entries()) { + for (let entry of fd.entries()) { entries.push(entry) } expect(entries).to.eql([ - ['param1', ['value1234', 'anothervalue']], - ['param2', ['val431']] + ['param1', 'value1234'], + ['param1', 'anothervalue'], + ['param2', 'val431'], ]) }) @@ -117,7 +118,8 @@ describe('FormData', () => { const fd = new FormData() fd.append('param1', 'value1') fd.append('param2', 'value2') - expect(fd.toString()).to.equal('param1=value1¶m2=value2') + fd.append('param2', 'value3') + expect(fd.toString()).to.equal('param1=value1¶m2=value2¶m2=value3') }) it('escapes special symbols', () => { diff --git a/v8env/tests/require.spec.js b/v8env/tests/require.spec.js deleted file mode 100644 index 087350e..0000000 --- a/v8env/tests/require.spec.js +++ /dev/null @@ -1,7 +0,0 @@ -describe("require fly", () => { - it("requires fly.Image", () => { - const { Image } = require("@fly/image") - expect(typeof Image).to.eq("function") - expect(new Image()).to.be.instanceOf(Image) - }) -}) \ No newline at end of file diff --git a/v8env/tests/response.spec.js b/v8env/tests/response.spec.js index 3465932..acc08eb 100644 --- a/v8env/tests/response.spec.js +++ b/v8env/tests/response.spec.js @@ -1,9 +1,9 @@ describe("Response", () => { it("errors on unknown body types", () => { - expect(() => new Response(1)).to.throw(/Bad Response body type/) - expect(() => new Response(true)).to.throw(/Bad Response body type/) - expect(() => new Response({})).to.throw(/Bad Response body type/) - expect(() => new Response(["wat"])).to.throw(/Bad Response body type/) + expect(() => new Response(1)).to.throw(/Bad FlyResponse body type/) + expect(() => new Response(true)).to.throw(/Bad FlyResponse body type/) + expect(() => new Response({})).to.throw(/Bad FlyResponse body type/) + expect(() => new Response(["wat"])).to.throw(/Bad FlyResponse body type/) }) }) describe("Response.redirect", () => { diff --git a/v8env/tests/timers.spec.js b/v8env/tests/timers.spec.js index 81edce6..897ef1c 100644 --- a/v8env/tests/timers.spec.js +++ b/v8env/tests/timers.spec.js @@ -11,6 +11,7 @@ describe("timers", () => { done() }, 20) }) + it("is cleared", function (done) { const t = setTimeout(function () { done(new Error("should not be called")) @@ -21,6 +22,7 @@ describe("timers", () => { }, 50) }) }) + describe("setImmediate", () => { it("calls the callback", function (done) { setImmediate(done) diff --git a/v8env/tests/url.spec.js b/v8env/tests/url.spec.js new file mode 100644 index 0000000..177bb9b --- /dev/null +++ b/v8env/tests/url.spec.js @@ -0,0 +1,28 @@ +describe("URL", () => { + it("ensures pathname begins with a slash", () => { + const url = new URL("https://fly.io/about") + url.pathname = "team" + expect(url.pathname).to.equal("/team") + }) + + it("resolves a relative path from a base", () => { + const url = new URL("fly", new URL("https://github.com/superfly/")) + expect(url.pathname).to.equal("/superfly/fly") + }) + + it("resolves an absolte path from a base", () => { + const url = new URL("/about", new URL("https://fly.io/path/")) + expect(url.pathname).to.equal("/about") + }) + + it("inserts trailing slash if needed", () => { + const url = new URL("fly", new URL("https://github.com/superfly")) + expect(url.pathname).to.equal("/superfly/fly") + }) + + it("doesn't double encode % in pathname", () => { + const url = new URL("https://fly.io") + url.pathname = "encoded%20space" + expect(url.pathname).to.equal("/encoded%20space") + }) +}) \ No newline at end of file diff --git a/v8env/tsconfig.common.json b/v8env/tsconfig.common.json index ea988cf..d604dab 100644 --- a/v8env/tsconfig.common.json +++ b/v8env/tsconfig.common.json @@ -14,7 +14,7 @@ "@fly/*": [ "./src" ] - }, + } // not sure we need these yet... // "esModuleInterop": true, // "allowSyntheticDefaultImports": true, diff --git a/v8env/tsconfig.json b/v8env/tsconfig.json index ad88d75..031c7d3 100644 --- a/v8env/tsconfig.json +++ b/v8env/tsconfig.json @@ -1,24 +1,23 @@ { - "extends": "./tsconfig.common.json", "include": [ "src/**/*" ], "compilerOptions": { - "composite": true, + "target": "es2017", + "module": "esnext", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, "rootDir": "./src", "outDir": "./lib", - // "lib": [ - // "es2017", - // "dom" - // ], - // ease the transition to TypeScript, remove after 2018-09-01 plzthx "strict": false, "noImplicitAny": false, "noFallthroughCasesInSwitch": true, "noLib": true, // "noUnusedLocals": true, // "skipLibCheck": true, - "types": [] + "types": [], + "resolveJsonModule": true }, "typedocOptions": { "out": "./docs/api/", diff --git a/v8env/yarn.lock b/v8env/yarn.lock index 8d53ad1..841a215 100644 --- a/v8env/yarn.lock +++ b/v8env/yarn.lock @@ -18,6 +18,11 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@chaitin/querystring@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@chaitin/querystring/-/querystring-1.1.0.tgz#e5c29e5bb506fe92781405f7d1773fd01b838085" + integrity sha512-3YXFzaJxX7dnCPaxWnfaw5/A99qVrj92lTLVdJyqvXd0LY4I4t2ql3LKIayj/eNNssX2lKuFzmqBh7pV/VyNBA== + "@stardazed/streams@^1.0.6": version "1.0.7" resolved "https://registry.yarnpkg.com/@stardazed/streams/-/streams-1.0.7.tgz#de0635ef129960f2c95d72a2c79e24a88cabb514" @@ -33,6 +38,11 @@ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.1.tgz#720a756ea8e760a258708b52441bd341f1ef4296" integrity sha512-64Uv+8bTRVZHlbB8eXQgMP9HguxPgnOOIYrQpwHWrtLDrtcG/lILKhUl7bV65NSOIJ9dXGYD7skQFXzhL8tk1A== +"@types/cookiejar@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" + integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw== + "@types/estree@0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" @@ -63,11 +73,6 @@ resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.0.tgz#eaae8364d1b7f752e263bc3fd68dfec98e6136c5" integrity sha1-6q6DZNG391LiY7w/1o3+yY5hNsU= -"@types/query-string@^6.1.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@types/query-string/-/query-string-6.1.0.tgz#5f721f9503bdf517d474c66cf4423da5dd2d5698" - integrity sha512-6QxF7V3SkdyBRJ81GheWL9Nzr7uDrCZH0hkxdorNcXeBOeAPN5AUf1n9dpecaBOzxJAckWP4nIOeY1YxlhuMTQ== - "@types/source-map-support@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@types/source-map-support/-/source-map-support-0.4.1.tgz#ad77158e8c6695a16629ef82b9fb9dfe7c610ac0" @@ -341,6 +346,11 @@ cookie@^0.3.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= +cookiejar@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -1173,13 +1183,10 @@ public-encrypt@^4.0.0: randombytes "^2.0.1" safe-buffer "^5.1.2" -query-string@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.2.0.tgz#468edeb542b7e0538f9f9b1aeb26f034f19c86e1" - integrity sha512-5wupExkIt8RYL4h/FE+WTg3JHk62e6fFPWtAZA9J5IWK1PfTfKkMS93HBUHcFpeYi9KsY5pFbh+ldvEyaz5MyA== - dependencies: - decode-uri-component "^0.2.0" - strict-uri-encode "^2.0.0" +querystring@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= randomatic@^3.0.0: version "3.1.0" @@ -1422,11 +1429,6 @@ stack-utils@^1.0.1: resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" integrity sha1-1PM6tU6OOHeLDKXP07OvsS22hiA= -strict-uri-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" - integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= - string-range@~1.2, string-range@~1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/string-range/-/string-range-1.2.2.tgz#a893ed347e72299bc83befbbf2a692a8d239d5dd" @@ -1483,10 +1485,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.0.1.tgz#43738f29585d3a87575520a4b93ab6026ef11fdb" - integrity sha512-zQIMOmC+372pC/CCVLqnQ0zSBiY7HHodU7mpQdjiZddek4GMj31I3dUJ7gAs9o65X7mnRma6OokOkc6f9jjfBg== +typescript@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" + integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== universalify@^0.1.0: version "0.1.2"